From 15ecf40ff47bfbdedddd3161b7d6d9d1418e64bb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Sun, 27 Oct 2024 20:03:31 +0000 Subject: [PATCH] clang format --- .clang-format | 225 + include/vkvg-svg.h | 27 +- include/vkvg.h | 1074 +- src/cross_os.c | 38 +- src/cross_os.h | 52 +- src/deps/tinycthread.c | 702 +- src/deps/tinycthread.h | 481 +- src/nsvg/nanosvg.h | 5604 ++++---- src/nsvg/vkvg_nsvg.c | 192 +- src/recording/vkvg_record.c | 81 +- src/recording/vkvg_record_internal.c | 804 +- src/recording/vkvg_record_internal.h | 208 +- src/shaders.h | 3685 ++--- src/stb_image.h | 12715 +++++++++--------- src/stb_image_write.h | 2395 ++-- src/stb_truetype.h | 7416 +++++----- src/vectors.h | 233 +- src/vkvg_context.c | 3137 +++-- src/vkvg_context_internal.c | 3758 +++--- src/vkvg_context_internal.h | 475 +- src/vkvg_device.c | 647 +- src/vkvg_device_internal.c | 1053 +- src/vkvg_device_internal.h | 200 +- src/vkvg_experimental.c | 3 - src/vkvg_fonts.c | 1184 +- src/vkvg_fonts.h | 228 +- src/vkvg_internal.h | 64 +- src/vkvg_matrix.c | 282 +- src/vkvg_matrix.h | 3 - src/vkvg_pattern.c | 419 +- src/vkvg_pattern.h | 30 +- src/vkvg_surface.c | 777 +- src/vkvg_surface_internal.c | 344 +- src/vkvg_surface_internal.h | 66 +- template.c | 10 +- tests/arcs.c | 148 +- tests/bezier.c | 353 +- tests/circles.c | 82 +- tests/clip.c | 341 +- tests/colinear.c | 28 +- tests/common/nanosvg.h | 5476 ++++---- tests/common/rnd.c | 2262 ++-- tests/common/test.c | 1333 +- tests/common/test.h | 130 +- tests/common/tinycthread.c | 702 +- tests/common/tinycthread.h | 481 +- tests/common/vkengine.c | 417 +- tests/common/vkengine.h | 57 +- tests/compositing.c | 51 +- tests/context.c | 28 +- tests/curve.c | 329 +- tests/dashes.c | 199 +- tests/fill.c | 32 +- tests/fill_and_stroke.c | 40 +- tests/fill_non_zero.c | 42 +- tests/gradient.c | 277 +- tests/gradient2.c | 295 +- tests/img_surf.c | 262 +- tests/inverse_colinear.c | 382 +- tests/line_caps.c | 96 +- tests/line_join.c | 338 +- tests/lines.c | 154 +- tests/multithreading/multithreaded.c | 91 +- tests/multithreading/multithreaded2.c | 79 +- tests/multithreading/threaded_create_surf.c | 65 +- tests/multithreading/threaded_text.c | 114 +- tests/offscreen.c | 28 +- tests/paint_surf.c | 178 +- tests/path_extents.c | 322 +- tests/pattern_transforms.c | 142 +- tests/perfs/random_rects.c | 32 +- tests/perfs/randoms.c | 156 +- tests/radial_gradient.c | 26 +- tests/recording.c | 77 +- tests/rect_fill.c | 44 +- tests/save_restore.c | 39 +- tests/simple_paint.c | 92 +- tests/stroke.c | 108 +- tests/surface.c | 28 +- tests/svg.c | 77 +- tests/test1.c | 694 +- tests/text.c | 479 +- tests/tmp/getarcstep.c | 263 +- tests/transform.c | 148 +- tests/vkvg-svg/svg-viewer.c | 656 +- 85 files changed, 33203 insertions(+), 33682 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..cf8cd36 --- /dev/null +++ b/.clang-format @@ -0,0 +1,225 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: false +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseTab: Never +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... + diff --git a/include/vkvg-svg.h b/include/vkvg-svg.h index 61b916c..4df57ce 100644 --- a/include/vkvg-svg.h +++ b/include/vkvg-svg.h @@ -27,9 +27,9 @@ extern "C" { #endif #ifdef VKVG_SVG -typedef struct _vkvg_svg_t* VkvgSvg; +typedef struct _vkvg_svg_t *VkvgSvg; #else -typedef struct NSVGimage* VkvgSvg; +typedef struct NSVGimage *VkvgSvg; #endif /** * @brief load svg file into @ref surface @@ -41,8 +41,8 @@ typedef struct NSVGimage* VkvgSvg; * @param height force the rendering height, if 0 autosize from svg. * @return The new vkvg surface with the loaded SVG drawing as content, or null if an error occured. */ -vkvg_public -VkvgSurface vkvg_surface_create_from_svg(VkvgDevice dev, uint32_t width, uint32_t height, const char* svgFilePath); +vkvg_public VkvgSurface vkvg_surface_create_from_svg(VkvgDevice dev, uint32_t width, uint32_t height, + const char *svgFilePath); /** * @brief create surface from svg fragment * @@ -53,8 +53,8 @@ VkvgSurface vkvg_surface_create_from_svg(VkvgDevice dev, uint32_t width, uint32_ * @param svgFragment The SVG fragment to parse. * @return The new vkvg surface with the parsed SVG fragment as content, or null if an error occured. */ -vkvg_public -VkvgSurface vkvg_surface_create_from_svg_fragment(VkvgDevice dev, uint32_t width, uint32_t height, char* svgFragment); +vkvg_public VkvgSurface vkvg_surface_create_from_svg_fragment(VkvgDevice dev, uint32_t width, uint32_t height, + char *svgFragment); /** * @brief get svg dimensions. * @@ -63,8 +63,7 @@ VkvgSurface vkvg_surface_create_from_svg_fragment(VkvgDevice dev, uint32_t width * @param width pointer to a valid integer to receive the svg width. * @param height pointer to a valid integer to receive the svg height. */ -vkvg_public -void vkvg_svg_get_dimensions (VkvgSvg svg, uint32_t* width, uint32_t* height); +vkvg_public void vkvg_svg_get_dimensions(VkvgSvg svg, uint32_t *width, uint32_t *height); /** * @brief Load svg file in memory. @@ -73,16 +72,14 @@ void vkvg_svg_get_dimensions (VkvgSvg svg, uint32_t* width, uint32_t* height); * @param svgFilePath a valid file path to the svg to load. * @return a VkvgSvg pointer. */ -vkvg_public -VkvgSvg vkvg_svg_load (const char* svgFilePath); +vkvg_public VkvgSvg vkvg_svg_load(const char *svgFilePath); /** * @brief Load svg from an svg source fragment. * @param svgFragment A valid svg code fragment. * @return a VkvgSvg pointer. */ -vkvg_public -VkvgSvg vkvg_svg_load_fragment (char* svgFragment); +vkvg_public VkvgSvg vkvg_svg_load_fragment(char *svgFragment); /** * @brief render svg on a context. @@ -90,15 +87,13 @@ VkvgSvg vkvg_svg_load_fragment (char* svgFragment); * @param ctx a valid vkvg context. * @param id an optional id to limit rendering to specific `` elemnt. */ -vkvg_public -void vkvg_svg_render (VkvgSvg svg, VkvgContext ctx, const char* id); +vkvg_public void vkvg_svg_render(VkvgSvg svg, VkvgContext ctx, const char *id); /** * @brief release VkvgSvg pointer resources. * @param svg a valid VkvgSvg handle to free. */ -vkvg_public -void vkvg_svg_destroy (VkvgSvg svg); +vkvg_public void vkvg_svg_destroy(VkvgSvg svg); #ifdef __cplusplus } diff --git a/include/vkvg.h b/include/vkvg.h index 2ac2c31..132aaba 100644 --- a/include/vkvg.h +++ b/include/vkvg.h @@ -28,11 +28,13 @@ extern "C" { /** @mainpage Documentation * - * VKVG is an open source 2d vector drawing library written in @b c and using [vulkan](https://www.khronos.org/vulkan/) for hardware acceleration. + * VKVG is an open source 2d vector drawing library written in @b c and using [vulkan](https://www.khronos.org/vulkan/) + * for hardware acceleration. * * @image html screenshot3.png * - * Its api is modeled on the [cairo graphic library](https://www.cairographics.org/) with the following software components: + * Its api is modeled on the [cairo graphic library](https://www.cairographics.org/) with the following software + * components: * * - @ref surface * - @ref context @@ -67,47 +69,46 @@ extern "C" { #include #ifndef vkvg_public - #ifdef VKVG_SHARED_BUILD - #if (defined(_WIN32) || defined(_WIN64)) - #define vkvg_public __declspec(dllexport) - #else - #define vkvg_public __attribute__((visibility("default"))) - #endif - #elif (defined(VKVG_SHARED_LINKING) && (defined(_WIN32) || defined(_WIN64))) - #define vkvg_public __declspec(dllimport) - #else - #define vkvg_public - #endif +#ifdef VKVG_SHARED_BUILD +#if (defined(_WIN32) || defined(_WIN64)) +#define vkvg_public __declspec(dllexport) +#else +#define vkvg_public __attribute__((visibility("default"))) +#endif +#elif (defined(VKVG_SHARED_LINKING) && (defined(_WIN32) || defined(_WIN64))) +#define vkvg_public __declspec(dllimport) +#else +#define vkvg_public +#endif #endif +#define VKVG_LOG_ERR 0x00000001 +#define VKVG_LOG_DEBUG 0x00000002 -#define VKVG_LOG_ERR 0x00000001 -#define VKVG_LOG_DEBUG 0x00000002 - -#define VKVG_LOG_INFO_PTS 0x00000004 -#define VKVG_LOG_INFO_PATH 0x00000008 -#define VKVG_LOG_INFO_CMD 0x00000010 -#define VKVG_LOG_INFO_VBO 0x00000020 -#define VKVG_LOG_INFO_IBO 0x00000040 -#define VKVG_LOG_INFO_VAO (VKVG_LOG_INFO_VBO|VKVG_LOG_INFO_IBO) -#define VKVG_LOG_THREAD 0x00000080 -#define VKVG_LOG_DBG_ARRAYS 0x00001000 -#define VKVG_LOG_STROKE 0x00010000 -#define VKVG_LOG_FULL 0xffffffff +#define VKVG_LOG_INFO_PTS 0x00000004 +#define VKVG_LOG_INFO_PATH 0x00000008 +#define VKVG_LOG_INFO_CMD 0x00000010 +#define VKVG_LOG_INFO_VBO 0x00000020 +#define VKVG_LOG_INFO_IBO 0x00000040 +#define VKVG_LOG_INFO_VAO (VKVG_LOG_INFO_VBO | VKVG_LOG_INFO_IBO) +#define VKVG_LOG_THREAD 0x00000080 +#define VKVG_LOG_DBG_ARRAYS 0x00001000 +#define VKVG_LOG_STROKE 0x00010000 +#define VKVG_LOG_FULL 0xffffffff -#define VKVG_LOG_INFO 0x00008000//(VKVG_LOG_INFO_PTS|VKVG_LOG_INFO_PATH|VKVG_LOG_INFO_CMD|VKVG_LOG_INFO_VAO) +#define VKVG_LOG_INFO 0x00008000 //(VKVG_LOG_INFO_PTS|VKVG_LOG_INFO_PATH|VKVG_LOG_INFO_CMD|VKVG_LOG_INFO_VAO) #ifdef DEBUG - extern uint32_t vkvg_log_level; - #ifdef VKVG_WIRED_DEBUG - typedef enum { - vkvg_wired_debug_mode_normal = 0x01, - vkvg_wired_debug_mode_points = 0x02, - vkvg_wired_debug_mode_lines = 0x04, - vkvg_wired_debug_mode_both = vkvg_wired_debug_mode_points|vkvg_wired_debug_mode_lines, - vkvg_wired_debug_mode_all = 0xFFFFFFFF - }vkvg_wired_debug_mode; - extern vkvg_wired_debug_mode vkvg_wired_debug; - #endif +extern uint32_t vkvg_log_level; +#ifdef VKVG_WIRED_DEBUG +typedef enum { + vkvg_wired_debug_mode_normal = 0x01, + vkvg_wired_debug_mode_points = 0x02, + vkvg_wired_debug_mode_lines = 0x04, + vkvg_wired_debug_mode_both = vkvg_wired_debug_mode_points | vkvg_wired_debug_mode_lines, + vkvg_wired_debug_mode_all = 0xFFFFFFFF +} vkvg_wired_debug_mode; +extern vkvg_wired_debug_mode vkvg_wired_debug; +#endif #endif /** @@ -120,40 +121,32 @@ extern "C" { * As soon as a status is not success, further operations will be canceled. */ typedef enum { - VKVG_STATUS_SUCCESS = 0, /*!< no error occurred.*/ - VKVG_STATUS_NO_MEMORY, /*!< out of memory*/ - VKVG_STATUS_INVALID_RESTORE, /*!< call to #vkvg_restore without matching call to #vkvg_save*/ - VKVG_STATUS_NO_CURRENT_POINT, /*!< path command expecting a current point to be defined failed*/ - VKVG_STATUS_INVALID_MATRIX, /*!< invalid matrix (not invertible)*/ - VKVG_STATUS_INVALID_STATUS, /*!< */ - VKVG_STATUS_INVALID_INDEX, /*!< */ - VKVG_STATUS_NULL_POINTER, /*!< NULL pointer*/ - VKVG_STATUS_WRITE_ERROR, /*!< */ - VKVG_STATUS_PATTERN_TYPE_MISMATCH, /*!< */ - VKVG_STATUS_PATTERN_INVALID_GRADIENT,/*!< occurs when stops count is zero */ - VKVG_STATUS_INVALID_FORMAT, /*!< */ - VKVG_STATUS_FILE_NOT_FOUND, /*!< */ - VKVG_STATUS_INVALID_DASH, /*!< invalid value for a dash setting */ - VKVG_STATUS_INVALID_RECT, /*!< rectangle with height or width equal to 0. */ - VKVG_STATUS_TIMEOUT, /*!< waiting for a vulkan operation to finish resulted in a fence timeout (5 seconds)*/ - VKVG_STATUS_DEVICE_ERROR, /*!< vkvg device initialization error */ - VKVG_STATUS_INVALID_IMAGE, /*!< */ - VKVG_STATUS_INVALID_SURFACE, /*!< */ - VKVG_STATUS_INVALID_FONT, /*!< Unresolved font name*/ - VKVG_STATUS_ENUM_MAX = 0x7FFFFFFF -}vkvg_status_t; + VKVG_STATUS_SUCCESS = 0, /*!< no error occurred.*/ + VKVG_STATUS_NO_MEMORY, /*!< out of memory*/ + VKVG_STATUS_INVALID_RESTORE, /*!< call to #vkvg_restore without matching call to #vkvg_save*/ + VKVG_STATUS_NO_CURRENT_POINT, /*!< path command expecting a current point to be defined failed*/ + VKVG_STATUS_INVALID_MATRIX, /*!< invalid matrix (not invertible)*/ + VKVG_STATUS_INVALID_STATUS, /*!< */ + VKVG_STATUS_INVALID_INDEX, /*!< */ + VKVG_STATUS_NULL_POINTER, /*!< NULL pointer*/ + VKVG_STATUS_WRITE_ERROR, /*!< */ + VKVG_STATUS_PATTERN_TYPE_MISMATCH, /*!< */ + VKVG_STATUS_PATTERN_INVALID_GRADIENT, /*!< occurs when stops count is zero */ + VKVG_STATUS_INVALID_FORMAT, /*!< */ + VKVG_STATUS_FILE_NOT_FOUND, /*!< */ + VKVG_STATUS_INVALID_DASH, /*!< invalid value for a dash setting */ + VKVG_STATUS_INVALID_RECT, /*!< rectangle with height or width equal to 0. */ + VKVG_STATUS_TIMEOUT, /*!< waiting for a vulkan operation to finish resulted in a fence timeout (5 seconds)*/ + VKVG_STATUS_DEVICE_ERROR, /*!< vkvg device initialization error */ + VKVG_STATUS_INVALID_IMAGE, /*!< */ + VKVG_STATUS_INVALID_SURFACE, /*!< */ + VKVG_STATUS_INVALID_FONT, /*!< Unresolved font name*/ + VKVG_STATUS_ENUM_MAX = 0x7FFFFFFF +} vkvg_status_t; -typedef enum { - VKVG_HORIZONTAL = 0, - VKVG_VERTICAL = 1 -}vkvg_direction_t; +typedef enum { VKVG_HORIZONTAL = 0, VKVG_VERTICAL = 1 } vkvg_direction_t; -typedef enum { - VKVG_FORMAT_ARGB32, - VKVG_FORMAT_RGB24, - VKVG_FORMAT_A8, - VKVG_FORMAT_A1 -} vkvg_format_t; +typedef enum { VKVG_FORMAT_ARGB32, VKVG_FORMAT_RGB24, VKVG_FORMAT_A8, VKVG_FORMAT_A1 } vkvg_format_t; /** * @brief pattern border policy * @@ -161,20 +154,19 @@ typedef enum { * the extend defines how the pattern will be rendered outside its original bounds. */ typedef enum { - VKVG_EXTEND_NONE, /*!< nothing will be outputed outside the pattern original bounds */ - VKVG_EXTEND_REPEAT, /*!< pattern will be repeated to fill all the target bounds */ - VKVG_EXTEND_REFLECT, /*!< pattern will be repeated but mirrored on each repeat */ - VKVG_EXTEND_PAD /*!< the last pixels making the borders of the pattern will be extended to the whole target */ + VKVG_EXTEND_NONE, /*!< nothing will be outputed outside the pattern original bounds */ + VKVG_EXTEND_REPEAT, /*!< pattern will be repeated to fill all the target bounds */ + VKVG_EXTEND_REFLECT, /*!< pattern will be repeated but mirrored on each repeat */ + VKVG_EXTEND_PAD /*!< the last pixels making the borders of the pattern will be extended to the whole target */ } vkvg_extend_t; - typedef enum { - VKVG_FILTER_FAST, - VKVG_FILTER_GOOD, - VKVG_FILTER_BEST, - VKVG_FILTER_NEAREST, - VKVG_FILTER_BILINEAR, - VKVG_FILTER_GAUSSIAN, + VKVG_FILTER_FAST, + VKVG_FILTER_GOOD, + VKVG_FILTER_BEST, + VKVG_FILTER_NEAREST, + VKVG_FILTER_BILINEAR, + VKVG_FILTER_GAUSSIAN, } vkvg_filter_t; /** @@ -183,12 +175,12 @@ typedef enum { * */ typedef enum { - VKVG_PATTERN_TYPE_SOLID, /*!< single color pattern */ - VKVG_PATTERN_TYPE_SURFACE, /*!< vkvg surface pattern */ - VKVG_PATTERN_TYPE_LINEAR, /*!< linear gradient pattern */ - VKVG_PATTERN_TYPE_RADIAL, /*!< radial gradient pattern */ - VKVG_PATTERN_TYPE_MESH, /*!< not implemented */ - VKVG_PATTERN_TYPE_RASTER_SOURCE, /*!< not implemented */ + VKVG_PATTERN_TYPE_SOLID, /*!< single color pattern */ + VKVG_PATTERN_TYPE_SURFACE, /*!< vkvg surface pattern */ + VKVG_PATTERN_TYPE_LINEAR, /*!< linear gradient pattern */ + VKVG_PATTERN_TYPE_RADIAL, /*!< radial gradient pattern */ + VKVG_PATTERN_TYPE_MESH, /*!< not implemented */ + VKVG_PATTERN_TYPE_RASTER_SOURCE, /*!< not implemented */ } vkvg_pattern_type_t; /** @@ -198,9 +190,9 @@ typedef enum { * configuration which may be accessed with #vkvg_set_line_cap and #vkvg_get_line_cap */ typedef enum { - VKVG_LINE_CAP_BUTT, /*!< normal line endings, this is the default. */ - VKVG_LINE_CAP_ROUND, /*!< rounded line caps */ - VKVG_LINE_CAP_SQUARE /*!< extend the caps with squared terminations having border equal to current line width. */ + VKVG_LINE_CAP_BUTT, /*!< normal line endings, this is the default. */ + VKVG_LINE_CAP_ROUND, /*!< rounded line caps */ + VKVG_LINE_CAP_SQUARE /*!< extend the caps with squared terminations having border equal to current line width. */ } vkvg_line_cap_t; /** * @brief lines articulations @@ -209,9 +201,9 @@ typedef enum { * in the context and may be accessed with #vkvg_set_line_join and #vkvg_get_line_join. */ typedef enum { - VKVG_LINE_JOIN_MITER, /*!< normal joins with sharp angles, this is the default. */ - VKVG_LINE_JOIN_ROUND, /*!< joins are rounded on the exterior border of the line. */ - VKVG_LINE_JOIN_BEVEL /*!< beveled line joins. */ + VKVG_LINE_JOIN_MITER, /*!< normal joins with sharp angles, this is the default. */ + VKVG_LINE_JOIN_ROUND, /*!< joins are rounded on the exterior border of the line. */ + VKVG_LINE_JOIN_BEVEL /*!< beveled line joins. */ } vkvg_line_join_t; /** @@ -223,58 +215,63 @@ typedef enum { * All further drawing and clipping operations are affected by this setting. */ typedef enum { - VKVG_FILL_RULE_EVEN_ODD, /*!< even-odd fill rule */ - VKVG_FILL_RULE_NON_ZERO /*!< non zero fill rule */ + VKVG_FILL_RULE_EVEN_ODD, /*!< even-odd fill rule */ + VKVG_FILL_RULE_NON_ZERO /*!< non zero fill rule */ } vkvg_fill_rule_t; typedef struct { - float r; /*!< the red component */ - float g; /*!< the green component */ - float b; /*!< the blue component */ - float a; /*!< the alpha component */ + float r; /*!< the red component */ + float g; /*!< the green component */ + float b; /*!< the blue component */ + float a; /*!< the alpha component */ } vkvg_color_t; /** - * @brief font metrics - * - * structure defining global font metrics for a particular font. It can be retrieve by calling @ref vkvg_font_extents - * on a valid context. - */ + * @brief font metrics + * + * structure defining global font metrics for a particular font. It can be retrieve by calling @ref vkvg_font_extents + * on a valid context. + */ typedef struct { - float ascent; /*!< the distance that the font extends above the baseline. */ - float descent; /*!< the distance that the font extends below the baseline.*/ - float height; /*!< the recommended vertical distance between baselines. */ - float max_x_advance; /*!< the maximum distance in the X direction that the origin is advanced for any glyph in the font.*/ - float max_y_advance; /*!< the maximum distance in the Y direction that the origin is advanced for any glyph in the font. This will be zero for normal fonts used for horizontal writing.*/ + float ascent; /*!< the distance that the font extends above the baseline. */ + float descent; /*!< the distance that the font extends below the baseline.*/ + float height; /*!< the recommended vertical distance between baselines. */ + float max_x_advance; /*!< the maximum distance in the X direction that the origin is advanced for any glyph in the + font.*/ + float max_y_advance; /*!< the maximum distance in the Y direction that the origin is advanced for any glyph in the + font. This will be zero for normal fonts used for horizontal writing.*/ } vkvg_font_extents_t; /** - * @brief text metrics - * - * structure defining metrics for a single or a string of glyphs. To measure text, call @ref vkvg_text_extents - * on a valid context. - */ + * @brief text metrics + * + * structure defining metrics for a single or a string of glyphs. To measure text, call @ref vkvg_text_extents + * on a valid context. + */ typedef struct { - float x_bearing; /*!< the horizontal distance from the origin to the leftmost part of the glyphs as drawn. Positive if the glyphs lie entirely to the right of the origin. */ - float y_bearing; /*!< the vertical distance from the origin to the topmost part of the glyphs as drawn. Positive only if the glyphs lie completely below the origin; will usually be negative.*/ - float width; /*!< width of the glyphs as drawn*/ - float height; /*!< height of the glyphs as drawn*/ - float x_advance; /*!< distance to advance in the X direction after drawing these glyphs*/ - float y_advance; /*!< distance to advance in the Y direction after drawing these glyphs. Will typically be zero except for vertical text layout as found in East-Asian languages.*/ + float x_bearing; /*!< the horizontal distance from the origin to the leftmost part of the glyphs as drawn. Positive + if the glyphs lie entirely to the right of the origin. */ + float y_bearing; /*!< the vertical distance from the origin to the topmost part of the glyphs as drawn. Positive + only if the glyphs lie completely below the origin; will usually be negative.*/ + float width; /*!< width of the glyphs as drawn*/ + float height; /*!< height of the glyphs as drawn*/ + float x_advance; /*!< distance to advance in the X direction after drawing these glyphs*/ + float y_advance; /*!< distance to advance in the Y direction after drawing these glyphs. Will typically be zero + except for vertical text layout as found in East-Asian languages.*/ } vkvg_text_extents_t; /** - * @brief glyphs position in a @ref VkvgText - * - * structure defining glyph position as computed for rendering a text run. - * the codepoint field is for internal use only. - */ + * @brief glyphs position in a @ref VkvgText + * + * structure defining glyph position as computed for rendering a text run. + * the codepoint field is for internal use only. + */ typedef struct _glyph_info_t { - int32_t x_advance; - int32_t y_advance; - int32_t x_offset; - int32_t y_offset; - /* private */ - uint32_t codepoint;//should be named glyphIndex, but for harfbuzz compatibility... + int32_t x_advance; + int32_t y_advance; + int32_t x_offset; + int32_t y_offset; + /* private */ + uint32_t codepoint; // should be named glyphIndex, but for harfbuzz compatibility... } vkvg_glyph_info_t; /** @@ -289,7 +286,7 @@ typedef struct _glyph_info_t { * Drawing text with @ref vkvg_show_text() implicitly create such intermediate structure * that is destroyed imediatly after the function call. */ -typedef struct _vkvg_text_run_t* VkvgText; +typedef struct _vkvg_text_run_t *VkvgText; /** * @brief The Vkvg drawing Context. @@ -297,7 +294,7 @@ typedef struct _vkvg_text_run_t* VkvgText; * * A #VkvgContext is the central object for drawing operations. */ -typedef struct _vkvg_context_t* VkvgContext; +typedef struct _vkvg_context_t *VkvgContext; /** * @brief Opaque pointer on a Vkvg Surface structure. * @ingroup surface @@ -309,14 +306,14 @@ typedef struct _vkvg_context_t* VkvgContext; * with the surface as the target, using #vkvg_create(). * */ -typedef struct _vkvg_surface_t* VkvgSurface; +typedef struct _vkvg_surface_t *VkvgSurface; /** * @brief Opaque pointer on a Vkvg device structure. * @ingroup device * * A #VkvgDevice is required for creating new surfaces. */ -typedef struct _vkvg_device_t* VkvgDevice; +typedef struct _vkvg_device_t *VkvgDevice; /** * @brief Opaque pointer on a Vkvg pattern structure. * @ingroup pattern @@ -324,28 +321,27 @@ typedef struct _vkvg_device_t* VkvgDevice; * Patterns are images to be drawn on surface with several * configurable parameters such as the wrap mode, the filtering, etc... */ -typedef struct _vkvg_pattern_t* VkvgPattern; +typedef struct _vkvg_pattern_t *VkvgPattern; #if VKVG_DBG_STATS /** * @brief vkvg memory and vulkan statistiques. - * + * * @ingroup device */ typedef struct { - uint32_t sizePoints; /**< maximum point array size */ - uint32_t sizePathes; /**< maximum path array size */ - uint32_t sizeVertices; /**< maximum size of host vertice cache */ - uint32_t sizeIndices; /**< maximum size of host index cache */ - uint32_t sizeVBO; /**< maximum size of vulkan vertex buffer */ - uint32_t sizeIBO; /**< maximum size of vulkan index buffer */ + uint32_t sizePoints; /**< maximum point array size */ + uint32_t sizePathes; /**< maximum path array size */ + uint32_t sizeVertices; /**< maximum size of host vertice cache */ + uint32_t sizeIndices; /**< maximum size of host index cache */ + uint32_t sizeVBO; /**< maximum size of vulkan vertex buffer */ + uint32_t sizeIBO; /**< maximum size of vulkan index buffer */ } vkvg_debug_stats_t; -vkvg_debug_stats_t vkvg_device_get_stats (VkvgDevice dev); -vkvg_debug_stats_t vkvg_device_reset_stats (VkvgDevice dev); +vkvg_debug_stats_t vkvg_device_get_stats(VkvgDevice dev); +vkvg_debug_stats_t vkvg_device_reset_stats(VkvgDevice dev); #endif - /** * @defgroup matrix Matrices * @brief Generic matrix operations @@ -353,7 +349,8 @@ vkvg_debug_stats_t vkvg_device_reset_stats (VkvgDevice dev); * This is the reference documentation for handling matrices to use as transformation in drawing operations. * Matrix computations in vkvg are taken from the cairo library. * @{ */ -#define VKVG_IDENTITY_MATRIX (vkvg_matrix_t){1,0,0,1,0,0}/*!< The identity matrix*/ +#define VKVG_IDENTITY_MATRIX \ + (vkvg_matrix_t) { 1, 0, 0, 1, 0, 0 } /*!< The identity matrix*/ /** * @brief vkvg matrix structure * @@ -372,9 +369,12 @@ vkvg_debug_stats_t vkvg_device_reset_stats (VkvgDevice dev); * @y0: Y translation component of the affine transformation */ typedef struct { - float xx; float yx; - float xy; float yy; - float x0; float y0; + float xx; + float yx; + float xy; + float yy; + float x0; + float y0; } vkvg_matrix_t; /** * @brief Set matrix to identity @@ -382,8 +382,7 @@ typedef struct { * Initialize members of the supplied #vkvg_matrix_t to make an identity matrix of it. * @param matrix a valid #vkvg_matrix_t pointer. */ -vkvg_public -void vkvg_matrix_init_identity (vkvg_matrix_t *matrix); +vkvg_public void vkvg_matrix_init_identity(vkvg_matrix_t *matrix); /** * @brief Matrix initialization. * @@ -397,11 +396,7 @@ void vkvg_matrix_init_identity (vkvg_matrix_t *matrix); * @param x0 X translation component of the affine transformation * @param y0 Y translation component of the affine transformation */ -vkvg_public -void vkvg_matrix_init (vkvg_matrix_t *matrix, - float xx, float yx, - float xy, float yy, - float x0, float y0); +vkvg_public void vkvg_matrix_init(vkvg_matrix_t *matrix, float xx, float yx, float xy, float yy, float x0, float y0); /** * @brief Rotation matrix initialization * @@ -410,8 +405,7 @@ void vkvg_matrix_init (vkvg_matrix_t *matrix, * @param tx translation in the X direction * @param ty translation in the Y direction */ -vkvg_public -void vkvg_matrix_init_translate (vkvg_matrix_t *matrix, float tx, float ty); +vkvg_public void vkvg_matrix_init_translate(vkvg_matrix_t *matrix, float tx, float ty); /** * @brief scaling matrix initialization * @@ -420,8 +414,7 @@ void vkvg_matrix_init_translate (vkvg_matrix_t *matrix, float tx, float ty); * @param sx scale in the x direction * @param sy Scale in the y direction */ -vkvg_public -void vkvg_matrix_init_scale (vkvg_matrix_t *matrix, float sx, float sy); +vkvg_public void vkvg_matrix_init_scale(vkvg_matrix_t *matrix, float sx, float sy); /** * @brief rotation matrix initialization * @@ -433,8 +426,7 @@ void vkvg_matrix_init_scale (vkvg_matrix_t *matrix, float sx, float sy); * axis orientation of vkvg, positive angles rotate in a clockwise * direction. */ -vkvg_public -void vkvg_matrix_init_rotate (vkvg_matrix_t *matrix, float radians); +vkvg_public void vkvg_matrix_init_rotate(vkvg_matrix_t *matrix, float radians); /** * @brief apply translation on matrix * @@ -445,8 +437,7 @@ void vkvg_matrix_init_rotate (vkvg_matrix_t *matrix, float radians); * @param tx translation in the x direction * @param ty translation in the y direction */ -vkvg_public -void vkvg_matrix_translate (vkvg_matrix_t *matrix, float tx, float ty); +vkvg_public void vkvg_matrix_translate(vkvg_matrix_t *matrix, float tx, float ty); /** * @brief apply scale on matrix * @@ -457,8 +448,7 @@ void vkvg_matrix_translate (vkvg_matrix_t *matrix, float tx, float ty); * @param sx scale in the x direction * @param sy scale in the y direction */ -vkvg_public -void vkvg_matrix_scale (vkvg_matrix_t *matrix, float sx, float sy); +vkvg_public void vkvg_matrix_scale(vkvg_matrix_t *matrix, float sx, float sy); /** * @brief apply rotation on matrix * @@ -470,8 +460,7 @@ void vkvg_matrix_scale (vkvg_matrix_t *matrix, float sx, float sy); * rotate in the direction from the positive X axis toward the positive Y axis. * With the default axis orientation of cairo, positive angles rotate in a clockwise direction. */ -vkvg_public -void vkvg_matrix_rotate (vkvg_matrix_t *matrix, float radians); +vkvg_public void vkvg_matrix_rotate(vkvg_matrix_t *matrix, float radians); /** * @brief matrices multiplication * @@ -480,25 +469,23 @@ void vkvg_matrix_rotate (vkvg_matrix_t *matrix, float radians); * @param a first operand of the multiplication * @param b second operand of the multiplication */ -vkvg_public -void vkvg_matrix_multiply (vkvg_matrix_t *result, const vkvg_matrix_t *a, const vkvg_matrix_t *b); +vkvg_public void vkvg_matrix_multiply(vkvg_matrix_t *result, const vkvg_matrix_t *a, const vkvg_matrix_t *b); /** * @brief transform distances * - * Transforms the distance vector (dx ,dy ) by matrix . This is similar to #cairo_matrix_transform_point() except that the translation - * components of the transformation are ignored. The calculation of the returned vector is as follows: + * Transforms the distance vector (dx ,dy ) by matrix . This is similar to #cairo_matrix_transform_point() except that + * the translation components of the transformation are ignored. The calculation of the returned vector is as follows: * @code * dx2 = dx1 * a + dy1 * c; * dy2 = dx1 * b + dy1 * d; * @endcode - * Affine transformations are position invariant, so the same vector always transforms to the same vector. If (x1 ,y1 ) transforms to (x2 ,y2 ) - * then (x1 +dx1 ,y1 +dy1 ) will transform to (x1 +dx2 ,y1 +dy2 ) for all values of x1 and x2 . + * Affine transformations are position invariant, so the same vector always transforms to the same vector. If (x1 ,y1 ) + * transforms to (x2 ,y2 ) then (x1 +dx1 ,y1 +dy1 ) will transform to (x1 +dx2 ,y1 +dy2 ) for all values of x1 and x2 . * @param matrix a valid #vkvg_matrix_t to use to transform distance * @param dx X component of a distance vector. An in/out parameter * @param dy Y component of a distance vector. An in/out parameter */ -vkvg_public -void vkvg_matrix_transform_distance (const vkvg_matrix_t *matrix, float *dx, float *dy); +vkvg_public void vkvg_matrix_transform_distance(const vkvg_matrix_t *matrix, float *dx, float *dy); /** * @brief transform point * @@ -507,8 +494,7 @@ void vkvg_matrix_transform_distance (const vkvg_matrix_t *matrix, float *dx, flo * @param x X position. An in/out parameter * @param y Y position. An in/out parameter */ -vkvg_public -void vkvg_matrix_transform_point (const vkvg_matrix_t *matrix, float *x, float *y); +vkvg_public void vkvg_matrix_transform_point(const vkvg_matrix_t *matrix, float *x, float *y); /** * @brief invert matrix * @@ -518,10 +504,8 @@ void vkvg_matrix_transform_point (const vkvg_matrix_t *matrix, float *x, float * * @return If matrix has an inverse, modifies matrix to be the inverse matrix and returns VKVG_STATUS_SUCCESS. * Otherwise, returns VKVG_STATUS_INVALID_MATRIX. */ -vkvg_public -vkvg_status_t vkvg_matrix_invert (vkvg_matrix_t *matrix); -vkvg_public -void vkvg_matrix_get_scale (const vkvg_matrix_t *matrix, float *sx, float *sy); +vkvg_public vkvg_status_t vkvg_matrix_invert(vkvg_matrix_t *matrix); +vkvg_public void vkvg_matrix_get_scale(const vkvg_matrix_t *matrix, float *sx, float *sy); /** @}*/ /*! @@ -564,38 +548,38 @@ void vkvg_matrix_get_scale (const vkvg_matrix_t *matrix, float *sx, float *sy); */ typedef struct { VkSampleCountFlags samples; - bool deferredResolve; - VkInstance inst; - VkPhysicalDevice phy; - VkDevice vkdev; - uint32_t qFamIdx; - uint32_t qIndex; -}vkvg_device_create_info_t; + bool deferredResolve; + VkInstance inst; + VkPhysicalDevice phy; + VkDevice vkdev; + uint32_t qFamIdx; + uint32_t qIndex; +} vkvg_device_create_info_t; /** * @brief Set device ready for multithreading. * * If thread aware mode is set to true, * - * This method should be called only once on device creation. If this method is called while some surfaces or patterns are - * in use, this could have unexpected results. + * This method should be called only once on device creation. If this method is called while some surfaces or patterns + * are in use, this could have unexpected results. * * * @param dev * @param thread_awayre */ +vkvg_public void vkvg_device_set_thread_aware(VkvgDevice dev, uint32_t thread_awayre); vkvg_public -void vkvg_device_set_thread_aware (VkvgDevice dev, uint32_t thread_awayre); -vkvg_public -/** - * @brief Set maximum cached context count. - * - * The context cache stored destroyed contexts per thread to speed-up new context creation. - * To disable context cache, call this method with maxCount=0. - * - * @param dev A valid vkvg device pointer. - * @param maxCount The maximum count of saved contexts for fast context instanciation. - */ -void vkvg_device_set_context_cache_size (VkvgDevice dev, uint32_t maxCount); + /** + * @brief Set maximum cached context count. + * + * The context cache stored destroyed contexts per thread to speed-up new context creation. + * To disable context cache, call this method with maxCount=0. + * + * @param dev A valid vkvg device pointer. + * @param maxCount The maximum count of saved contexts for fast context instanciation. + */ + void + vkvg_device_set_context_cache_size(VkvgDevice dev, uint32_t maxCount); /** * @brief Create a new vkvg device. * @@ -608,11 +592,10 @@ void vkvg_device_set_context_cache_size (VkvgDevice dev, uint32_t maxCount); * - VKVG_STATUS_NULL_POINTER: vulkan function pointer fetching failed. * * @param samples The sample count that will be setup for the surfaces created by this device. - * @param deferredResolve If true, the final simple sampled image of the surface will only be resolved on demand with a call - * to #vkvg_surface_resolve() or + * @param deferredResolve If true, the final simple sampled image of the surface will only be resolved on demand with a + * call to #vkvg_surface_resolve() or */ -vkvg_public -VkvgDevice vkvg_device_create (vkvg_device_create_info_t* info); +vkvg_public VkvgDevice vkvg_device_create(vkvg_device_create_info_t *info); /** * @brief Create a new vkvg device from an existing vulkan logical device. * @@ -658,8 +641,7 @@ VkvgDevice vkvg_device_create (vkvg_device_create_info_t* info); * Vkvg Devices has to stay active as long as surfaces created by it are used. * @param dev The vkvg device to destroy. */ -vkvg_public -void vkvg_device_destroy (VkvgDevice dev); +vkvg_public void vkvg_device_destroy(VkvgDevice dev); /** * @brief Get the current status of the device. * @@ -667,8 +649,7 @@ void vkvg_device_destroy (VkvgDevice dev); * @param dev a valid vkvg device pointer. * @return current state. */ -vkvg_public -vkvg_status_t vkvg_device_status (VkvgDevice dev); +vkvg_public vkvg_status_t vkvg_device_status(VkvgDevice dev); /** * @brief Increment the reference count on this device. * @@ -676,8 +657,7 @@ vkvg_status_t vkvg_device_status (VkvgDevice dev); * @param The vkvg device pointer to increment the reference count for. * @return */ -vkvg_public -VkvgDevice vkvg_device_reference (VkvgDevice dev); +vkvg_public VkvgDevice vkvg_device_reference(VkvgDevice dev); /** * @brief Query the reference count of the device. * @@ -685,8 +665,7 @@ VkvgDevice vkvg_device_reference (VkvgDevice dev); * @param dev The vkvg device to get the reference count for. * @return The reference count on this device. */ -vkvg_public -uint32_t vkvg_device_get_reference_count (VkvgDevice dev); +vkvg_public uint32_t vkvg_device_get_reference_count(VkvgDevice dev); /** * @brief Set the screen dot per inch for this device. * @@ -695,8 +674,7 @@ uint32_t vkvg_device_get_reference_count (VkvgDevice dev); * @param hdpy Horizontal dot per inch. * @param vdpy Vertical dot per inch. */ -vkvg_public -void vkvg_device_set_dpy (VkvgDevice dev, int hdpy, int vdpy); +vkvg_public void vkvg_device_set_dpy(VkvgDevice dev, int hdpy, int vdpy); /** * @brief Get the current dpy values. * @@ -706,8 +684,7 @@ void vkvg_device_set_dpy (VkvgDevice dev, int hdpy, int vdpy); * @param hdpy The current horizontal dot per inch. * @param vdpy The current vertical dot per inch. */ -vkvg_public -void vkvg_device_get_dpy (VkvgDevice dev, int* hdpy, int* vdpy); +vkvg_public void vkvg_device_get_dpy(VkvgDevice dev, int *hdpy, int *vdpy); /** * @brief query required instance extensions for vkvg. @@ -716,8 +693,7 @@ void vkvg_device_get_dpy (VkvgDevice dev, int* hdpy, int* vdpy); * by calling this method with pExtension being a NULL pointer. * @param pExtCount a valid pointer to an integer that will be fill with the required extension count. */ -vkvg_public -void vkvg_get_required_instance_extensions (const char** pExtensions, uint32_t* pExtCount); +vkvg_public void vkvg_get_required_instance_extensions(const char **pExtensions, uint32_t *pExtCount); /** * @brief query required device extensions for vkvg. * @param phy the vulkan physical device that will be used to create the @ref VkvgDevice. @@ -725,9 +701,9 @@ void vkvg_get_required_instance_extensions (const char** pExtensions, uint32_t* * by calling this method with pExtension being a NULL pointer. * @param pExtCount a valid pointer to an integer that will be fill with the required extension count. * @return #VKVG_STATUS_SUCCESS or #VKVG_STATUS_DEVICE_ERROR if a fatal error occured. -*/ -vkvg_public -vkvg_status_t vkvg_get_required_device_extensions(VkPhysicalDevice phy, const char** pExtensions, uint32_t* pExtCount); + */ +vkvg_public vkvg_status_t vkvg_get_required_device_extensions(VkPhysicalDevice phy, const char **pExtensions, + uint32_t *pExtCount); /** * @brief get vulkan device creation requirement to fit vkvg needs. * @@ -735,8 +711,7 @@ vkvg_status_t vkvg_get_required_device_extensions(VkPhysicalDevice phy, const ch * @return the required pNext chain for the vulkan device creation. The first structure is guarantied to * be VkPhysicalDeviceVulkan12Features if vulkan version is >= 1.2 */ -vkvg_public -const void* vkvg_get_device_requirements (VkPhysicalDeviceFeatures* pEnabledFeatures); +vkvg_public const void *vkvg_get_device_requirements(VkPhysicalDeviceFeatures *pEnabledFeatures); /** @}*/ /** @addtogroup surface @@ -751,8 +726,7 @@ const void* vkvg_get_device_requirements (VkPhysicalDeviceFeatures* pEnabledFeat * @param height Height in pixel of the surface to create. * @return The new vkvg surface pointer, or null if an error occured. */ -vkvg_public -VkvgSurface vkvg_surface_create (VkvgDevice dev, uint32_t width, uint32_t height); +vkvg_public VkvgSurface vkvg_surface_create(VkvgDevice dev, uint32_t width, uint32_t height); /** * @brief Create a new vkvg surface by loading an image file. * The resulting surface will have the same dimension as the supplied image. @@ -762,8 +736,7 @@ VkvgSurface vkvg_surface_create (VkvgDevice dev, uint32_t width, uint32_t height * @param filePath The path of the image to load for creating the surface. * @return The new vkvg surface with the loaded image as content, or null if an error occured. */ -vkvg_public -VkvgSurface vkvg_surface_create_from_image (VkvgDevice dev, const char* filePath); +vkvg_public VkvgSurface vkvg_surface_create_from_image(VkvgDevice dev, const char *filePath); /** * @brief Create a new vkvg surface using an existing vulkan texture as backend. * This method will always return a valid pointer. @@ -771,8 +744,7 @@ VkvgSurface vkvg_surface_create_from_image (VkvgDevice dev, const char* filePath * @param vkhImg The VkhImage to use as the backend texture for drawing operations. * @return A new surface, or null if an error occured. */ -vkvg_public -VkvgSurface vkvg_surface_create_for_VkhImage (VkvgDevice dev, void* vkhImg); +vkvg_public VkvgSurface vkvg_surface_create_for_VkhImage(VkvgDevice dev, void *vkhImg); /** * @brief Create a new vkvg surface from an in memory rgba bitmap * @param dev The vkvg device used for creating the surface. @@ -781,35 +753,31 @@ VkvgSurface vkvg_surface_create_for_VkhImage (VkvgDevice dev, void* vkhImg); * @param height the height of the provided bitmap. * @return */ -vkvg_public -VkvgSurface vkvg_surface_create_from_bitmap (VkvgDevice dev, unsigned char* img, uint32_t width, uint32_t height); +vkvg_public VkvgSurface vkvg_surface_create_from_bitmap(VkvgDevice dev, unsigned char *img, uint32_t width, + uint32_t height); /** * @brief Increment reference count on the surface by one. * @param The vkvg surface to increment the reference count for. * @return ? */ -vkvg_public -VkvgSurface vkvg_surface_reference (VkvgSurface surf); +vkvg_public VkvgSurface vkvg_surface_reference(VkvgSurface surf); /** * @brief Get the current reference count on this surface. * @param The vkvg surface to get the reference count for. * @return The reference count on the surface. */ -vkvg_public -uint32_t vkvg_surface_get_reference_count (VkvgSurface surf); +vkvg_public uint32_t vkvg_surface_get_reference_count(VkvgSurface surf); /** * @brief Decrement the reference count on the surface by one. Destroy it if count reach 0. * @param The vkvg surface to destroy. */ -vkvg_public -void vkvg_surface_destroy (VkvgSurface surf); +vkvg_public void vkvg_surface_destroy(VkvgSurface surf); /** * @brief Query the current status of the surface. * @param The vkvg surface to query the status for. * @return The current surface status. */ -vkvg_public -vkvg_status_t vkvg_surface_status (VkvgSurface surf); +vkvg_public vkvg_status_t vkvg_surface_status(VkvgSurface surf); /** * @brief Clear surface's content. * @@ -820,68 +788,60 @@ vkvg_status_t vkvg_surface_status (VkvgSurface surf); * function of the context that will try to use the render pass load operations when possible. * @param The surface to clear. */ -vkvg_public -void vkvg_surface_clear (VkvgSurface surf); +vkvg_public void vkvg_surface_clear(VkvgSurface surf); /** * @brief Get the final single sampled vulkan image of this surface. * @param The vkvg surface to get the vulkan texture of. * @return The VkImage object containing the result of the drawing operations on the surface. */ -vkvg_public -VkImage vkvg_surface_get_vk_image (VkvgSurface surf); +vkvg_public VkImage vkvg_surface_get_vk_image(VkvgSurface surf); /** * @brief Get the vulkan format of the vulkan texture used as backend for this surface. * @param The surface to get the format for. * @return The VkFormat. */ -vkvg_public -VkFormat vkvg_surface_get_vk_format (VkvgSurface surf); +vkvg_public VkFormat vkvg_surface_get_vk_format(VkvgSurface surf); /** * @brief Get the actual surface width. * @param The vkvg surface to get the width for. * @return The width in pixel of the surface. */ -vkvg_public -uint32_t vkvg_surface_get_width (VkvgSurface surf); +vkvg_public uint32_t vkvg_surface_get_width(VkvgSurface surf); /** * @brief Get the actual surface height. * @param The vkvg surface to get the height for. * @return The height in pixel of the surface. */ -vkvg_public -uint32_t vkvg_surface_get_height (VkvgSurface surf); +vkvg_public uint32_t vkvg_surface_get_height(VkvgSurface surf); /** * @brief Write surface content to a png file on disk. * @param The surface to save on disk. * @param The png file path. * @return SUCCESS or not. */ -vkvg_public -vkvg_status_t vkvg_surface_write_to_png (VkvgSurface surf, const char* path); +vkvg_public vkvg_status_t vkvg_surface_write_to_png(VkvgSurface surf, const char *path); /** * @brief Save surface to memory * @param The surface to save * @param A valid pointer on cpu memory large enough to contain surface pixels (stride * height) * @return SUCCESS or not. */ -vkvg_public -vkvg_status_t vkvg_surface_write_to_memory (VkvgSurface surf, unsigned char* const bitmap); +vkvg_public vkvg_status_t vkvg_surface_write_to_memory(VkvgSurface surf, unsigned char *const bitmap); /** * @brief Explicitly resolve a multisampled surface. * * Multisampled surfaces are backed internally by 2 vulkan textures, one multisampled for internal use only, and one * single sampled texture onto which the multisampled one is resolved. * If #VkvgDevice is created with `deferredResolve` set to `false`, multisampled image is automatically resolved on each - * draw call. If `deferredResolve` is set to `true`, multisampled image will be resolved only with a call to #vkvg_surface_resolve() or - * by a call to #vkvg_surface_get_vk_image(). + * draw call. If `deferredResolve` is set to `true`, multisampled image will be resolved only with a call to + * #vkvg_surface_resolve() or by a call to #vkvg_surface_get_vk_image(). * * @param surf The multisampled surface to resolve. */ -vkvg_public -void vkvg_surface_resolve (VkvgSurface surf); +vkvg_public void vkvg_surface_resolve(VkvgSurface surf); /** @}*/ -//mimic from cairo, to facilitate usage of vkvg as cairo vulkan backend +// mimic from cairo, to facilitate usage of vkvg as cairo vulkan backend /** * @brief compositing operators @@ -889,40 +849,41 @@ void vkvg_surface_resolve (VkvgSurface surf); * define the operation used to draw */ typedef enum _vkvg_operator { - VKVG_OPERATOR_CLEAR, + VKVG_OPERATOR_CLEAR, - VKVG_OPERATOR_SOURCE, - VKVG_OPERATOR_OVER, -/* VKVG_OPERATOR_IN, - VKVG_OPERATOR_OUT, - VKVG_OPERATOR_ATOP, + VKVG_OPERATOR_SOURCE, + VKVG_OPERATOR_OVER, + /* VKVG_OPERATOR_IN, + VKVG_OPERATOR_OUT, + VKVG_OPERATOR_ATOP, - VKVG_OPERATOR_DEST, - VKVG_OPERATOR_DEST_OVER, - VKVG_OPERATOR_DEST_IN, - VKVG_OPERATOR_DEST_OUT, - VKVG_OPERATOR_DEST_ATOP, + VKVG_OPERATOR_DEST, + VKVG_OPERATOR_DEST_OVER, + VKVG_OPERATOR_DEST_IN, + VKVG_OPERATOR_DEST_OUT, + VKVG_OPERATOR_DEST_ATOP, - VKVG_OPERATOR_XOR, - VKVG_OPERATOR_ADD, - VKVG_OPERATOR_SATURATE, + VKVG_OPERATOR_XOR, + VKVG_OPERATOR_ADD, + VKVG_OPERATOR_SATURATE, - VKVG_OPERATOR_MULTIPLY, - VKVG_OPERATOR_SCREEN, - VKVG_OPERATOR_OVERLAY, - VKVG_OPERATOR_DARKEN, - VKVG_OPERATOR_LIGHTEN, - VKVG_OPERATOR_COLOR_DODGE, - VKVG_OPERATOR_COLOR_BURN, - VKVG_OPERATOR_HARD_LIGHT, - VKVG_OPERATOR_SOFT_LIGHT, - */VKVG_OPERATOR_DIFFERENCE,/* - VKVG_OPERATOR_EXCLUSION, - VKVG_OPERATOR_HSL_HUE, - VKVG_OPERATOR_HSL_SATURATION, - VKVG_OPERATOR_HSL_COLOR, - VKVG_OPERATOR_HSL_LUMINOSITY,*/ - VKVG_OPERATOR_MAX, + VKVG_OPERATOR_MULTIPLY, + VKVG_OPERATOR_SCREEN, + VKVG_OPERATOR_OVERLAY, + VKVG_OPERATOR_DARKEN, + VKVG_OPERATOR_LIGHTEN, + VKVG_OPERATOR_COLOR_DODGE, + VKVG_OPERATOR_COLOR_BURN, + VKVG_OPERATOR_HARD_LIGHT, + VKVG_OPERATOR_SOFT_LIGHT, + */ + VKVG_OPERATOR_DIFFERENCE, /* + VKVG_OPERATOR_EXCLUSION, + VKVG_OPERATOR_HSL_HUE, + VKVG_OPERATOR_HSL_SATURATION, + VKVG_OPERATOR_HSL_COLOR, + VKVG_OPERATOR_HSL_LUMINOSITY,*/ + VKVG_OPERATOR_MAX, } vkvg_operator_t; /** @addtogroup context @@ -931,22 +892,21 @@ typedef enum _vkvg_operator { /** * @brief Create a new vkvg context used for drawing on surfaces. * - * Creates a new #VkvgContext with all graphics state parameters set to default values and with surf as a target surface. - * This method will always return a valid pointer even if memory allocation failed. - * @remark This function references surf, so you can immediately call #vkvg_surface_destroy() on it if you don't need to maintain a separate reference to it. + * Creates a new #VkvgContext with all graphics state parameters set to default values and with surf as a target + * surface. This method will always return a valid pointer even if memory allocation failed. + * @remark This function references surf, so you can immediately call #vkvg_surface_destroy() on it if you don't need to + * maintain a separate reference to it. * @param surf The target surface of the drawing operations. * @return A new #VkvgContext or null if an error occured. */ -vkvg_public -VkvgContext vkvg_create (VkvgSurface surf); +vkvg_public VkvgContext vkvg_create(VkvgSurface surf); /** * @brief Destroy vkvg context. * * Decrement the reference count on the context by one. Destroy it if count reach 0. * @param ctx The vkvg context to destroy. */ -vkvg_public -void vkvg_destroy (VkvgContext ctx); +vkvg_public void vkvg_destroy(VkvgContext ctx); /** * @brief Get context status. * @@ -954,8 +914,7 @@ void vkvg_destroy (VkvgContext ctx); * * @param ctx The vkvg context to query the status for. */ -vkvg_public -vkvg_status_t vkvg_status (VkvgContext ctx); +vkvg_public vkvg_status_t vkvg_status(VkvgContext ctx); /** * vkvg_status_to_string: * @status: a vkvg status @@ -964,22 +923,19 @@ vkvg_status_t vkvg_status (VkvgContext ctx); * * Returns: a string representation of the status **/ -vkvg_public -const char* vkvg_status_to_string (vkvg_status_t status); +vkvg_public const char *vkvg_status_to_string(vkvg_status_t status); /** * @brief Increment by one the reference count on this context. * @param ctx The context to increment the reference count for. * @return */ -vkvg_public -VkvgContext vkvg_reference (VkvgContext ctx); +vkvg_public VkvgContext vkvg_reference(VkvgContext ctx); /** * @brief Get the current reference count of this context. * @param The vkvg context to query. * @return The current reference count for this context. */ -vkvg_public -uint32_t vkvg_get_reference_count (VkvgContext ctx); +vkvg_public uint32_t vkvg_get_reference_count(VkvgContext ctx); /** * @brief Perform all the pending drawing operations on a context. * @@ -989,8 +945,7 @@ uint32_t vkvg_get_reference_count (VkvgContext ctx); * The context is automatically flushed on destruction. * @param ctx The vkvg context to flush. */ -vkvg_public -void vkvg_flush (VkvgContext ctx); +vkvg_public void vkvg_flush(VkvgContext ctx); /** * @brief Start a new empty path. * @@ -999,8 +954,7 @@ void vkvg_flush (VkvgContext ctx); * The current position is reseted to (0,0). * @param ctx The vkvg context pointer. */ -vkvg_public -void vkvg_new_path (VkvgContext ctx); +vkvg_public void vkvg_new_path(VkvgContext ctx); /** * @brief Close the current path. * @@ -1009,8 +963,7 @@ void vkvg_new_path (VkvgContext ctx); * than 2. * @param ctx The vkvg context pointer. */ -vkvg_public -void vkvg_close_path (VkvgContext ctx); +vkvg_public void vkvg_close_path(VkvgContext ctx); /** * @brief Start a new sub path. * @@ -1020,8 +973,7 @@ void vkvg_close_path (VkvgContext ctx); * In many cases, this call is not needed since new sub-paths are frequently started with #vkvg_move_to(). * @param ctx The vkvg context pointer. */ -vkvg_public -void vkvg_new_sub_path (VkvgContext ctx); +vkvg_public void vkvg_new_sub_path(VkvgContext ctx); /** * @brief vkvg_path_extents * @param ctx a valid @ref context @@ -1030,8 +982,7 @@ void vkvg_new_sub_path (VkvgContext ctx); * @param x2 right of the resulting extents * @param y2 bottom of the resulting extents */ -vkvg_public -void vkvg_path_extents (VkvgContext ctx, float *x1, float *y1, float *x2, float *y2); +vkvg_public void vkvg_path_extents(VkvgContext ctx, float *x1, float *y1, float *x2, float *y2); /** * @brief Get the current point. * @@ -1040,8 +991,7 @@ void vkvg_path_extents (VkvgContext ctx, float *x1, float *y1, float *x2, float * @param x A valid float pointer to receive the x coordinate of the current point. * @param y A valid float pointer to receive the y coordinate of the current point. */ -vkvg_public -void vkvg_get_current_point (VkvgContext ctx, float* x, float* y); +vkvg_public void vkvg_get_current_point(VkvgContext ctx, float *x, float *y); /** * @brief Add a line to the current path from the current point to the coordinate given in arguments. * @@ -1052,8 +1002,7 @@ void vkvg_get_current_point (VkvgContext ctx, float* x, float* y); * @param x absolute x coordinate of second point * @param y aboslute y coordinate of second point */ -vkvg_public -void vkvg_line_to (VkvgContext ctx, float x, float y); +vkvg_public void vkvg_line_to(VkvgContext ctx, float x, float y); /** * @brief Add a line to the current path from the current point to the coordinate relative to it. * @@ -1064,8 +1013,7 @@ void vkvg_line_to (VkvgContext ctx, float x, float y); * @param dx delta x * @param dy delta y */ -vkvg_public -void vkvg_rel_line_to (VkvgContext ctx, float dx, float dy); +vkvg_public void vkvg_rel_line_to(VkvgContext ctx, float dx, float dy); /** * @brief Move the context pen to the position given in argument. * @@ -1078,8 +1026,7 @@ void vkvg_rel_line_to (VkvgContext ctx, float dx, float dy); * @param x new x position of the pen * @param y new y position of the pen */ -vkvg_public -void vkvg_move_to (VkvgContext ctx, float x, float y); +vkvg_public void vkvg_move_to(VkvgContext ctx, float x, float y); /** * @brief Move the context pen relative to the current point. * @@ -1091,22 +1038,23 @@ void vkvg_move_to (VkvgContext ctx, float x, float y); * @param x delta in the horizontal direction. * @param y delta in the vertical direction. */ -vkvg_public -void vkvg_rel_move_to (VkvgContext ctx, float x, float y); +vkvg_public void vkvg_rel_move_to(VkvgContext ctx, float x, float y); /** * @brief Adds a circular arc of the given radius to the current path. * - * Adds a circular arc in clockwise order of the given radius to the current path following angles of a trigonometric circle. - * After this call the current point will be the last computed point of the arc. - * The arc is centered at (xc , yc ), begins at angle a1 and proceeds in the direction of increasing angles to end at angle a2. - * If a2 is less than a1, it will be progressively increased by 2*PI until it is greater than a1. + * Adds a circular arc in clockwise order of the given radius to the current path following angles of a trigonometric + * circle. After this call the current point will be the last computed point of the arc. The arc is centered at (xc , yc + * ), begins at angle a1 and proceeds in the direction of increasing angles to end at angle a2. If a2 is less than a1, + * it will be progressively increased by 2*PI until it is greater than a1. * - * If there is a current point, an initial line segment will be added to the path to connect the current point to the beginning of the arc. - * If this initial line is undesired, it can be avoided by calling vkvg_new_sub_path() before calling vkvg_arc(). + * If there is a current point, an initial line segment will be added to the path to connect the current point to the + * beginning of the arc. If this initial line is undesired, it can be avoided by calling vkvg_new_sub_path() before + * calling vkvg_arc(). * * Angles are measured in radians. An angle of 0.0 is in the direction of the positive X axis. * An angle of PI/2 radians (90 degrees) is in the direction of the positive Y axis. Angles increase in the direction - * from the positive X axis toward the positive Y axis. So with the default transformation matrix, angles increase in a clockwise direction. + * from the positive X axis toward the positive Y axis. So with the default transformation matrix, angles increase in a + * clockwise direction. * * @remark To convert from degrees to radians, use degrees * (PI/180). * @param ctx The vkvg context pointer. @@ -1116,14 +1064,13 @@ void vkvg_rel_move_to (VkvgContext ctx, float x, float y); * @param a1 start angle in radians of the arc as if on a trigonometric circle. * @param a2 end angle in radians of the arc to draw. */ -vkvg_public -void vkvg_arc (VkvgContext ctx, float xc, float yc, float radius, float a1, float a2); +vkvg_public void vkvg_arc(VkvgContext ctx, float xc, float yc, float radius, float a1, float a2); /** * @brief Add a circular arc in counter clockwise order to the current path. * - * Adds a circular arc in counter clockwise order of the given radius to the current path following angles of a trigonometric circle. - * After this call the current point will be the last computed point of the arc. - * The arc is centered at `(xc,yc)`, begins at angle `a1` and proceeds in the direction of decreasing angles to end at angle `a2`. + * Adds a circular arc in counter clockwise order of the given radius to the current path following angles of a + * trigonometric circle. After this call the current point will be the last computed point of the arc. The arc is + * centered at `(xc,yc)`, begins at angle `a1` and proceeds in the direction of decreasing angles to end at angle `a2`. * If `a2` is greater than `a1`, it will be progressively decreased by `2*PI` until it is less than `a1`. * * @@ -1135,15 +1082,15 @@ void vkvg_arc (VkvgContext ctx, float xc, float yc, float radius, float a1, floa * @param a1 start angle in radians of the arc as if on a trigonometric circle. * @param a2 end angle in radians of the arc to draw. */ -vkvg_public -void vkvg_arc_negative (VkvgContext ctx, float xc, float yc, float radius, float a1, float a2); +vkvg_public void vkvg_arc_negative(VkvgContext ctx, float xc, float yc, float radius, float a1, float a2); /** * @brief Adds a cubic Bézier spline to the current path. * - * Adds a cubic Bezier spline to the path from the current point to position (x3, y3), using (x1, y1) and (x2, y2) as the control points. - * After this call the current point will be (x3, y3). + * Adds a cubic Bezier spline to the path from the current point to position (x3, y3), using (x1, y1) and (x2, y2) as + * the control points. After this call the current point will be (x3, y3). * - * If there is no current point before the call to vkvg_curve_to() this function will behave as if preceded by a call to vkvg_move_to(ctx, x1, y1). + * If there is no current point before the call to vkvg_curve_to() this function will behave as if preceded by a call to + * vkvg_move_to(ctx, x1, y1). * @param ctx The vkvg context pointer. * @param x1 The X coordinate of the first control point. * @param y1 The Y coordinate of the first control point. @@ -1152,14 +1099,13 @@ void vkvg_arc_negative (VkvgContext ctx, float xc, float yc, float radius, float * @param x3 The X coordinate of the end of the curve. * @param y3 The Y coordinate of the end of the curve. */ -vkvg_public -void vkvg_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3); +vkvg_public void vkvg_curve_to(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3); /** * @brief Adds a cubic Bézier spline to the current path relative to the current point. * - * Adds a cubic Bézier spline to the path from the current point to position (x3, y3) in relative coordinate to the current point, - * using (x1, y1) and (x2, y2) as the control points relative to the current point. - * After this call the current point will be (x3, y3). + * Adds a cubic Bézier spline to the path from the current point to position (x3, y3) in relative coordinate to the + * current point, using (x1, y1) and (x2, y2) as the control points relative to the current point. After this call the + * current point will be (x3, y3). * * If there is no current point before the call to vkvg_rel_curve_to() => error:VKVG_STATUS_NO_CURRENT_POINT. * @param ctx The vkvg context pointer. @@ -1170,20 +1116,19 @@ void vkvg_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, flo * @param x3 The X coordinate of the end of the curve. * @param y3 The Y coordinate of the end of the curve. */ -vkvg_public -void vkvg_rel_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3); +vkvg_public void vkvg_rel_curve_to(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3); /** * @brief Add a quadratic Bezizer curve to the current path * - * If there is no current point before the call to vkvg_quadratic_to() this function will behave as if preceded by a call to vkvg_move_to(ctx, x1, y1). + * If there is no current point before the call to vkvg_quadratic_to() this function will behave as if preceded by a + * call to vkvg_move_to(ctx, x1, y1). * @param ctx The vkvg context pointer. * @param x1 The X coordinate of the control point. * @param y1 The Y coordinate of the control point. * @param x2 The X coordinate of the end point of the curve. * @param y2 The Y coordinate of the end point of the curve. */ -vkvg_public -void vkvg_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2); +vkvg_public void vkvg_quadratic_to(VkvgContext ctx, float x1, float y1, float x2, float y2); /** * @brief Add a quadratic Bezizer curve to the current path relative to the current point * @@ -1193,8 +1138,7 @@ void vkvg_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2) * @param x2 The X coordinate of the end point of the curve relative to the current point. * @param y2 The Y coordinate of the end point of the curve relative to the current point. */ -vkvg_public -void vkvg_rel_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2); +vkvg_public void vkvg_rel_quadratic_to(VkvgContext ctx, float x1, float y1, float x2, float y2); /** * @brief Add an axis aligned rectangle subpath to the current path. * @@ -1206,37 +1150,34 @@ void vkvg_rel_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float * @param h The height in pixel of the rectangle to draw. * @return VKVG_STATUS_SUCCESS or VKVG_STATUS_INVALID_RECT if width or height is equal to 0. */ -vkvg_public -vkvg_status_t vkvg_rectangle(VkvgContext ctx, float x, float y, float w, float h); -/** -* @brief Add an axis aligned rectangle with rounded corners to the current path. -* -* Adds a closed sub-path rectangle of the given size to the current path at position (x, y). -* @param ctx The vkvg context pointer. -* @param x The x coordinate of the top left corner of the rectangle to emit. -* @param y The y coordinate of the top left corner of the rectangle to emit. -* @param w The width in pixel of the rectangle to draw. -* @param h The height in pixel of the rectangle to draw. -* @param radius The radius of the corners. -* @return VKVG_STATUS_SUCCESS or VKVG_STATUS_INVALID_RECT if width or height is equal to 0. -*/ -vkvg_public -vkvg_status_t vkvg_rounded_rectangle (VkvgContext ctx, float x, float y, float w, float h, float radius); -/** -* @brief Add an axis aligned rectangle with rounded corners defined in both axis to the current path. -* -* Adds a closed sub-path rectangle of the given size to the current path at position (x, y). -* @param ctx The vkvg context pointer. -* @param x The x coordinate of the top left corner of the rectangle to emit. -* @param y The y coordinate of the top left corner of the rectangle to emit. -* @param w The width in pixel of the rectangle to draw. -* @param h The height in pixel of the rectangle to draw. -* @param rx The horizontal radius of the corners. -* @param ry The vertical radius of the corners. -* @return VKVG_STATUS_SUCCESS or VKVG_STATUS_INVALID_RECT if width or height is equal to 0. -*/ -vkvg_public -void vkvg_rounded_rectangle2 (VkvgContext ctx, float x, float y, float w, float h, float rx, float ry); +vkvg_public vkvg_status_t vkvg_rectangle(VkvgContext ctx, float x, float y, float w, float h); +/** + * @brief Add an axis aligned rectangle with rounded corners to the current path. + * + * Adds a closed sub-path rectangle of the given size to the current path at position (x, y). + * @param ctx The vkvg context pointer. + * @param x The x coordinate of the top left corner of the rectangle to emit. + * @param y The y coordinate of the top left corner of the rectangle to emit. + * @param w The width in pixel of the rectangle to draw. + * @param h The height in pixel of the rectangle to draw. + * @param radius The radius of the corners. + * @return VKVG_STATUS_SUCCESS or VKVG_STATUS_INVALID_RECT if width or height is equal to 0. + */ +vkvg_public vkvg_status_t vkvg_rounded_rectangle(VkvgContext ctx, float x, float y, float w, float h, float radius); +/** + * @brief Add an axis aligned rectangle with rounded corners defined in both axis to the current path. + * + * Adds a closed sub-path rectangle of the given size to the current path at position (x, y). + * @param ctx The vkvg context pointer. + * @param x The x coordinate of the top left corner of the rectangle to emit. + * @param y The y coordinate of the top left corner of the rectangle to emit. + * @param w The width in pixel of the rectangle to draw. + * @param h The height in pixel of the rectangle to draw. + * @param rx The horizontal radius of the corners. + * @param ry The vertical radius of the corners. + * @return VKVG_STATUS_SUCCESS or VKVG_STATUS_INVALID_RECT if width or height is equal to 0. + */ +vkvg_public void vkvg_rounded_rectangle2(VkvgContext ctx, float x, float y, float w, float h, float rx, float ry); /** * @brief Add a closed ellipse to the current path. @@ -1250,16 +1191,15 @@ void vkvg_rounded_rectangle2 (VkvgContext ctx, float x, float y, float w, float * @param y Ellipse's center y coordinate. * @param rotationAngle A clockwise rotation angle in radian. */ -vkvg_public -void vkvg_ellipse (VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle); +vkvg_public void vkvg_ellipse(VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle); /** * @brief Add an elliptical arc to the current path. * - * Draws an elliptical arc from the current point to (x, y). The size and orientation of the ellipse are defined by two radii (rx, ry) - * and an x-axis-rotation, which indicates how the ellipse as a whole is rotated relative to the current coordinate system. - * The center (cx, cy) of the ellipse is calculated automatically to satisfy the constraints imposed by the other parameters. - * For a given radii pair, there are two ellipses that could connect two random points. large-arc-flag and sweep-flag contribute - * to the automatic calculations and help determine how the arc is drawn. + * Draws an elliptical arc from the current point to (x, y). The size and orientation of the ellipse are defined by two + * radii (rx, ry) and an x-axis-rotation, which indicates how the ellipse as a whole is rotated relative to the current + * coordinate system. The center (cx, cy) of the ellipse is calculated automatically to satisfy the constraints imposed + * by the other parameters. For a given radii pair, there are two ellipses that could connect two random points. + * large-arc-flag and sweep-flag contribute to the automatic calculations and help determine how the arc is drawn. * * @image html elliptical-arc-options.svg * @@ -1272,12 +1212,13 @@ void vkvg_ellipse (VkvgContext ctx, float radiusX, float radiusY, float x, float * @param ry The y radius of the ellipse. * @param phi Clockwise rotation of the arc in radian. */ -vkvg_public -void vkvg_elliptic_arc_to (VkvgContext ctx, float x, float y, bool large_arc_flag, bool sweep_flag, float rx, float ry, float phi); +vkvg_public void vkvg_elliptic_arc_to(VkvgContext ctx, float x, float y, bool large_arc_flag, bool sweep_flag, float rx, + float ry, float phi); /** * @brief Add an elliptical arc to the current path. * - * This method has the same effect as a call to #vkvg_elliptic_arc_to except that the coordinate are expressed relative to the current point. + * This method has the same effect as a call to #vkvg_elliptic_arc_to except that the coordinate are expressed relative + * to the current point. * @param ctx A valid context handle. * @param x the arc end point x coordinate relative to the current point. * @param y the arc end point y coordinate relative to the current point. @@ -1287,19 +1228,18 @@ void vkvg_elliptic_arc_to (VkvgContext ctx, float x, float y, bool large_arc_fla * @param ry The y radius of the ellipse. * @param phi Clockwise rotation of the arc in radian. */ -vkvg_public -void vkvg_rel_elliptic_arc_to (VkvgContext ctx, float x, float y, bool large_arc_flag, bool sweep_flag, float rx, float ry, float phi); +vkvg_public void vkvg_rel_elliptic_arc_to(VkvgContext ctx, float x, float y, bool large_arc_flag, bool sweep_flag, + float rx, float ry, float phi); /** * @brief Stroke command * - * A drawing operator that strokes the current path according to the current line width, line join, line cap, and dash settings. - * After vkvg_stroke(), the current path will be cleared from the vkvg context. See #vkvg_set_line_width(), #vkvg_set_line_join(), - * #vkvg_set_line_cap(), #vkvg_set_dash(), and #vkvg_stroke_preserve(). + * A drawing operator that strokes the current path according to the current line width, line join, line cap, and dash + * settings. After vkvg_stroke(), the current path will be cleared from the vkvg context. See #vkvg_set_line_width(), + * #vkvg_set_line_join(), #vkvg_set_line_cap(), #vkvg_set_dash(), and #vkvg_stroke_preserve(). * * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_stroke (VkvgContext ctx); +vkvg_public void vkvg_stroke(VkvgContext ctx); /** * @brief Stroke command that preserve current path. * @@ -1307,8 +1247,7 @@ void vkvg_stroke (VkvgContext ctx); * * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_stroke_preserve (VkvgContext ctx); +vkvg_public void vkvg_stroke_preserve(VkvgContext ctx); /** * @brief Fill command * @@ -1317,8 +1256,7 @@ void vkvg_stroke_preserve (VkvgContext ctx); * * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_fill (VkvgContext ctx); +vkvg_public void vkvg_fill(VkvgContext ctx); /** * @brief Fill command that preserve current path. * @@ -1326,8 +1264,7 @@ void vkvg_fill (VkvgContext ctx); * * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_fill_preserve (VkvgContext ctx); +vkvg_public void vkvg_fill_preserve(VkvgContext ctx); /** * @brief Paint command. * @@ -1336,8 +1273,7 @@ void vkvg_fill_preserve (VkvgContext ctx); * * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_paint (VkvgContext ctx); +vkvg_public void vkvg_paint(VkvgContext ctx); /** * @brief Clear surface. * @@ -1348,8 +1284,7 @@ void vkvg_paint (VkvgContext ctx); * @remark To clear a surface not bound to a context, call #vkvg_surface_clear(). * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_clear (VkvgContext ctx);//use vkClearAttachment to speed up clearing surf +vkvg_public void vkvg_clear(VkvgContext ctx); // use vkClearAttachment to speed up clearing surf /** * @brief Reset the current clip region. * @@ -1357,25 +1292,25 @@ void vkvg_clear (VkvgContext ctx);//use vkClearAttachment to speed up clearing s * * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_reset_clip (VkvgContext ctx); +vkvg_public void vkvg_reset_clip(VkvgContext ctx); /** * @brief Establishes a new clip region. * - * Establishes a new clip region by intersecting the current clip region with the current path as it would be filled by @ref vkvg_fill() and - * according to the current fill rule (@ref vkvg_set_fill_rule()). + * Establishes a new clip region by intersecting the current clip region with the current path as it would be filled by + * @ref vkvg_fill() and according to the current fill rule (@ref vkvg_set_fill_rule()). * - * The current clip region affects all drawing operations by effectively masking out any changes to the surface that are outside the current clip region. + * The current clip region affects all drawing operations by effectively masking out any changes to the surface that are + * outside the current clip region. * * After vkvg_clip(), the current path will be cleared from the context. * - * Calling vkvg_clip() can only make the clip region smaller, never larger. But the current clip is part of the graphics state, - * so a temporary restriction of the clip region can be achieved by calling @ref vkvg_clip() within a @ref vkvg_save()/@ref vkvg_restore() pair. - * The only other means of increasing the size of the clip region is @ref vkvg_reset_clip(). + * Calling vkvg_clip() can only make the clip region smaller, never larger. But the current clip is part of the graphics + * state, so a temporary restriction of the clip region can be achieved by calling @ref vkvg_clip() within a @ref + * vkvg_save()/@ref vkvg_restore() pair. The only other means of increasing the size of the clip region is @ref + * vkvg_reset_clip(). * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_clip (VkvgContext ctx); +vkvg_public void vkvg_clip(VkvgContext ctx); /** * @brief Establishes a new clip region preserving the current path. * @@ -1383,8 +1318,7 @@ void vkvg_clip (VkvgContext ctx); * * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_clip_preserve (VkvgContext ctx); +vkvg_public void vkvg_clip_preserve(VkvgContext ctx); /** * @brief Set global opacity for drawing operations. * @@ -1393,24 +1327,23 @@ void vkvg_clip_preserve (VkvgContext ctx); * @param ctx a valid context handle. * @param opacity global opacity value between 0..1. */ +vkvg_public void vkvg_set_opacity(VkvgContext ctx, float opacity); vkvg_public -void vkvg_set_opacity (VkvgContext ctx, float opacity); -vkvg_public -/** - * @brief Get current opacity. - * - * Retrieve the current opacity for the supplied context as set by a call to #vkvg_set_opacity(). - * @param ctx a valid context handle. - * @return the current opacity of the supplied context. - */ -float vkvg_get_opacity (VkvgContext ctx); + /** + * @brief Get current opacity. + * + * Retrieve the current opacity for the supplied context as set by a call to #vkvg_set_opacity(). + * @param ctx a valid context handle. + * @return the current opacity of the supplied context. + */ + float + vkvg_get_opacity(VkvgContext ctx); /** * @brief Set current source for drawing to the solid color defined by the supplied 32bit integer. * @param ctx a valid vkvg @ref context * @param rgba color coded in 32bit integer. */ -vkvg_public -void vkvg_set_source_color (VkvgContext ctx, uint32_t c); +vkvg_public void vkvg_set_source_color(VkvgContext ctx, uint32_t c); /** * @brief set color with alpha. * @@ -1421,8 +1354,7 @@ void vkvg_set_source_color (VkvgContext ctx, uint32_t c); * @param b the blue component of the color. * @param a the alpha component holding the transparency for the current color. */ -vkvg_public -void vkvg_set_source_rgba (VkvgContext ctx, float r, float g, float b, float a); +vkvg_public void vkvg_set_source_rgba(VkvgContext ctx, float r, float g, float b, float a); /** * @brief set opaque color as new source. * @@ -1437,8 +1369,7 @@ void vkvg_set_source_rgba (VkvgContext ctx, float r, float g, float b, float a); * @param b the blue component of the color. * @param a the alpha component holding the transparency for the current color. */ -vkvg_public -void vkvg_set_source_rgb (VkvgContext ctx, float r, float g, float b); +vkvg_public void vkvg_set_source_rgb(VkvgContext ctx, float r, float g, float b); /** * @brief set line width for the next draw command. * @@ -1448,24 +1379,24 @@ void vkvg_set_source_rgb (VkvgContext ctx, float r, float g, float b); * @param ctx a valid vkvg @ref context * @param width new current line width for the context. */ -vkvg_public -void vkvg_set_line_width (VkvgContext ctx, float width); +vkvg_public void vkvg_set_line_width(VkvgContext ctx, float width); /** * @brief set line join miter size limit. * - * If the current line join style is set to VKVG_LINE_JOIN_MITER (see vkvg_set_line_join()), the miter limit is used to determine whether the lines should be - * joined with a bevel instead of a miter. Vkvg divides the length of the miter by the line width. If the result is greater than the miter limit, the style is converted to a bevel. + * If the current line join style is set to VKVG_LINE_JOIN_MITER (see vkvg_set_line_join()), the miter limit is used to + * determine whether the lines should be joined with a bevel instead of a miter. Vkvg divides the length of the miter by + * the line width. If the result is greater than the miter limit, the style is converted to a bevel. * - * The default miter limit value is 10.0, which will convert joins with interior angles less than 11 degrees to bevels instead of miters. - * For reference, a miter limit of 2.0 makes the miter cutoff at 60 degrees, and a miter limit of 1.414 makes the cutoff at 90 degrees. + * The default miter limit value is 10.0, which will convert joins with interior angles less than 11 degrees to bevels + * instead of miters. For reference, a miter limit of 2.0 makes the miter cutoff at 60 degrees, and a miter limit + * of 1.414 makes the cutoff at 90 degrees. * * A miter limit for a desired angle can be computed as: miter limit = 1/sin(angle/2) * * @param ctx a valid vkvg @ref context * @param limit new current miter limit value for the context. */ -vkvg_public -void vkvg_set_miter_limit (VkvgContext ctx, float limit); +vkvg_public void vkvg_set_miter_limit(VkvgContext ctx, float limit); /** * @brief Gets the current miter limit. * @@ -1474,8 +1405,7 @@ void vkvg_set_miter_limit (VkvgContext ctx, float limit); * @param ctx a valid vkvg @ref context * @return the current miter limit for the context. */ -vkvg_public -float vkvg_get_miter_limit (VkvgContext ctx); +vkvg_public float vkvg_get_miter_limit(VkvgContext ctx); /** * @brief set line terminations for the next draw command. * @@ -1483,8 +1413,7 @@ float vkvg_get_miter_limit (VkvgContext ctx); * @param ctx a valid vkvg @ref context * @param cap new line termination, may be one of the value of #vkvg_line_cap_t. */ -vkvg_public -void vkvg_set_line_cap (VkvgContext ctx, vkvg_line_cap_t cap); +vkvg_public void vkvg_set_line_cap(VkvgContext ctx, vkvg_line_cap_t cap); /** * @brief set line joins for the next draw command. * @@ -1492,8 +1421,7 @@ void vkvg_set_line_cap (VkvgContext ctx, vkvg_line_cap_t cap); * @param ctx a valid vkvg @ref context * @param join new line join as defined in #vkvg_line_joint_t. */ -vkvg_public -void vkvg_set_line_join (VkvgContext ctx, vkvg_line_join_t join); +vkvg_public void vkvg_set_line_join(VkvgContext ctx, vkvg_line_join_t join); /** * @brief use supplied surface as current pattern. * @@ -1503,8 +1431,7 @@ void vkvg_set_line_join (VkvgContext ctx, vkvg_line_join_t join); * @param x an x offset to apply for drawing operations using this surface. * @param y an y offset to apply for drawing operations using this surface. */ -vkvg_public -void vkvg_set_source_surface (VkvgContext ctx, VkvgSurface surf, float x, float y); +vkvg_public void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y); /** * @brief set supplied pattern as current source. * @@ -1512,24 +1439,21 @@ void vkvg_set_source_surface (VkvgContext ctx, VkvgSurface surf, float x, float * @param ctx a valid vkvg @ref context * @param pat the new pattern to use as source for further drawing operations. */ -vkvg_public -void vkvg_set_source (VkvgContext ctx, VkvgPattern pat); +vkvg_public void vkvg_set_source(VkvgContext ctx, VkvgPattern pat); /** * @brief * * @param ctx a valid vkvg @ref context * @param op */ -vkvg_public -void vkvg_set_operator (VkvgContext ctx, vkvg_operator_t op); +vkvg_public void vkvg_set_operator(VkvgContext ctx, vkvg_operator_t op); /** * @brief * * @param ctx a valid vkvg @ref context * @param fr */ -vkvg_public -void vkvg_set_fill_rule (VkvgContext ctx, vkvg_fill_rule_t fr); +vkvg_public void vkvg_set_fill_rule(VkvgContext ctx, vkvg_fill_rule_t fr); /** * @brief set the dash configuration for strokes * @@ -1542,8 +1466,7 @@ void vkvg_set_fill_rule (VkvgContext ctx, vkvg_fill_rule_t fr); * @param num_dashes the length of the dash array. * @param offset an offset into the dash pattern at which the stroke should start. */ -vkvg_public -void vkvg_set_dash (VkvgContext ctx, const float* dashes, uint32_t num_dashes, float offset); +vkvg_public void vkvg_set_dash(VkvgContext ctx, const float *dashes, uint32_t num_dashes, float offset); /** * @brief get current dash settings. * @@ -1555,8 +1478,7 @@ void vkvg_set_dash (VkvgContext ctx, const float* dashes, uint32_t num_dashes, f * @param num_dashes[out] return length of dash array or 0 if dash is not set. * @param offset[out] return value for the current dash offset */ -vkvg_public -void vkvg_get_dash (VkvgContext ctx, const float *dashes, uint32_t* num_dashes, float* offset); +vkvg_public void vkvg_get_dash(VkvgContext ctx, const float *dashes, uint32_t *num_dashes, float *offset); /** * @brief get current line width @@ -1565,32 +1487,28 @@ void vkvg_get_dash (VkvgContext ctx, const float *dashes, uint32_t* num_dashes, * @param ctx a valid vkvg @ref context * @return current line width. */ -vkvg_public -float vkvg_get_line_width (VkvgContext ctx); +vkvg_public float vkvg_get_line_width(VkvgContext ctx); /** * @brief * * @param ctx a valid vkvg @ref context * @return vkvg_line_cap_t */ -vkvg_public -vkvg_line_cap_t vkvg_get_line_cap (VkvgContext ctx); +vkvg_public vkvg_line_cap_t vkvg_get_line_cap(VkvgContext ctx); /** * @brief * * @param ctx a valid vkvg @ref context * @return vkvg_line_join_t */ -vkvg_public -vkvg_line_join_t vkvg_get_line_join (VkvgContext ctx); +vkvg_public vkvg_line_join_t vkvg_get_line_join(VkvgContext ctx); /** * @brief * * @param ctx a valid vkvg @ref context * @return vkvg_operator_t */ -vkvg_public -vkvg_operator_t vkvg_get_operator (VkvgContext ctx); +vkvg_public vkvg_operator_t vkvg_get_operator(VkvgContext ctx); /** * @brief Get current fill rule. * @@ -1602,8 +1520,7 @@ vkvg_operator_t vkvg_get_operator (VkvgContext ctx); * @param ctx a valid vkvg @ref context * @return vkvg_fill_rule_t The current fill rule of the context. */ -vkvg_public -vkvg_fill_rule_t vkvg_get_fill_rule (VkvgContext ctx); +vkvg_public vkvg_fill_rule_t vkvg_get_fill_rule(VkvgContext ctx); /** * @brief Get the current source of the context. * @@ -1612,8 +1529,7 @@ vkvg_fill_rule_t vkvg_get_fill_rule (VkvgContext ctx); * @param ctx a valid vkvg @ref context * @return VkvgPattern The current context's source. */ -vkvg_public -VkvgPattern vkvg_get_source (VkvgContext ctx); +vkvg_public VkvgPattern vkvg_get_source(VkvgContext ctx); /** * @brief Get the current target of the context. @@ -1622,8 +1538,7 @@ VkvgPattern vkvg_get_source (VkvgContext ctx); * @param ctx a valid vkvg @ref context * @return The currently bound target surface. */ -vkvg_public -VkvgSurface vkvg_get_target (VkvgContext ctx); +vkvg_public VkvgSurface vkvg_get_target(VkvgContext ctx); /** * @brief Check if context has a current point defined. * @@ -1633,8 +1548,7 @@ VkvgSurface vkvg_get_target (VkvgContext ctx); * @param ctx a valig vkvg @ref context * @return bool `true`if a current point is defined, `false` otherwise. **/ -vkvg_public -bool vkvg_has_current_point (VkvgContext ctx); +vkvg_public bool vkvg_has_current_point(VkvgContext ctx); /** * @brief Save context's graphic states. @@ -1644,8 +1558,7 @@ bool vkvg_has_current_point (VkvgContext ctx); * * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_save (VkvgContext ctx); +vkvg_public void vkvg_save(VkvgContext ctx); /** * @brief Restore context's graphic states. * @@ -1654,28 +1567,27 @@ void vkvg_save (VkvgContext ctx); * * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_restore (VkvgContext ctx); +vkvg_public void vkvg_restore(VkvgContext ctx); /** * @brief Add a translation to the current transformation matrix. * - * Modifies the current transformation matrix by applying an additional translation transformation by (dx,dy) in user space coordinate. + * Modifies the current transformation matrix by applying an additional translation transformation by (dx,dy) in user + * space coordinate. * @param ctx a valid vkvg @ref context * @param dx the x translation * @param dy the y translation */ -vkvg_public -void vkvg_translate (VkvgContext ctx, float dx, float dy); +vkvg_public void vkvg_translate(VkvgContext ctx, float dx, float dy); /** * @brief Add a scaling transform to the current transformation matrix. * - * Modifies the current transformation matrix by applying an additional scaling transformation by (sx,sy) in user space coordinate. + * Modifies the current transformation matrix by applying an additional scaling transformation by (sx,sy) in user space + * coordinate. * @param ctx a valid vkvg @ref context * @param sx scale in the x direction. * @param sy scale in the y direction. */ -vkvg_public -void vkvg_scale (VkvgContext ctx, float sx, float sy); +vkvg_public void vkvg_scale(VkvgContext ctx, float sx, float sy); /** * @brief Add a rotation to the current transformation matrix. * @@ -1683,8 +1595,7 @@ void vkvg_scale (VkvgContext ctx, float sx, float sy); * @param ctx a valid vkvg @ref context * @param radians rotation angle in radian. */ -vkvg_public -void vkvg_rotate (VkvgContext ctx, float radians); +vkvg_public void vkvg_rotate(VkvgContext ctx, float radians); /** * @brief Add an additional transformation to the current matrix. * @@ -1693,8 +1604,7 @@ void vkvg_rotate (VkvgContext ctx, float radians); * @param ctx a valid vkvg @ref context * @param matrix */ -vkvg_public -void vkvg_transform (VkvgContext ctx, const vkvg_matrix_t* matrix); +vkvg_public void vkvg_transform(VkvgContext ctx, const vkvg_matrix_t *matrix); /** * @brief Set the current matrix. * @@ -1703,8 +1613,7 @@ void vkvg_transform (VkvgContext ctx, const vkvg_matrix_t* matrix); * @param ctx a valid vkvg @ref context * @param matrix */ -vkvg_public -void vkvg_set_matrix (VkvgContext ctx, const vkvg_matrix_t* matrix); +vkvg_public void vkvg_set_matrix(VkvgContext ctx, const vkvg_matrix_t *matrix); /** * @brief Get the current matrix. * @@ -1713,8 +1622,7 @@ void vkvg_set_matrix (VkvgContext ctx, const vkvg_matrix_t* matrix); * @param ctx a valid vkvg @ref context * @param matrix a valid #vkvg_matrix_t pointer to receive the current context's transform. */ -vkvg_public -void vkvg_get_matrix (VkvgContext ctx, vkvg_matrix_t * const matrix); +vkvg_public void vkvg_get_matrix(VkvgContext ctx, vkvg_matrix_t *const matrix); /** * @brief Set the current matrix to identity. * @@ -1722,8 +1630,7 @@ void vkvg_get_matrix (VkvgContext ctx, vkvg_matrix_t * const matrix); * * @param ctx a valid vkvg @ref context */ -vkvg_public -void vkvg_identity_matrix (VkvgContext ctx); +vkvg_public void vkvg_identity_matrix(VkvgContext ctx); /** * @brief Try find font with the specified name using the FontConfig library. @@ -1731,8 +1638,7 @@ void vkvg_identity_matrix (VkvgContext ctx); * @param ctx a valid vkvg @ref context * @param name A name to be recognized by the FontConfig library */ -vkvg_public -void vkvg_select_font_face (VkvgContext ctx, const char* name); +vkvg_public void vkvg_select_font_face(VkvgContext ctx, const char *name); /** * @brief Select a new font by providing its file path. * @@ -1740,8 +1646,7 @@ void vkvg_select_font_face (VkvgContext ctx, const char* name); * @param path A valid font file path. * @param name A short name to select this font afteward */ -vkvg_public -void vkvg_load_font_from_path (VkvgContext ctx, const char* path, const char *name); +vkvg_public void vkvg_load_font_from_path(VkvgContext ctx, const char *path, const char *name); /** * @brief Select a new font by providing a pointer on the font file loaded in memory and its size in byte. * @@ -1750,16 +1655,15 @@ void vkvg_load_font_from_path (VkvgContext ctx, const char* path, const char *na * @param fontBufferByteSize the size of the font buffer in bytes. * @param name A short name to select this font afteward */ -vkvg_public -void vkvg_load_font_from_memory (VkvgContext ctx, unsigned char* fontBuffer, long fontBufferByteSize, const char* name); +vkvg_public void vkvg_load_font_from_memory(VkvgContext ctx, unsigned char *fontBuffer, long fontBufferByteSize, + const char *name); /** * @brief * * @param ctx a valid vkvg @ref context * @param size */ -vkvg_public -void vkvg_set_font_size (VkvgContext ctx, uint32_t size); +vkvg_public void vkvg_set_font_size(VkvgContext ctx, uint32_t size); /** * @brief Show a string of text. * @@ -1769,8 +1673,7 @@ void vkvg_set_font_size (VkvgContext ctx, uint32_t size); * @param ctx a valid vkvg @ref context * @param utf8 A null-terminated utf8 encoded string of text. */ -vkvg_public -void vkvg_show_text (VkvgContext ctx, const char* utf8); +vkvg_public void vkvg_show_text(VkvgContext ctx, const char *utf8); /** * @brief Gets the extents for a string of text. * @@ -1778,18 +1681,16 @@ void vkvg_show_text (VkvgContext ctx, const char* utf8); * @param utf8 A null-terminated utf8 encoded string of text. * @param extents */ -vkvg_public -void vkvg_text_extents (VkvgContext ctx, const char* utf8, vkvg_text_extents_t* extents); +vkvg_public void vkvg_text_extents(VkvgContext ctx, const char *utf8, vkvg_text_extents_t *extents); /** * @brief Gets the font extents for the currently selected font. * * @param ctx a valid vkvg @ref context * @param extents A valid #vkvg_font_extents_t handle to be filled with current font extents. */ -vkvg_public -void vkvg_font_extents (VkvgContext ctx, vkvg_font_extents_t* extents); +vkvg_public void vkvg_font_extents(VkvgContext ctx, vkvg_font_extents_t *extents); -//text run holds harfbuz datas, and prevent recreating them multiple times for the same line of text. +// text run holds harfbuz datas, and prevent recreating them multiple times for the same line of text. /** * @brief Create a new text run. * @@ -1797,8 +1698,7 @@ void vkvg_font_extents (VkvgContext ctx, vkvg_font_extents_t* extents); * @param text Null terminated utf8 string. * @return VkvgText */ -vkvg_public -VkvgText vkvg_text_run_create (VkvgContext ctx, const char* text); +vkvg_public VkvgText vkvg_text_run_create(VkvgContext ctx, const char *text); /** * @brief Create a new text run for a non null terminated string. * @@ -1807,46 +1707,38 @@ VkvgText vkvg_text_run_create (VkvgContext ctx, const char* text); * @param length glyphs count, not to be confused with byte length. * @return VkvgText */ -vkvg_public -VkvgText vkvg_text_run_create_with_length (VkvgContext ctx, const char* text, uint32_t length); +vkvg_public VkvgText vkvg_text_run_create_with_length(VkvgContext ctx, const char *text, uint32_t length); /** * @brief Release resources holded by the text run. * * @param VkvgtextRun A valid VkvgText pointer. */ -vkvg_public -void vkvg_text_run_destroy (VkvgText textRun); +vkvg_public void vkvg_text_run_destroy(VkvgText textRun); /** * @brief * * @param ctx a valid vkvg @ref context * @param textRun */ -vkvg_public -void vkvg_show_text_run (VkvgContext ctx, VkvgText textRun); +vkvg_public void vkvg_show_text_run(VkvgContext ctx, VkvgText textRun); /** * @brief * * @param textRun * @param extents */ -vkvg_public -void vkvg_text_run_get_extents (VkvgText textRun, vkvg_text_extents_t* extents); +vkvg_public void vkvg_text_run_get_extents(VkvgText textRun, vkvg_text_extents_t *extents); /** * @brief Get glyph count of text run. * * @return glyph count */ -vkvg_public -uint32_t vkvg_text_run_get_glyph_count (VkvgText textRun); +vkvg_public uint32_t vkvg_text_run_get_glyph_count(VkvgText textRun); /** * @brief retrieve glyph positions. * */ -vkvg_public -void vkvg_text_run_get_glyph_position (VkvgText textRun, - uint32_t index, - vkvg_glyph_info_t* pGlyphInfo); +vkvg_public void vkvg_text_run_get_glyph_position(VkvgText textRun, uint32_t index, vkvg_glyph_info_t *pGlyphInfo); /** @}*/ /** @@ -1864,8 +1756,7 @@ void vkvg_text_run_get_glyph_position (VkvgText textRun, * @param pat A valid pattern handle. * @return The current status of the pattern. */ -vkvg_public -vkvg_status_t vkvg_pattern_status (VkvgPattern pat); +vkvg_public vkvg_status_t vkvg_pattern_status(VkvgPattern pat); /** * @brief add reference * @@ -1873,8 +1764,7 @@ vkvg_status_t vkvg_pattern_status (VkvgPattern pat); * @param pat a valid #VkvgPattern pointer * @return VkvgPattern */ -vkvg_public -VkvgPattern vkvg_pattern_reference (VkvgPattern pat); +vkvg_public VkvgPattern vkvg_pattern_reference(VkvgPattern pat); /** * @brief get reference count * @@ -1882,8 +1772,7 @@ VkvgPattern vkvg_pattern_reference (VkvgPattern pat); * @param pat a valid #VkvgPattern to query for its reference count * @return uint32_t the current reference count for this instance. */ -vkvg_public -uint32_t vkvg_pattern_get_reference_count (VkvgPattern pat); +vkvg_public uint32_t vkvg_pattern_get_reference_count(VkvgPattern pat); /** * @brief create a surface pattern * @@ -1894,8 +1783,7 @@ uint32_t vkvg_pattern_get_reference_count (VkvgPattern pat); * @param surf a valid #VkvgSurface to use for pattern * @return VkvgPattern a newly created pattern */ -vkvg_public -VkvgPattern vkvg_pattern_create_for_surface (VkvgSurface surf); +vkvg_public VkvgPattern vkvg_pattern_create_for_surface(VkvgSurface surf); /** * @brief create a new linear gradient. * @@ -1908,8 +1796,7 @@ VkvgPattern vkvg_pattern_create_for_surface (VkvgSurface surf); * @param y1 y coordinate of the end point * @return VkvgPattern the newly created pattern, call @ref vkvg_pattern_destroy when finished with it. */ -vkvg_public -VkvgPattern vkvg_pattern_create_linear (float x0, float y0, float x1, float y1); +vkvg_public VkvgPattern vkvg_pattern_create_linear(float x0, float y0, float x1, float y1); /** * @brief edit an existing linear gradient. * @@ -1921,8 +1808,7 @@ VkvgPattern vkvg_pattern_create_linear (float x0, float y0, float x1, float y1); * @param y1 y coordinate of the end point * @return VKVG_STATUS_SUCCESS, or VKVG_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a linear gradient. */ -vkvg_public -vkvg_status_t vkvg_pattern_edit_linear(VkvgPattern pat, float x0, float y0, float x1, float y1); +vkvg_public vkvg_status_t vkvg_pattern_edit_linear(VkvgPattern pat, float x0, float y0, float x1, float y1); /** * @brief get the gradient end points for a linear gradient * @@ -1934,11 +1820,10 @@ vkvg_status_t vkvg_pattern_edit_linear(VkvgPattern pat, float x0, float y0, floa * @param y1 y coordinate of the end point * @return VKVG_STATUS_SUCCESS, or VKVG_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a linear gradient. */ -vkvg_public -vkvg_status_t vkvg_pattern_get_linear_points(VkvgPattern pat, float* x0, float* y0, float* x1, float* y1); +vkvg_public vkvg_status_t vkvg_pattern_get_linear_points(VkvgPattern pat, float *x0, float *y0, float *x1, float *y1); /** * @brief create a new radial gradient. - * + * * Creates a new radial gradient between the two circles defined by (cx0, cy0, radius0) and (cx1, cy1, radius1). * Before using the gradient pattern, a number of color stops should be defined using vkvg_pattern_add_color_stop. * @@ -1950,9 +1835,8 @@ vkvg_status_t vkvg_pattern_get_linear_points(VkvgPattern pat, float* x0, float* * @param radius1 radius for the center of the end circle, the outer circle. * @return VkvgPattern the newly created pattern to be disposed when finished by calling @ref vkvg_pattern_destroy. */ -vkvg_public -VkvgPattern vkvg_pattern_create_radial (float cx0, float cy0, float radius0, - float cx1, float cy1, float radius1); +vkvg_public VkvgPattern vkvg_pattern_create_radial(float cx0, float cy0, float radius0, float cx1, float cy1, + float radius1); /** * @brief edit an existing radial gradient. * @@ -1967,10 +1851,8 @@ VkvgPattern vkvg_pattern_create_radial (float cx0, float cy0, float radius0, * @param radius1 radius for the center of the end circle, the outer circle. * @return VKVG_STATUS_SUCCESS, or VKVG_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a radial gradient. */ -vkvg_public -vkvg_status_t vkvg_pattern_edit_radial(VkvgPattern pat, - float cx0, float cy0, float radius0, - float cx1, float cy1, float radius1); +vkvg_public vkvg_status_t vkvg_pattern_edit_radial(VkvgPattern pat, float cx0, float cy0, float radius0, float cx1, + float cy1, float radius1); /** * @brief get color stop count. * @@ -1980,13 +1862,12 @@ vkvg_status_t vkvg_pattern_edit_radial(VkvgPattern pat, * @param count a valid integer pointer to old the current stop count returned. * @return VKVG_STATUS_SUCCESS, or VKVG_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a gradient. */ -vkvg_public -vkvg_status_t vkvg_pattern_get_color_stop_count (VkvgPattern pat, uint32_t* count); +vkvg_public vkvg_status_t vkvg_pattern_get_color_stop_count(VkvgPattern pat, uint32_t *count); /** * @brief get color stop. * - * Gets the color and offset information at the given index for a gradient pattern. Values of index range from 0 to n-1 where n is the number - * returned by @ref vkvg_pattern_get_color_stop_count(). + * Gets the color and offset information at the given index for a gradient pattern. Values of index range from 0 to n-1 + * where n is the number returned by @ref vkvg_pattern_get_color_stop_count(). * * @param pat a valid pattern pointer. * @param index index of the stop to return data for. @@ -1995,24 +1876,23 @@ vkvg_status_t vkvg_pattern_get_color_stop_count (VkvgPattern pat, uint32_t* coun * @param g a valid float pointer to old the green component. * @param b a valid float pointer to old the blue component. * @param a a valid float pointer to old the alpha component. - * @return VKVG_STATUS_SUCCESS, VKVG_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a gradient, VKVG_STATUS_INVALID_INDEX if index is out of bounds. + * @return VKVG_STATUS_SUCCESS, VKVG_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a gradient, + * VKVG_STATUS_INVALID_INDEX if index is out of bounds. */ -vkvg_public -vkvg_status_t vkvg_pattern_get_color_stop_rgba (VkvgPattern pat, uint32_t index, - float* offset, float* r, float* g, float* b, float* a); +vkvg_public vkvg_status_t vkvg_pattern_get_color_stop_rgba(VkvgPattern pat, uint32_t index, float *offset, float *r, + float *g, float *b, float *a); /** * @brief dispose pattern. - * + * * When you have finished using a pattern, free its resources by calling this method. * * @param pat the pattern to destroy. */ -vkvg_public -void vkvg_pattern_destroy (VkvgPattern pat); +vkvg_public void vkvg_pattern_destroy(VkvgPattern pat); /** * @brief add colors to gradients - * + * * for each color step in the gradient, call this method and provide an absolute position between 0 and 1 * and a color. * @@ -2023,43 +1903,39 @@ void vkvg_pattern_destroy (VkvgPattern pat); * @param b the blue component of the color stop * @param a the alpha chanel of the color stop */ -vkvg_public -vkvg_status_t vkvg_pattern_add_color_stop(VkvgPattern pat, float offset, float r, float g, float b, float a); +vkvg_public vkvg_status_t vkvg_pattern_add_color_stop(VkvgPattern pat, float offset, float r, float g, float b, + float a); /** * @brief control the extend of the pattern - * + * * control whether the pattern has to be repeated or extended when painted on a surface. * * @param pat the pattern to set extend for. * @param extend one value of the @ref vkvg_extend_t enumeration. * @return VKVG_STATUS_SUCCESS, or VKVG_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a gradient. */ -vkvg_public -void vkvg_pattern_set_extend (VkvgPattern pat, vkvg_extend_t extend); +vkvg_public void vkvg_pattern_set_extend(VkvgPattern pat, vkvg_extend_t extend); /** * @brief control the filtering when using this pattern on a surface. * * @param pat pat the pattern to set filter for. * @param filter one value of the @ref vkvg_filter_t enumeration. */ -vkvg_public -void vkvg_pattern_set_filter (VkvgPattern pat, vkvg_filter_t filter); +vkvg_public void vkvg_pattern_set_filter(VkvgPattern pat, vkvg_filter_t filter); /** * @brief query the current extend value for a pa * * @param pat * @return vkvg_extend_t */ -vkvg_public -vkvg_extend_t vkvg_pattern_get_extend (VkvgPattern pat); +vkvg_public vkvg_extend_t vkvg_pattern_get_extend(VkvgPattern pat); /** * @brief * * @param pat * @return vkvg_filter_t */ -vkvg_public -vkvg_filter_t vkvg_pattern_get_filter (VkvgPattern pat); +vkvg_public vkvg_filter_t vkvg_pattern_get_filter(VkvgPattern pat); /** * @brief get pattern type * @@ -2068,38 +1944,26 @@ vkvg_filter_t vkvg_pattern_get_filter (VkvgPattern pat); * @param pat the pattern to query * @return vkvg_pattern_type_t */ -vkvg_public -vkvg_pattern_type_t vkvg_pattern_get_type (VkvgPattern pat); -vkvg_public -void vkvg_pattern_set_matrix (VkvgPattern pat, const vkvg_matrix_t* matrix); -vkvg_public -void vkvg_pattern_get_matrix (VkvgPattern pat, vkvg_matrix_t* matrix); +vkvg_public vkvg_pattern_type_t vkvg_pattern_get_type(VkvgPattern pat); +vkvg_public void vkvg_pattern_set_matrix(VkvgPattern pat, const vkvg_matrix_t *matrix); +vkvg_public void vkvg_pattern_get_matrix(VkvgPattern pat, vkvg_matrix_t *matrix); /** @}*/ /********* EXPERIMENTAL **************/ -vkvg_public -void vkvg_set_source_color_name (VkvgContext ctx, const char* color); +vkvg_public void vkvg_set_source_color_name(VkvgContext ctx, const char *color); #ifdef VKVG_RECORDING -typedef struct _vkvg_recording_t* VkvgRecording; +typedef struct _vkvg_recording_t *VkvgRecording; -vkvg_public -void vkvg_start_recording (VkvgContext ctx); -vkvg_public -VkvgRecording vkvg_stop_recording (VkvgContext ctx); -vkvg_public -void vkvg_replay (VkvgContext ctx, VkvgRecording rec); -vkvg_public -void vkvg_replay_command (VkvgContext ctx, VkvgRecording rec, uint32_t cmdIndex); -vkvg_public -void vkvg_recording_get_command (VkvgRecording rec, uint32_t cmdIndex, uint32_t* cmd, void** dataOffset); -vkvg_public -uint32_t vkvg_recording_get_count(VkvgRecording rec); -vkvg_public -void* vkvg_recording_get_data (VkvgRecording rec); -vkvg_public -void vkvg_recording_destroy (VkvgRecording rec); +vkvg_public void vkvg_start_recording(VkvgContext ctx); +vkvg_public VkvgRecording vkvg_stop_recording(VkvgContext ctx); +vkvg_public void vkvg_replay(VkvgContext ctx, VkvgRecording rec); +vkvg_public void vkvg_replay_command(VkvgContext ctx, VkvgRecording rec, uint32_t cmdIndex); +vkvg_public void vkvg_recording_get_command(VkvgRecording rec, uint32_t cmdIndex, uint32_t *cmd, void **dataOffset); +vkvg_public uint32_t vkvg_recording_get_count(VkvgRecording rec); +vkvg_public void *vkvg_recording_get_data(VkvgRecording rec); +vkvg_public void vkvg_recording_destroy(VkvgRecording rec); /*************************************/ #endif diff --git a/src/cross_os.c b/src/cross_os.c index 41ec036..e7c1a0c 100644 --- a/src/cross_os.c +++ b/src/cross_os.c @@ -25,23 +25,23 @@ #define _CRT_SECURE_NO_WARNINGS -int directoryExists (const char* path) { +int directoryExists(const char *path) { #if defined(_WIN32) || defined(_WIN64) #elif __APPLE__ #elif __unix__ - struct stat st = {0}; - return stat(path, &st)+1; + struct stat st = {0}; + return stat(path, &st) + 1; #else - return -1; + return -1; #endif } -const char* getUserDir () { +const char *getUserDir() { #if defined(_WIN32) || defined(_WIN64) - return getenv("HOME"); + return getenv("HOME"); #elif __APPLE__ #elif __unix__ - struct passwd *pw = getpwuid(getuid()); - return pw->pw_dir; + struct passwd *pw = getpwuid(getuid()); + return pw->pw_dir; #endif } @@ -53,20 +53,20 @@ const char* getUserDir () { #include void handler(int sig) { - void *array[100]; - size_t size; + void *array[100]; + size_t size; - // get void*'s for all entries on the stack - size = backtrace(array, 100); + // get void*'s for all entries on the stack + size = backtrace(array, 100); - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); - exit(1); + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, STDERR_FILENO); + exit(1); } -void _linux_register_error_handler () { - signal(SIGSEGV, handler); // install our handler - signal(SIGABRT, handler); // install our handler +void _linux_register_error_handler() { + signal(SIGSEGV, handler); // install our handler + signal(SIGABRT, handler); // install our handler } #endif diff --git a/src/cross_os.h b/src/cross_os.h index e2d4350..e047ba8 100644 --- a/src/cross_os.h +++ b/src/cross_os.h @@ -22,36 +22,36 @@ #ifndef CROSS_OS_H #define CROSS_OS_H -//cross platform os helpers +// cross platform os helpers #if defined(_WIN32) || defined(_WIN64) - //disable warning on iostream functions on windows - #define _CRT_SECURE_NO_WARNINGS - #include "windows.h" - #if defined(_WIN64) - #ifndef isnan - #define isnan _isnanf - #endif - #endif - #define vkvg_inline __forceinline - #define disable_warning (warn) - #define reset_warning (warn) +// disable warning on iostream functions on windows +#define _CRT_SECURE_NO_WARNINGS +#include "windows.h" +#if defined(_WIN64) +#ifndef isnan +#define isnan _isnanf +#endif +#endif +#define vkvg_inline __forceinline +#define disable_warning (warn) +#define reset_warning (warn) #elif __APPLE__ - #include - #define vkvg_inline static - #define disable_warning (warn) - #define reset_warning (warn) +#include +#define vkvg_inline static +#define disable_warning (warn) +#define reset_warning (warn) #elif __unix__ - #include - #include - #include - #define vkvg_inline static inline __attribute((always_inline)) - #define disable_warning (warn) #pragma GCC diagnostic ignored "-W"#warn - #define reset_warning (warn) #pragma GCC diagnostic warning "-W"#warn - #if __linux__ - void _linux_register_error_handler (); - #endif +#include +#include +#include +#define vkvg_inline static inline __attribute((always_inline)) +#define disable_warning (warn) #pragma GCC diagnostic ignored "-W" #warn +#define reset_warning (warn) #pragma GCC diagnostic warning "-W" #warn +#if __linux__ +void _linux_register_error_handler(); +#endif #endif -const char* getUserDir (); +const char *getUserDir(); #endif // CROSS_OS_H diff --git a/src/deps/tinycthread.c b/src/deps/tinycthread.c index f9cea2e..5dcf01f 100644 --- a/src/deps/tinycthread.c +++ b/src/deps/tinycthread.c @@ -32,103 +32,96 @@ freely, subject to the following restrictions: /* Platform specific includes */ #if defined(_TTHREAD_POSIX_) - #include - #include - #include - #include - #include +#include +#include +#include +#include +#include #elif defined(_TTHREAD_WIN32_) - #include - #include +#include +#include #endif /* Standard, good-to-have defines */ #ifndef NULL - #define NULL (void*)0 +#define NULL (void *)0 #endif #ifndef TRUE - #define TRUE 1 +#define TRUE 1 #endif #ifndef FALSE - #define FALSE 0 +#define FALSE 0 #endif -int mtx_init(mtx_t *mtx, int type) -{ +int mtx_init(mtx_t *mtx, int type) { #if defined(_TTHREAD_WIN32_) - mtx->mAlreadyLocked = FALSE; - mtx->mRecursive = type & mtx_recursive; - InitializeCriticalSection(&mtx->mHandle); - return thrd_success; + mtx->mAlreadyLocked = FALSE; + mtx->mRecursive = type & mtx_recursive; + InitializeCriticalSection(&mtx->mHandle); + return thrd_success; #else - int ret; - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - if (type & mtx_recursive) - { - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - } - ret = pthread_mutex_init(mtx, &attr); - pthread_mutexattr_destroy(&attr); - return ret == 0 ? thrd_success : thrd_error; + int ret; + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + if (type & mtx_recursive) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + ret = pthread_mutex_init(mtx, &attr); + pthread_mutexattr_destroy(&attr); + return ret == 0 ? thrd_success : thrd_error; #endif } -void mtx_destroy(mtx_t *mtx) -{ +void mtx_destroy(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mtx->mHandle); + DeleteCriticalSection(&mtx->mHandle); #else - pthread_mutex_destroy(mtx); + pthread_mutex_destroy(mtx); #endif } -int mtx_lock(mtx_t *mtx) -{ +int mtx_lock(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mtx->mHandle); - if (!mtx->mRecursive) - { - while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */ - mtx->mAlreadyLocked = TRUE; - } - return thrd_success; + EnterCriticalSection(&mtx->mHandle); + if (!mtx->mRecursive) { + while (mtx->mAlreadyLocked) + Sleep(1000); /* Simulate deadlock... */ + mtx->mAlreadyLocked = TRUE; + } + return thrd_success; #else - return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; + return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; #endif } -int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) -{ - /* FIXME! */ - (void)mtx; - (void)ts; - return thrd_error; +int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) { + /* FIXME! */ + (void)mtx; + (void)ts; + return thrd_error; } -int mtx_trylock(mtx_t *mtx) -{ +int mtx_trylock(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; - if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) - { - LeaveCriticalSection(&mtx->mHandle); - ret = thrd_busy; - } - return ret; + int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; + if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) { + LeaveCriticalSection(&mtx->mHandle); + ret = thrd_busy; + } + return ret; #else - return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; + return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; #endif } -int mtx_unlock(mtx_t *mtx) -{ +int mtx_unlock(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - mtx->mAlreadyLocked = FALSE; - LeaveCriticalSection(&mtx->mHandle); - return thrd_success; + mtx->mAlreadyLocked = FALSE; + LeaveCriticalSection(&mtx->mHandle); + return thrd_success; #else - return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;; + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; + ; #endif } @@ -137,458 +130,397 @@ int mtx_unlock(mtx_t *mtx) #define _CONDITION_EVENT_ALL 1 #endif -int cnd_init(cnd_t *cond) -{ +int cnd_init(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - cond->mWaitersCount = 0; + cond->mWaitersCount = 0; - /* Init critical section */ - InitializeCriticalSection(&cond->mWaitersCountLock); + /* Init critical section */ + InitializeCriticalSection(&cond->mWaitersCountLock); - /* Init events */ - cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); - if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) - { - cond->mEvents[_CONDITION_EVENT_ALL] = NULL; - return thrd_error; - } - cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); - if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); - cond->mEvents[_CONDITION_EVENT_ONE] = NULL; - return thrd_error; - } + /* Init events */ + cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) { + cond->mEvents[_CONDITION_EVENT_ALL] = NULL; + return thrd_error; + } + cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + cond->mEvents[_CONDITION_EVENT_ONE] = NULL; + return thrd_error; + } - return thrd_success; + return thrd_success; #else - return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; + return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; #endif } -void cnd_destroy(cnd_t *cond) -{ +void cnd_destroy(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); - } - if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); - } - DeleteCriticalSection(&cond->mWaitersCountLock); + if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + } + if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); + } + DeleteCriticalSection(&cond->mWaitersCountLock); #else - pthread_cond_destroy(cond); + pthread_cond_destroy(cond); #endif } -int cnd_signal(cnd_t *cond) -{ +int cnd_signal(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - int haveWaiters; - - /* Are there any waiters? */ - EnterCriticalSection(&cond->mWaitersCountLock); - haveWaiters = (cond->mWaitersCount > 0); - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* If we have any waiting threads, send them a signal */ - if(haveWaiters) - { - if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) - { - return thrd_error; + int haveWaiters; + + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we have any waiting threads, send them a signal */ + if (haveWaiters) { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) { + return thrd_error; + } } - } - return thrd_success; + return thrd_success; #else - return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; #endif } -int cnd_broadcast(cnd_t *cond) -{ +int cnd_broadcast(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - int haveWaiters; - - /* Are there any waiters? */ - EnterCriticalSection(&cond->mWaitersCountLock); - haveWaiters = (cond->mWaitersCount > 0); - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* If we have any waiting threads, send them a signal */ - if(haveWaiters) - { - if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) - { - return thrd_error; + int haveWaiters; + + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we have any waiting threads, send them a signal */ + if (haveWaiters) { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) { + return thrd_error; + } } - } - return thrd_success; + return thrd_success; #else - return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; #endif } #if defined(_TTHREAD_WIN32_) -static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) -{ - int result, lastWaiter; - - /* Increment number of waiters */ - EnterCriticalSection(&cond->mWaitersCountLock); - ++ cond->mWaitersCount; - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* Release the mutex while waiting for the condition (will decrease - the number of waiters when done)... */ - mtx_unlock(mtx); - - /* Wait for either event to become signaled due to cnd_signal() or - cnd_broadcast() being called */ - result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); - if (result == WAIT_TIMEOUT) - { - return thrd_timeout; - } - else if (result == (int)WAIT_FAILED) - { - return thrd_error; - } - - /* Check if we are the last waiter */ - EnterCriticalSection(&cond->mWaitersCountLock); - -- cond->mWaitersCount; - lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && - (cond->mWaitersCount == 0); - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* If we are the last waiter to be notified to stop waiting, reset the event */ - if (lastWaiter) - { - if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) - { - return thrd_error; +static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) { + int result, lastWaiter; + + /* Increment number of waiters */ + EnterCriticalSection(&cond->mWaitersCountLock); + ++cond->mWaitersCount; + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* Release the mutex while waiting for the condition (will decrease + the number of waiters when done)... */ + mtx_unlock(mtx); + + /* Wait for either event to become signaled due to cnd_signal() or + cnd_broadcast() being called */ + result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); + if (result == WAIT_TIMEOUT) { + return thrd_timeout; + } else if (result == (int)WAIT_FAILED) { + return thrd_error; + } + + /* Check if we are the last waiter */ + EnterCriticalSection(&cond->mWaitersCountLock); + --cond->mWaitersCount; + lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && (cond->mWaitersCount == 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we are the last waiter to be notified to stop waiting, reset the event */ + if (lastWaiter) { + if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) { + return thrd_error; + } } - } - /* Re-acquire the mutex */ - mtx_lock(mtx); + /* Re-acquire the mutex */ + mtx_lock(mtx); - return thrd_success; + return thrd_success; } #endif -int cnd_wait(cnd_t *cond, mtx_t *mtx) -{ +int cnd_wait(cnd_t *cond, mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - return _cnd_timedwait_win32(cond, mtx, INFINITE); + return _cnd_timedwait_win32(cond, mtx, INFINITE); #else - return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; #endif } -int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) -{ +int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) { #if defined(_TTHREAD_WIN32_) - struct timespec now; - if (clock_gettime(CLOCK_REALTIME, &now) == 0) - { - DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 + - (ts->tv_nsec - now.tv_nsec + 500000) / 1000000); - return _cnd_timedwait_win32(cond, mtx, delta); - } - else - return thrd_error; + struct timespec now; + if (clock_gettime(CLOCK_REALTIME, &now) == 0) { + DWORD delta = (DWORD)((ts->tv_sec - now.tv_sec) * 1000 + (ts->tv_nsec - now.tv_nsec + 500000) / 1000000); + return _cnd_timedwait_win32(cond, mtx, delta); + } else + return thrd_error; #else - int ret; - ret = pthread_cond_timedwait(cond, mtx, ts); - if (ret == ETIMEDOUT) - { - return thrd_timeout; - } - return ret == 0 ? thrd_success : thrd_error; + int ret; + ret = pthread_cond_timedwait(cond, mtx, ts); + if (ret == ETIMEDOUT) { + return thrd_timeout; + } + return ret == 0 ? thrd_success : thrd_error; #endif } - /** Information to pass to the new thread (what to run). */ typedef struct { - thrd_start_t mFunction; /**< Pointer to the function to be executed. */ - void * mArg; /**< Function argument for the thread function. */ + thrd_start_t mFunction; /**< Pointer to the function to be executed. */ + void *mArg; /**< Function argument for the thread function. */ } _thread_start_info; /* Thread wrapper function. */ #if defined(_TTHREAD_WIN32_) -static unsigned WINAPI _thrd_wrapper_function(void * aArg) +static unsigned WINAPI _thrd_wrapper_function(void *aArg) #elif defined(_TTHREAD_POSIX_) -static void * _thrd_wrapper_function(void * aArg) +static void *_thrd_wrapper_function(void *aArg) #endif { - thrd_start_t fun; - void *arg; - int res; + thrd_start_t fun; + void *arg; + int res; #if defined(_TTHREAD_POSIX_) - void *pres; + void *pres; #endif - /* Get thread startup information */ - _thread_start_info *ti = (_thread_start_info *) aArg; - fun = ti->mFunction; - arg = ti->mArg; + /* Get thread startup information */ + _thread_start_info *ti = (_thread_start_info *)aArg; + fun = ti->mFunction; + arg = ti->mArg; - /* The thread is responsible for freeing the startup information */ - free((void *)ti); + /* The thread is responsible for freeing the startup information */ + free((void *)ti); - /* Call the actual client thread function */ - res = fun(arg); + /* Call the actual client thread function */ + res = fun(arg); #if defined(_TTHREAD_WIN32_) - return res; + return res; #else - pres = malloc(sizeof(int)); - if (pres != NULL) - { - *(int*)pres = res; - } - return pres; + pres = malloc(sizeof(int)); + if (pres != NULL) { + *(int *)pres = res; + } + return pres; #endif } -int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) -{ - /* Fill out the thread startup information (passed to the thread wrapper, - which will eventually free it) */ - _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info)); - if (ti == NULL) - { - return thrd_nomem; - } - ti->mFunction = func; - ti->mArg = arg; - - /* Create the thread */ +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { + /* Fill out the thread startup information (passed to the thread wrapper, + which will eventually free it) */ + _thread_start_info *ti = (_thread_start_info *)malloc(sizeof(_thread_start_info)); + if (ti == NULL) { + return thrd_nomem; + } + ti->mFunction = func; + ti->mArg = arg; + + /* Create the thread */ #if defined(_TTHREAD_WIN32_) - *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); + *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); #elif defined(_TTHREAD_POSIX_) - if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) - { - *thr = 0; - } + if (pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) { + *thr = 0; + } #endif - /* Did we fail to create the thread? */ - if(!*thr) - { - free(ti); - return thrd_error; - } + /* Did we fail to create the thread? */ + if (!*thr) { + free(ti); + return thrd_error; + } - return thrd_success; + return thrd_success; } -thrd_t thrd_current(void) -{ +thrd_t thrd_current(void) { #if defined(_TTHREAD_WIN32_) - return GetCurrentThread(); + return GetCurrentThread(); #else - return pthread_self(); + return pthread_self(); #endif } -int thrd_detach(thrd_t thr) -{ - /* FIXME! */ - (void)thr; - return thrd_error; +int thrd_detach(thrd_t thr) { + /* FIXME! */ + (void)thr; + return thrd_error; } -int thrd_equal(thrd_t thr0, thrd_t thr1) -{ +int thrd_equal(thrd_t thr0, thrd_t thr1) { #if defined(_TTHREAD_WIN32_) - return thr0 == thr1; + return thr0 == thr1; #else - return pthread_equal(thr0, thr1); + return pthread_equal(thr0, thr1); #endif } -void thrd_exit(int res) -{ +void thrd_exit(int res) { #if defined(_TTHREAD_WIN32_) - ExitThread(res); + ExitThread(res); #else - void *pres = malloc(sizeof(int)); - if (pres != NULL) - { - *(int*)pres = res; - } - pthread_exit(pres); + void *pres = malloc(sizeof(int)); + if (pres != NULL) { + *(int *)pres = res; + } + pthread_exit(pres); #endif } -int thrd_join(thrd_t thr, int *res) -{ +int thrd_join(thrd_t thr, int *res) { #if defined(_TTHREAD_WIN32_) - if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) - { - return thrd_error; - } - if (res != NULL) - { - DWORD dwRes; - GetExitCodeThread(thr, &dwRes); - *res = dwRes; - } + if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) { + return thrd_error; + } + if (res != NULL) { + DWORD dwRes; + GetExitCodeThread(thr, &dwRes); + *res = dwRes; + } #elif defined(_TTHREAD_POSIX_) - void *pres; - int ires = 0; - if (pthread_join(thr, &pres) != 0) - { - return thrd_error; - } - if (pres != NULL) - { - ires = *(int*)pres; - free(pres); - } - if (res != NULL) - { - *res = ires; - } -#endif - return thrd_success; + void *pres; + int ires = 0; + if (pthread_join(thr, &pres) != 0) { + return thrd_error; + } + if (pres != NULL) { + ires = *(int *)pres; + free(pres); + } + if (res != NULL) { + *res = ires; + } +#endif + return thrd_success; } -int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) -{ - struct timespec now; +int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) { + struct timespec now; #if defined(_TTHREAD_WIN32_) - DWORD delta; + DWORD delta; #else - long delta; + long delta; #endif - /* Get the current time */ - if (clock_gettime(CLOCK_REALTIME, &now) != 0) - return -2; // FIXME: Some specific error code? + /* Get the current time */ + if (clock_gettime(CLOCK_REALTIME, &now) != 0) + return -2; // FIXME: Some specific error code? #if defined(_TTHREAD_WIN32_) - /* Delta in milliseconds */ - delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 + - (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); - if (delta > 0) - { - Sleep(delta); - } + /* Delta in milliseconds */ + delta = (DWORD)((time_point->tv_sec - now.tv_sec) * 1000 + (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); + if (delta > 0) { + Sleep(delta); + } #else - /* Delta in microseconds */ - delta = (time_point->tv_sec - now.tv_sec) * 1000000L + - (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; - - /* On some systems, the usleep argument must be < 1000000 */ - while (delta > 999999L) - { - usleep(999999); - delta -= 999999L; - } - if (delta > 0L) - { - usleep((useconds_t)delta); - } -#endif - - /* We don't support waking up prematurely (yet) */ - if (remaining) - { - remaining->tv_sec = 0; - remaining->tv_nsec = 0; - } - return 0; + /* Delta in microseconds */ + delta = (time_point->tv_sec - now.tv_sec) * 1000000L + (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; + + /* On some systems, the usleep argument must be < 1000000 */ + while (delta > 999999L) { + usleep(999999); + delta -= 999999L; + } + if (delta > 0L) { + usleep((useconds_t)delta); + } +#endif + + /* We don't support waking up prematurely (yet) */ + if (remaining) { + remaining->tv_sec = 0; + remaining->tv_nsec = 0; + } + return 0; } -void thrd_yield(void) -{ +void thrd_yield(void) { #if defined(_TTHREAD_WIN32_) - Sleep(0); + Sleep(0); #else - sched_yield(); + sched_yield(); #endif } -int tss_create(tss_t *key, tss_dtor_t dtor) -{ +int tss_create(tss_t *key, tss_dtor_t dtor) { #if defined(_TTHREAD_WIN32_) - /* FIXME: The destructor function is not supported yet... */ - if (dtor != NULL) - { - return thrd_error; - } - *key = TlsAlloc(); - if (*key == TLS_OUT_OF_INDEXES) - { - return thrd_error; - } + /* FIXME: The destructor function is not supported yet... */ + if (dtor != NULL) { + return thrd_error; + } + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) { + return thrd_error; + } #else - if (pthread_key_create(key, dtor) != 0) - { - return thrd_error; - } + if (pthread_key_create(key, dtor) != 0) { + return thrd_error; + } #endif - return thrd_success; + return thrd_success; } -void tss_delete(tss_t key) -{ +void tss_delete(tss_t key) { #if defined(_TTHREAD_WIN32_) - TlsFree(key); + TlsFree(key); #else - pthread_key_delete(key); + pthread_key_delete(key); #endif } -void *tss_get(tss_t key) -{ +void *tss_get(tss_t key) { #if defined(_TTHREAD_WIN32_) - return TlsGetValue(key); + return TlsGetValue(key); #else - return pthread_getspecific(key); + return pthread_getspecific(key); #endif } -int tss_set(tss_t key, void *val) -{ +int tss_set(tss_t key, void *val) { #if defined(_TTHREAD_WIN32_) - if (TlsSetValue(key, val) == 0) - { - return thrd_error; - } + if (TlsSetValue(key, val) == 0) { + return thrd_error; + } #else - if (pthread_setspecific(key, val) != 0) - { - return thrd_error; - } + if (pthread_setspecific(key, val) != 0) { + return thrd_error; + } #endif - return thrd_success; + return thrd_success; } #if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_) -int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) -{ +int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) { #if defined(_TTHREAD_WIN32_) - struct _timeb tb; - _ftime(&tb); - ts->tv_sec = (time_t)tb.time; - ts->tv_nsec = 1000000L * (long)tb.millitm; + struct _timeb tb; + _ftime(&tb); + ts->tv_sec = (time_t)tb.time; + ts->tv_nsec = 1000000L * (long)tb.millitm; #else - struct timeval tv; - gettimeofday(&tv, NULL); - ts->tv_sec = (time_t)tv.tv_sec; - ts->tv_nsec = 1000L * (long)tv.tv_usec; + struct timeval tv; + gettimeofday(&tv, NULL); + ts->tv_sec = (time_t)tv.tv_sec; + ts->tv_nsec = 1000L * (long)tv.tv_usec; #endif - return 0; + return 0; } #endif // _TTHREAD_EMULATE_CLOCK_GETTIME_ - diff --git a/src/deps/tinycthread.h b/src/deps/tinycthread.h index 42958c3..eaacfbe 100644 --- a/src/deps/tinycthread.h +++ b/src/deps/tinycthread.h @@ -25,52 +25,52 @@ freely, subject to the following restrictions: #define _TINYCTHREAD_H_ /** -* @file -* @mainpage TinyCThread API Reference -* -* @section intro_sec Introduction -* TinyCThread is a minimal, portable implementation of basic threading -* classes for C. -* -* They closely mimic the functionality and naming of the C11 standard, and -* should be easily replaceable with the corresponding standard variants. -* -* @section port_sec Portability -* The Win32 variant uses the native Win32 API for implementing the thread -* classes, while for other systems, the POSIX threads API (pthread) is used. -* -* @section misc_sec Miscellaneous -* The following special keywords are available: #_Thread_local. -* -* For more detailed information, browse the different sections of this -* documentation. A good place to start is: -* tinycthread.h. -*/ + * @file + * @mainpage TinyCThread API Reference + * + * @section intro_sec Introduction + * TinyCThread is a minimal, portable implementation of basic threading + * classes for C. + * + * They closely mimic the functionality and naming of the C11 standard, and + * should be easily replaceable with the corresponding standard variants. + * + * @section port_sec Portability + * The Win32 variant uses the native Win32 API for implementing the thread + * classes, while for other systems, the POSIX threads API (pthread) is used. + * + * @section misc_sec Miscellaneous + * The following special keywords are available: #_Thread_local. + * + * For more detailed information, browse the different sections of this + * documentation. A good place to start is: + * tinycthread.h. + */ /* Which platform are we on? */ #if !defined(_TTHREAD_PLATFORM_DEFINED_) - #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) - #define _TTHREAD_WIN32_ - #else - #define _TTHREAD_POSIX_ - #endif - #define _TTHREAD_PLATFORM_DEFINED_ +#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) +#define _TTHREAD_WIN32_ +#else +#define _TTHREAD_POSIX_ +#endif +#define _TTHREAD_PLATFORM_DEFINED_ #endif /* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ #if defined(_TTHREAD_POSIX_) - #undef _FEATURES_H - #if !defined(_GNU_SOURCE) - #define _GNU_SOURCE - #endif - #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) - #undef _POSIX_C_SOURCE - #define _POSIX_C_SOURCE 199309L - #endif - #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) - #undef _XOPEN_SOURCE - #define _XOPEN_SOURCE 500 - #endif +#undef _FEATURES_H +#if !defined(_GNU_SOURCE) +#define _GNU_SOURCE +#endif +#if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 199309L +#endif +#if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) +#undef _XOPEN_SOURCE +#define _XOPEN_SOURCE 500 +#endif #endif /* Generic includes */ @@ -78,18 +78,18 @@ freely, subject to the following restrictions: /* Platform specific includes */ #if defined(_TTHREAD_POSIX_) - #include - #include +#include +#include #elif defined(_TTHREAD_WIN32_) - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #define __UNDEF_LEAN_AND_MEAN - #endif - #include - #ifdef __UNDEF_LEAN_AND_MEAN - #undef WIN32_LEAN_AND_MEAN - #undef __UNDEF_LEAN_AND_MEAN - #endif +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#define __UNDEF_LEAN_AND_MEAN +#endif +#include +#ifdef __UNDEF_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#undef __UNDEF_LEAN_AND_MEAN +#endif #endif /* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, @@ -97,11 +97,11 @@ freely, subject to the following restrictions: the only other supported time specifier: CLOCK_REALTIME (and if that fails, we're probably emulating clock_gettime anyway, so anything goes). */ #ifndef TIME_UTC - #ifdef CLOCK_REALTIME - #define TIME_UTC CLOCK_REALTIME - #else - #define TIME_UTC 0 - #endif +#ifdef CLOCK_REALTIME +#define TIME_UTC CLOCK_REALTIME +#else +#define TIME_UTC 0 +#endif #endif /* Workaround for missing clock_gettime (most Windows compilers, afaik) */ @@ -110,8 +110,8 @@ freely, subject to the following restrictions: /* Emulate struct timespec */ #if defined(_TTHREAD_WIN32_) struct _ttherad_timespec { - time_t tv_sec; - long tv_nsec; + time_t tv_sec; + long tv_nsec; }; #define timespec _ttherad_timespec #endif @@ -124,11 +124,10 @@ typedef int _tthread_clockid_t; int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); #define clock_gettime _tthread_clock_gettime #ifndef CLOCK_REALTIME - #define CLOCK_REALTIME 0 +#define CLOCK_REALTIME 0 #endif #endif - /** TinyCThread version (major number). */ #define TINYCTHREAD_VERSION_MAJOR 1 /** TinyCThread version (minor number). */ @@ -137,42 +136,44 @@ int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); #define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) /** -* @def _Thread_local -* Thread local storage keyword. -* A variable that is declared with the @c _Thread_local keyword makes the -* value of the variable local to each thread (known as thread-local storage, -* or TLS). Example usage: -* @code -* // This variable is local to each thread. -* _Thread_local int variable; -* @endcode -* @note The @c _Thread_local keyword is a macro that maps to the corresponding -* compiler directive (e.g. @c __declspec(thread)). -* @note This directive is currently not supported on Mac OS X (it will give -* a compiler error), since compile-time TLS is not supported in the Mac OS X -* executable format. Also, some older versions of MinGW (before GCC 4.x) do -* not support this directive. -* @hideinitializer -*/ + * @def _Thread_local + * Thread local storage keyword. + * A variable that is declared with the @c _Thread_local keyword makes the + * value of the variable local to each thread (known as thread-local storage, + * or TLS). Example usage: + * @code + * // This variable is local to each thread. + * _Thread_local int variable; + * @endcode + * @note The @c _Thread_local keyword is a macro that maps to the corresponding + * compiler directive (e.g. @c __declspec(thread)). + * @note This directive is currently not supported on Mac OS X (it will give + * a compiler error), since compile-time TLS is not supported in the Mac OS X + * executable format. Also, some older versions of MinGW (before GCC 4.x) do + * not support this directive. + * @hideinitializer + */ /* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) - #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) - #define _Thread_local __thread - #else - #define _Thread_local __declspec(thread) - #endif +#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) +#define _Thread_local __thread +#else +#define _Thread_local __declspec(thread) +#endif #endif /* Macros */ #define TSS_DTOR_ITERATIONS 0 /* Function return values */ -#define thrd_error 0 /**< The requested operation failed */ -#define thrd_success 1 /**< The requested operation succeeded */ -#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ -#define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ -#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ +#define thrd_error 0 /**< The requested operation failed */ +#define thrd_success 1 /**< The requested operation succeeded */ +#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ +#define thrd_busy \ + 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use \ + */ +#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ /* Mutex types */ #define mtx_plain 1 @@ -183,261 +184,259 @@ int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); /* Mutex */ #if defined(_TTHREAD_WIN32_) typedef struct { - CRITICAL_SECTION mHandle; /* Critical section handle */ - int mAlreadyLocked; /* TRUE if the mutex is already locked */ - int mRecursive; /* TRUE if the mutex is recursive */ + CRITICAL_SECTION mHandle; /* Critical section handle */ + int mAlreadyLocked; /* TRUE if the mutex is already locked */ + int mRecursive; /* TRUE if the mutex is recursive */ } mtx_t; #else typedef pthread_mutex_t mtx_t; #endif /** Create a mutex object. -* @param mtx A mutex object. -* @param type Bit-mask that must have one of the following six values: -* @li @c mtx_plain for a simple non-recursive mutex -* @li @c mtx_timed for a non-recursive mutex that supports timeout -* @li @c mtx_try for a non-recursive mutex that supports test and return -* @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) -* @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) -* @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param mtx A mutex object. + * @param type Bit-mask that must have one of the following six values: + * @li @c mtx_plain for a simple non-recursive mutex + * @li @c mtx_timed for a non-recursive mutex that supports timeout + * @li @c mtx_try for a non-recursive mutex that supports test and return + * @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) + * @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) + * @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int mtx_init(mtx_t *mtx, int type); /** Release any resources used by the given mutex. -* @param mtx A mutex object. -*/ + * @param mtx A mutex object. + */ void mtx_destroy(mtx_t *mtx); /** Lock the given mutex. -* Blocks until the given mutex can be locked. If the mutex is non-recursive, and -* the calling thread already has a lock on the mutex, this call will block -* forever. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * Blocks until the given mutex can be locked. If the mutex is non-recursive, and + * the calling thread already has a lock on the mutex, this call will block + * forever. + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int mtx_lock(mtx_t *mtx); /** NOT YET IMPLEMENTED. -*/ + */ int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); /** Try to lock the given mutex. -* The specified mutex shall support either test and return or timeout. If the -* mutex is already locked, the function returns without blocking. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_busy if the resource -* requested is already in use, or @ref thrd_error if the request could not be -* honored. -*/ + * The specified mutex shall support either test and return or timeout. If the + * mutex is already locked, the function returns without blocking. + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_busy if the resource + * requested is already in use, or @ref thrd_error if the request could not be + * honored. + */ int mtx_trylock(mtx_t *mtx); /** Unlock the given mutex. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int mtx_unlock(mtx_t *mtx); /* Condition variable */ #if defined(_TTHREAD_WIN32_) typedef struct { - HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ - unsigned int mWaitersCount; /* Count of the number of waiters. */ - CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ + HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ + unsigned int mWaitersCount; /* Count of the number of waiters. */ + CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ } cnd_t; #else -typedef pthread_cond_t cnd_t; +typedef pthread_cond_t cnd_t; #endif /** Create a condition variable object. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param cond A condition variable object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_init(cnd_t *cond); /** Release any resources used by the given condition variable. -* @param cond A condition variable object. -*/ + * @param cond A condition variable object. + */ void cnd_destroy(cnd_t *cond); /** Signal a condition variable. -* Unblocks one of the threads that are blocked on the given condition variable -* at the time of the call. If no threads are blocked on the condition variable -* at the time of the call, the function does nothing and return success. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * Unblocks one of the threads that are blocked on the given condition variable + * at the time of the call. If no threads are blocked on the condition variable + * at the time of the call, the function does nothing and return success. + * @param cond A condition variable object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_signal(cnd_t *cond); /** Broadcast a condition variable. -* Unblocks all of the threads that are blocked on the given condition variable -* at the time of the call. If no threads are blocked on the condition variable -* at the time of the call, the function does nothing and return success. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * Unblocks all of the threads that are blocked on the given condition variable + * at the time of the call. If no threads are blocked on the condition variable + * at the time of the call, the function does nothing and return success. + * @param cond A condition variable object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_broadcast(cnd_t *cond); /** Wait for a condition variable to become signaled. -* The function atomically unlocks the given mutex and endeavors to block until -* the given condition variable is signaled by a call to cnd_signal or to -* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex -* before it returns. -* @param cond A condition variable object. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * The function atomically unlocks the given mutex and endeavors to block until + * the given condition variable is signaled by a call to cnd_signal or to + * cnd_broadcast. When the calling thread becomes unblocked it locks the mutex + * before it returns. + * @param cond A condition variable object. + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_wait(cnd_t *cond, mtx_t *mtx); /** Wait for a condition variable to become signaled. -* The function atomically unlocks the given mutex and endeavors to block until -* the given condition variable is signaled by a call to cnd_signal or to -* cnd_broadcast, or until after the specified time. When the calling thread -* becomes unblocked it locks the mutex before it returns. -* @param cond A condition variable object. -* @param mtx A mutex object. -* @param xt A point in time at which the request will time out (absolute time). -* @return @ref thrd_success upon success, or @ref thrd_timeout if the time -* specified in the call was reached without acquiring the requested resource, or -* @ref thrd_error if the request could not be honored. -*/ + * The function atomically unlocks the given mutex and endeavors to block until + * the given condition variable is signaled by a call to cnd_signal or to + * cnd_broadcast, or until after the specified time. When the calling thread + * becomes unblocked it locks the mutex before it returns. + * @param cond A condition variable object. + * @param mtx A mutex object. + * @param xt A point in time at which the request will time out (absolute time). + * @return @ref thrd_success upon success, or @ref thrd_timeout if the time + * specified in the call was reached without acquiring the requested resource, or + * @ref thrd_error if the request could not be honored. + */ int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); /* Thread */ #if defined(_TTHREAD_WIN32_) typedef HANDLE thrd_t; #else -typedef pthread_t thrd_t; +typedef pthread_t thrd_t; #endif /** Thread start function. -* Any thread that is started with the @ref thrd_create() function must be -* started through a function of this type. -* @param arg The thread argument (the @c arg argument of the corresponding -* @ref thrd_create() call). -* @return The thread return value, which can be obtained by another thread -* by using the @ref thrd_join() function. -*/ + * Any thread that is started with the @ref thrd_create() function must be + * started through a function of this type. + * @param arg The thread argument (the @c arg argument of the corresponding + * @ref thrd_create() call). + * @return The thread return value, which can be obtained by another thread + * by using the @ref thrd_join() function. + */ typedef int (*thrd_start_t)(void *arg); /** Create a new thread. -* @param thr Identifier of the newly created thread. -* @param func A function pointer to the function that will be executed in -* the new thread. -* @param arg An argument to the thread function. -* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could -* be allocated for the thread requested, or @ref thrd_error if the request -* could not be honored. -* @note A thread’s identifier may be reused for a different thread once the -* original thread has exited and either been detached or joined to another -* thread. -*/ + * @param thr Identifier of the newly created thread. + * @param func A function pointer to the function that will be executed in + * the new thread. + * @param arg An argument to the thread function. + * @return @ref thrd_success on success, or @ref thrd_nomem if no memory could + * be allocated for the thread requested, or @ref thrd_error if the request + * could not be honored. + * @note A thread’s identifier may be reused for a different thread once the + * original thread has exited and either been detached or joined to another + * thread. + */ int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); /** Identify the calling thread. -* @return The identifier of the calling thread. -*/ + * @return The identifier of the calling thread. + */ thrd_t thrd_current(void); /** NOT YET IMPLEMENTED. -*/ + */ int thrd_detach(thrd_t thr); /** Compare two thread identifiers. -* The function determines if two thread identifiers refer to the same thread. -* @return Zero if the two thread identifiers refer to different threads. -* Otherwise a nonzero value is returned. -*/ + * The function determines if two thread identifiers refer to the same thread. + * @return Zero if the two thread identifiers refer to different threads. + * Otherwise a nonzero value is returned. + */ int thrd_equal(thrd_t thr0, thrd_t thr1); /** Terminate execution of the calling thread. -* @param res Result code of the calling thread. -*/ + * @param res Result code of the calling thread. + */ void thrd_exit(int res); /** Wait for a thread to terminate. -* The function joins the given thread with the current thread by blocking -* until the other thread has terminated. -* @param thr The thread to join with. -* @param res If this pointer is not NULL, the function will store the result -* code of the given thread in the integer pointed to by @c res. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * The function joins the given thread with the current thread by blocking + * until the other thread has terminated. + * @param thr The thread to join with. + * @param res If this pointer is not NULL, the function will store the result + * code of the given thread in the integer pointed to by @c res. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int thrd_join(thrd_t thr, int *res); /** Put the calling thread to sleep. -* Suspend execution of the calling thread. -* @param time_point A point in time at which the thread will resume (absolute time). -* @param remaining If non-NULL, this parameter will hold the remaining time until -* time_point upon return. This will typically be zero, but if -* the thread was woken up by a signal that is not ignored before -* time_point was reached @c remaining will hold a positive -* time. -* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. -*/ + * Suspend execution of the calling thread. + * @param time_point A point in time at which the thread will resume (absolute time). + * @param remaining If non-NULL, this parameter will hold the remaining time until + * time_point upon return. This will typically be zero, but if + * the thread was woken up by a signal that is not ignored before + * time_point was reached @c remaining will hold a positive + * time. + * @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. + */ int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); /** Yield execution to another thread. -* Permit other threads to run, even if the current thread would ordinarily -* continue to run. -*/ + * Permit other threads to run, even if the current thread would ordinarily + * continue to run. + */ void thrd_yield(void); /* Thread local storage */ #if defined(_TTHREAD_WIN32_) typedef DWORD tss_t; #else -typedef pthread_key_t tss_t; +typedef pthread_key_t tss_t; #endif /** Destructor function for a thread-specific storage. -* @param val The value of the destructed thread-specific storage. -*/ + * @param val The value of the destructed thread-specific storage. + */ typedef void (*tss_dtor_t)(void *val); /** Create a thread-specific storage. -* @param key The unique key identifier that will be set if the function is -* successful. -* @param dtor Destructor function. This can be NULL. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -* @note The destructor function is not supported under Windows. If @c dtor is -* not NULL when calling this function under Windows, the function will fail -* and return @ref thrd_error. -*/ + * @param key The unique key identifier that will be set if the function is + * successful. + * @param dtor Destructor function. This can be NULL. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + * @note The destructor function is not supported under Windows. If @c dtor is + * not NULL when calling this function under Windows, the function will fail + * and return @ref thrd_error. + */ int tss_create(tss_t *key, tss_dtor_t dtor); /** Delete a thread-specific storage. -* The function releases any resources used by the given thread-specific -* storage. -* @param key The key that shall be deleted. -*/ + * The function releases any resources used by the given thread-specific + * storage. + * @param key The key that shall be deleted. + */ void tss_delete(tss_t key); /** Get the value for a thread-specific storage. -* @param key The thread-specific storage identifier. -* @return The value for the current thread held in the given thread-specific -* storage. -*/ + * @param key The thread-specific storage identifier. + * @return The value for the current thread held in the given thread-specific + * storage. + */ void *tss_get(tss_t key); /** Set the value for a thread-specific storage. -* @param key The thread-specific storage identifier. -* @param val The value of the thread-specific storage to set for the current -* thread. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param key The thread-specific storage identifier. + * @param val The value of the thread-specific storage to set for the current + * thread. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int tss_set(tss_t key, void *val); - #endif /* _TINYTHREAD_H_ */ - diff --git a/src/nsvg/nanosvg.h b/src/nsvg/nanosvg.h index 809bc87..5f6951b 100644 --- a/src/nsvg/nanosvg.h +++ b/src/nsvg/nanosvg.h @@ -27,7 +27,6 @@ * */ - #ifndef NANOSVG_H #define NANOSVG_H @@ -54,128 +53,107 @@ extern "C" { // // If you don't know or care about the units stuff, "px" and 96 should get you going. - /* Example Usage: - // Load SVG - NSVGimage* image; - image = nsvgParseFromFile("test.svg", "px", 96); - printf("size: %f x %f\n", image->width, image->height); - // Use... - for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { - for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { - for (int i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); - } - } - } - // Delete - nsvgDelete(image); + // Load SVG + NSVGimage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + printf("size: %f x %f\n", image->width, image->height); + // Use... + for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { + for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { + for (int i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); + } + } + } + // Delete + nsvgDelete(image); */ enum NSVGpaintType { - NSVG_PAINT_NONE = 0, - NSVG_PAINT_COLOR = 1, - NSVG_PAINT_LINEAR_GRADIENT = 2, - NSVG_PAINT_RADIAL_GRADIENT = 3 + NSVG_PAINT_NONE = 0, + NSVG_PAINT_COLOR = 1, + NSVG_PAINT_LINEAR_GRADIENT = 2, + NSVG_PAINT_RADIAL_GRADIENT = 3 }; -enum NSVGspreadType { - NSVG_SPREAD_PAD = 0, - NSVG_SPREAD_REFLECT = 1, - NSVG_SPREAD_REPEAT = 2 -}; +enum NSVGspreadType { NSVG_SPREAD_PAD = 0, NSVG_SPREAD_REFLECT = 1, NSVG_SPREAD_REPEAT = 2 }; -enum NSVGlineJoin { - NSVG_JOIN_MITER = 0, - NSVG_JOIN_ROUND = 1, - NSVG_JOIN_BEVEL = 2 -}; +enum NSVGlineJoin { NSVG_JOIN_MITER = 0, NSVG_JOIN_ROUND = 1, NSVG_JOIN_BEVEL = 2 }; -enum NSVGlineCap { - NSVG_CAP_BUTT = 0, - NSVG_CAP_ROUND = 1, - NSVG_CAP_SQUARE = 2 -}; +enum NSVGlineCap { NSVG_CAP_BUTT = 0, NSVG_CAP_ROUND = 1, NSVG_CAP_SQUARE = 2 }; -enum NSVGfillRule { - NSVG_FILLRULE_NONZERO = 0, - NSVG_FILLRULE_EVENODD = 1 -}; +enum NSVGfillRule { NSVG_FILLRULE_NONZERO = 0, NSVG_FILLRULE_EVENODD = 1 }; -enum NSVGflags { - NSVG_FLAGS_VISIBLE = 0x01 -}; +enum NSVGflags { NSVG_FLAGS_VISIBLE = 0x01 }; typedef struct NSVGgradientStop { - unsigned int color; - float offset; + unsigned int color; + float offset; } NSVGgradientStop; typedef struct NSVGgradient { - float xform[6]; - char spread; - float fx, fy; - int nstops; - NSVGgradientStop stops[1]; + float xform[6]; + char spread; + float fx, fy; + int nstops; + NSVGgradientStop stops[1]; } NSVGgradient; typedef struct NSVGpaint { - char type; - union { - unsigned int color; - NSVGgradient* gradient; - }; + char type; + union { + unsigned int color; + NSVGgradient *gradient; + }; } NSVGpaint; -typedef struct NSVGpath -{ - float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... - int npts; // Total number of bezier points. - char closed; // Flag indicating if shapes should be treated as closed. - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - struct NSVGpath* next; // Pointer to next path, or NULL if last element. +typedef struct NSVGpath { + float *pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... + int npts; // Total number of bezier points. + char closed; // Flag indicating if shapes should be treated as closed. + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + struct NSVGpath *next; // Pointer to next path, or NULL if last element. } NSVGpath; -typedef struct NSVGshape -{ - char id[64]; // Optional 'id' attr of the shape or its group - NSVGpaint fill; // Fill paint - NSVGpaint stroke; // Stroke paint - float opacity; // Opacity of the shape. - float strokeWidth; // Stroke width (scaled). - float strokeDashOffset; // Stroke dash offset (scaled). - float strokeDashArray[8]; // Stroke dash array (scaled). - char strokeDashCount; // Number of dash values in dash array. - char strokeLineJoin; // Stroke join type. - char strokeLineCap; // Stroke cap type. - float miterLimit; // Miter limit - char fillRule; // Fill rule, see NSVGfillRule. - unsigned char flags; // Logical or of NSVG_FLAGS_* flags - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - NSVGpath* paths; // Linked list of paths in the image. - struct NSVGshape* next; // Pointer to next shape, or NULL if last element. +typedef struct NSVGshape { + char id[64]; // Optional 'id' attr of the shape or its group + NSVGpaint fill; // Fill paint + NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. + float strokeWidth; // Stroke width (scaled). + float strokeDashOffset; // Stroke dash offset (scaled). + float strokeDashArray[8]; // Stroke dash array (scaled). + char strokeDashCount; // Number of dash values in dash array. + char strokeLineJoin; // Stroke join type. + char strokeLineCap; // Stroke cap type. + float miterLimit; // Miter limit + char fillRule; // Fill rule, see NSVGfillRule. + unsigned char flags; // Logical or of NSVG_FLAGS_* flags + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + NSVGpath *paths; // Linked list of paths in the image. + struct NSVGshape *next; // Pointer to next shape, or NULL if last element. } NSVGshape; -typedef struct NSVGimage -{ - float width; // Width of the image. - float height; // Height of the image. - NSVGshape* shapes; // Linked list of shapes in the image. +typedef struct NSVGimage { + float width; // Width of the image. + float height; // Height of the image. + NSVGshape *shapes; // Linked list of shapes in the image. } NSVGimage; // Parses SVG file from a file, returns SVG image as paths. -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); +NSVGimage *nsvgParseFromFile(const char *filename, const char *units, float dpi); // Parses SVG file from a null terminated string, returns SVG image as paths. // Important note: changes the string. -NSVGimage* nsvgParse(char* input, const char* units, float dpi); +NSVGimage *nsvgParse(char *input, const char *units, float dpi); // Duplicates a path. -NSVGpath* nsvgDuplicatePath(NSVGpath* p); +NSVGpath *nsvgDuplicatePath(NSVGpath *p); // Deletes an image. -void nsvgDelete(NSVGimage* image); +void nsvgDelete(NSVGimage *image); #ifndef NANOSVG_CPLUSPLUS #ifdef __cplusplus @@ -191,2817 +169,2827 @@ void nsvgDelete(NSVGimage* image); #include #include -#define NSVG_PI (3.14159265358979323846264338327f) -#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. +#define NSVG_PI (3.14159265358979323846264338327f) +#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. -#define NSVG_ALIGN_MIN 0 -#define NSVG_ALIGN_MID 1 -#define NSVG_ALIGN_MAX 2 -#define NSVG_ALIGN_NONE 0 -#define NSVG_ALIGN_MEET 1 +#define NSVG_ALIGN_MIN 0 +#define NSVG_ALIGN_MID 1 +#define NSVG_ALIGN_MAX 2 +#define NSVG_ALIGN_NONE 0 +#define NSVG_ALIGN_MEET 1 #define NSVG_ALIGN_SLICE 2 -#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) +#define NSVG_NOTUSED(v) \ + do { \ + (void)(1 ? (void)0 : ((void)(v))); \ + } while (0) #define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) #ifdef _MSC_VER - #pragma warning (disable: 4996) // Switch off security warnings - #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings - #ifdef __cplusplus - #define NSVG_INLINE inline - #else - #define NSVG_INLINE - #endif +#pragma warning(disable : 4996) // Switch off security warnings +#pragma warning(disable : 4100) // Switch off unreferenced formal parameter warnings +#ifdef __cplusplus +#define NSVG_INLINE inline +#else +#define NSVG_INLINE +#endif #else - #define NSVG_INLINE inline +#define NSVG_INLINE inline #endif #ifndef NANOSVG_DEBUG #define NANOSVG_DEBUG(...) -//#define NANOSVG_DEBUG printf +// #define NANOSVG_DEBUG printf #endif -static int nsvg__isspace(char c) -{ - return strchr(" \t\n\v\f\r", c) != 0; -} +static int nsvg__isspace(char c) { return strchr(" \t\n\v\f\r", c) != 0; } -static int nsvg__isdigit(char c) -{ - return c >= '0' && c <= '9'; -} +static int nsvg__isdigit(char c) { return c >= '0' && c <= '9'; } -static int nsvg__isnum(char c) -{ - return strchr("0123456789+-.eE", c) != 0; -} +static int nsvg__isnum(char c) { return strchr("0123456789+-.eE", c) != 0; } static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } - // Simple XML parser -#define NSVG_XML_TAG 1 -#define NSVG_XML_CONTENT 2 +#define NSVG_XML_TAG 1 +#define NSVG_XML_CONTENT 2 #define NSVG_XML_MAX_ATTRIBS 256 -static void nsvg__parseContent(char* s, - void (*contentCb)(void* ud, const char* s), - void* ud) -{ - // Trim start white spaces - while (nsvg__isspace(*s)) s++; - if (!*s) return; - - if (contentCb) - (*contentCb)(ud, s); -} - -static void nsvg__parseElement(char* s, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void* ud) -{ - const char* attr[NSVG_XML_MAX_ATTRIBS]; - int nattr = 0; - char* name; - int start = 0; - int end = 0; - char quote; - - // Skip white space after the '<' - while (nsvg__isspace(*s)) s++; - - // Check if the tag is end tag - if (*s == '/') { - s++; - end = 1; - } else { - start = 1; - } - - // Skip comments, data and preprocessor stuff. - if (!*s || *s == '?' || *s == '!') - return; - - // Get tag name - name = s; - while (*s && !nsvg__isspace(*s)) s++; - if (*s) { *s++ = '\0'; } - - // Get attribs - while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { - char* name = NULL; - char* value = NULL; - - // Skip white space before the attrib name - while (nsvg__isspace(*s)) s++; - if (!*s) break; - if (*s == '/') { - end = 1; - break; - } - name = s; - // Find end of the attrib name. - while (*s && !nsvg__isspace(*s) && *s != '=') s++; - if (*s) { *s++ = '\0'; } - // Skip until the beginning of the value. - while (*s && *s != '\"' && *s != '\'') s++; - if (!*s) break; - quote = *s; - s++; - // Store value and find the end of it. - value = s; - while (*s && *s != quote) s++; - if (*s) { *s++ = '\0'; } - - // Store only well formed attributes - if (name && value) { - attr[nattr++] = name; - attr[nattr++] = value; - } - } - - // List terminator - attr[nattr++] = 0; - attr[nattr++] = 0; - - // Call callbacks. - if (start && startelCb) - (*startelCb)(ud, name, attr); - if (end && endelCb) - (*endelCb)(ud, name); -} - -int nsvg__parseXML(char* input, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void (*contentCb)(void* ud, const char* s), - void* ud) -{ - char* s = input; - char* mark = s; - int state = NSVG_XML_CONTENT; - while (*s) { - if (*s == '<' && state == NSVG_XML_CONTENT) { - // Start of a tag - *s++ = '\0'; - nsvg__parseContent(mark, contentCb, ud); - mark = s; - state = NSVG_XML_TAG; - } else if (*s == '>' && state == NSVG_XML_TAG) { - // Start of a content or new tag. - *s++ = '\0'; - nsvg__parseElement(mark, startelCb, endelCb, ud); - mark = s; - state = NSVG_XML_CONTENT; - } else { - s++; - } - } - - return 1; +static void nsvg__parseContent(char *s, void (*contentCb)(void *ud, const char *s), void *ud) { + // Trim start white spaces + while (nsvg__isspace(*s)) + s++; + if (!*s) + return; + + if (contentCb) + (*contentCb)(ud, s); +} + +static void nsvg__parseElement(char *s, void (*startelCb)(void *ud, const char *el, const char **attr), + void (*endelCb)(void *ud, const char *el), void *ud) { + const char *attr[NSVG_XML_MAX_ATTRIBS]; + int nattr = 0; + char *name; + int start = 0; + int end = 0; + char quote; + + // Skip white space after the '<' + while (nsvg__isspace(*s)) + s++; + + // Check if the tag is end tag + if (*s == '/') { + s++; + end = 1; + } else { + start = 1; + } + + // Skip comments, data and preprocessor stuff. + if (!*s || *s == '?' || *s == '!') + return; + + // Get tag name + name = s; + while (*s && !nsvg__isspace(*s)) + s++; + if (*s) { + *s++ = '\0'; + } + + // Get attribs + while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS - 3) { + char *name = NULL; + char *value = NULL; + + // Skip white space before the attrib name + while (nsvg__isspace(*s)) + s++; + if (!*s) + break; + if (*s == '/') { + end = 1; + break; + } + name = s; + // Find end of the attrib name. + while (*s && !nsvg__isspace(*s) && *s != '=') + s++; + if (*s) { + *s++ = '\0'; + } + // Skip until the beginning of the value. + while (*s && *s != '\"' && *s != '\'') + s++; + if (!*s) + break; + quote = *s; + s++; + // Store value and find the end of it. + value = s; + while (*s && *s != quote) + s++; + if (*s) { + *s++ = '\0'; + } + + // Store only well formed attributes + if (name && value) { + attr[nattr++] = name; + attr[nattr++] = value; + } + } + + // List terminator + attr[nattr++] = 0; + attr[nattr++] = 0; + + // Call callbacks. + if (start && startelCb) + (*startelCb)(ud, name, attr); + if (end && endelCb) + (*endelCb)(ud, name); +} + +int nsvg__parseXML(char *input, void (*startelCb)(void *ud, const char *el, const char **attr), + void (*endelCb)(void *ud, const char *el), void (*contentCb)(void *ud, const char *s), void *ud) { + char *s = input; + char *mark = s; + int state = NSVG_XML_CONTENT; + while (*s) { + if (*s == '<' && state == NSVG_XML_CONTENT) { + // Start of a tag + *s++ = '\0'; + nsvg__parseContent(mark, contentCb, ud); + mark = s; + state = NSVG_XML_TAG; + } else if (*s == '>' && state == NSVG_XML_TAG) { + // Start of a content or new tag. + *s++ = '\0'; + nsvg__parseElement(mark, startelCb, endelCb, ud); + mark = s; + state = NSVG_XML_CONTENT; + } else { + s++; + } + } + + return 1; } - /* Simple SVG parser. */ #define NSVG_MAX_ATTR 128 -enum NSVGgradientUnits { - NSVG_USER_SPACE = 0, - NSVG_OBJECT_SPACE = 1 -}; +enum NSVGgradientUnits { NSVG_USER_SPACE = 0, NSVG_OBJECT_SPACE = 1 }; #define NSVG_MAX_DASHES 8 enum NSVGunits { - NSVG_UNITS_USER, - NSVG_UNITS_PX, - NSVG_UNITS_PT, - NSVG_UNITS_PC, - NSVG_UNITS_MM, - NSVG_UNITS_CM, - NSVG_UNITS_IN, - NSVG_UNITS_PERCENT, - NSVG_UNITS_EM, - NSVG_UNITS_EX + NSVG_UNITS_USER, + NSVG_UNITS_PX, + NSVG_UNITS_PT, + NSVG_UNITS_PC, + NSVG_UNITS_MM, + NSVG_UNITS_CM, + NSVG_UNITS_IN, + NSVG_UNITS_PERCENT, + NSVG_UNITS_EM, + NSVG_UNITS_EX }; typedef struct NSVGcoordinate { - float value; - int units; + float value; + int units; } NSVGcoordinate; typedef struct NSVGlinearData { - NSVGcoordinate x1, y1, x2, y2; + NSVGcoordinate x1, y1, x2, y2; } NSVGlinearData; typedef struct NSVGradialData { - NSVGcoordinate cx, cy, r, fx, fy; + NSVGcoordinate cx, cy, r, fx, fy; } NSVGradialData; -typedef struct NSVGgradientData -{ - char id[64]; - char ref[64]; - char type; - union { - NSVGlinearData linear; - NSVGradialData radial; - }; - char spread; - char units; - float xform[6]; - int nstops; - NSVGgradientStop* stops; - struct NSVGgradientData* next; +typedef struct NSVGgradientData { + char id[64]; + char ref[64]; + char type; + union { + NSVGlinearData linear; + NSVGradialData radial; + }; + char spread; + char units; + float xform[6]; + int nstops; + NSVGgradientStop *stops; + struct NSVGgradientData *next; } NSVGgradientData; -typedef struct NSVGattrib -{ - char id[64]; - float xform[6]; - unsigned int fillColor; - unsigned int strokeColor; - float opacity; - float fillOpacity; - float strokeOpacity; - char fillGradient[64]; - char strokeGradient[64]; - float strokeWidth; - float strokeDashOffset; - float strokeDashArray[NSVG_MAX_DASHES]; - int strokeDashCount; - char strokeLineJoin; - char strokeLineCap; - float miterLimit; - char fillRule; - float fontSize; - unsigned int stopColor; - float stopOpacity; - float stopOffset; - char hasFill; - char hasStroke; - char visible; +typedef struct NSVGattrib { + char id[64]; + float xform[6]; + unsigned int fillColor; + unsigned int strokeColor; + float opacity; + float fillOpacity; + float strokeOpacity; + char fillGradient[64]; + char strokeGradient[64]; + float strokeWidth; + float strokeDashOffset; + float strokeDashArray[NSVG_MAX_DASHES]; + int strokeDashCount; + char strokeLineJoin; + char strokeLineCap; + float miterLimit; + char fillRule; + float fontSize; + unsigned int stopColor; + float stopOpacity; + float stopOffset; + char hasFill; + char hasStroke; + char visible; } NSVGattrib; -typedef struct NSVGparser -{ - NSVGattrib attr[NSVG_MAX_ATTR]; - int attrHead; - float* pts; - int npts; - int cpts; - NSVGpath* plist; - NSVGimage* image; - NSVGgradientData* gradients; - NSVGshape* shapesTail; - float viewMinx, viewMiny, viewWidth, viewHeight; - int alignX, alignY, alignType; - float dpi; - char pathFlag; - char defsFlag; +typedef struct NSVGparser { + NSVGattrib attr[NSVG_MAX_ATTR]; + int attrHead; + float *pts; + int npts; + int cpts; + NSVGpath *plist; + NSVGimage *image; + NSVGgradientData *gradients; + NSVGshape *shapesTail; + float viewMinx, viewMiny, viewWidth, viewHeight; + int alignX, alignY, alignType; + float dpi; + char pathFlag; + char defsFlag; } NSVGparser; -static void nsvg__xformIdentity(float* t) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetTranslation(float* t, float tx, float ty) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = tx; t[5] = ty; -} - -static void nsvg__xformSetScale(float* t, float sx, float sy) -{ - t[0] = sx; t[1] = 0.0f; - t[2] = 0.0f; t[3] = sy; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetSkewX(float* t, float a) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = tanf(a); t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetSkewY(float* t, float a) -{ - t[0] = 1.0f; t[1] = tanf(a); - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetRotation(float* t, float a) -{ - float cs = cosf(a), sn = sinf(a); - t[0] = cs; t[1] = sn; - t[2] = -sn; t[3] = cs; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformMultiply(float* t, float* s) -{ - float t0 = t[0] * s[0] + t[1] * s[2]; - float t2 = t[2] * s[0] + t[3] * s[2]; - float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; - t[1] = t[0] * s[1] + t[1] * s[3]; - t[3] = t[2] * s[1] + t[3] * s[3]; - t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; - t[0] = t0; - t[2] = t2; - t[4] = t4; -} - -static void nsvg__xformInverse(float* inv, float* t) -{ - double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; - if (det > -1e-6 && det < 1e-6) { - nsvg__xformIdentity(t); - return; - } - invdet = 1.0 / det; - inv[0] = (float)(t[3] * invdet); - inv[2] = (float)(-t[2] * invdet); - inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); - inv[1] = (float)(-t[1] * invdet); - inv[3] = (float)(t[0] * invdet); - inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); -} - -static void nsvg__xformPremultiply(float* t, float* s) -{ - float s2[6]; - memcpy(s2, s, sizeof(float)*6); - nsvg__xformMultiply(s2, t); - memcpy(t, s2, sizeof(float)*6); -} - -static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) -{ - *dx = x*t[0] + y*t[2] + t[4]; - *dy = x*t[1] + y*t[3] + t[5]; -} - -static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) -{ - *dx = x*t[0] + y*t[2]; - *dy = x*t[1] + y*t[3]; +static void nsvg__xformIdentity(float *t) { + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetTranslation(float *t, float tx, float ty) { + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = tx; + t[5] = ty; +} + +static void nsvg__xformSetScale(float *t, float sx, float sy) { + t[0] = sx; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = sy; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetSkewX(float *t, float a) { + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = tanf(a); + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetSkewY(float *t, float a) { + t[0] = 1.0f; + t[1] = tanf(a); + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetRotation(float *t, float a) { + float cs = cosf(a), sn = sinf(a); + t[0] = cs; + t[1] = sn; + t[2] = -sn; + t[3] = cs; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformMultiply(float *t, float *s) { + float t0 = t[0] * s[0] + t[1] * s[2]; + float t2 = t[2] * s[0] + t[3] * s[2]; + float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; + t[1] = t[0] * s[1] + t[1] * s[3]; + t[3] = t[2] * s[1] + t[3] * s[3]; + t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; + t[0] = t0; + t[2] = t2; + t[4] = t4; +} + +static void nsvg__xformInverse(float *inv, float *t) { + double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; + if (det > -1e-6 && det < 1e-6) { + nsvg__xformIdentity(t); + return; + } + invdet = 1.0 / det; + inv[0] = (float)(t[3] * invdet); + inv[2] = (float)(-t[2] * invdet); + inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); + inv[1] = (float)(-t[1] * invdet); + inv[3] = (float)(t[0] * invdet); + inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); +} + +static void nsvg__xformPremultiply(float *t, float *s) { + float s2[6]; + memcpy(s2, s, sizeof(float) * 6); + nsvg__xformMultiply(s2, t); + memcpy(t, s2, sizeof(float) * 6); +} + +static void nsvg__xformPoint(float *dx, float *dy, float x, float y, float *t) { + *dx = x * t[0] + y * t[2] + t[4]; + *dy = x * t[1] + y * t[3] + t[5]; +} + +static void nsvg__xformVec(float *dx, float *dy, float x, float y, float *t) { + *dx = x * t[0] + y * t[2]; + *dy = x * t[1] + y * t[3]; } #define NSVG_EPSILON (1e-12) -static int nsvg__ptInBounds(float* pt, float* bounds) -{ - return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; -} - - -static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) -{ - double it = 1.0-t; - return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; -} - -static void nsvg__curveBounds(float* bounds, float* curve) -{ - int i, j, count; - double roots[2], a, b, c, b2ac, t, v; - float* v0 = &curve[0]; - float* v1 = &curve[2]; - float* v2 = &curve[4]; - float* v3 = &curve[6]; - - // Start the bounding box by end points - bounds[0] = nsvg__minf(v0[0], v3[0]); - bounds[1] = nsvg__minf(v0[1], v3[1]); - bounds[2] = nsvg__maxf(v0[0], v3[0]); - bounds[3] = nsvg__maxf(v0[1], v3[1]); - - // Bezier curve fits inside the convex hull of it's control points. - // If control points are inside the bounds, we're done. - if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) - return; - - // Add bezier curve inflection points in X and Y. - for (i = 0; i < 2; i++) { - a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; - b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; - c = 3.0 * v1[i] - 3.0 * v0[i]; - count = 0; - if (fabs(a) < NSVG_EPSILON) { - if (fabs(b) > NSVG_EPSILON) { - t = -c / b; - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - } - } else { - b2ac = b*b - 4.0*c*a; - if (b2ac > NSVG_EPSILON) { - t = (-b + sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - t = (-b - sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - } - } - for (j = 0; j < count; j++) { - v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); - bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); - bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); - } - } -} - -static NSVGparser* nsvg__createParser() -{ - NSVGparser* p; - p = (NSVGparser*)malloc(sizeof(NSVGparser)); - if (p == NULL) goto error; - memset(p, 0, sizeof(NSVGparser)); - - p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); - if (p->image == NULL) goto error; - memset(p->image, 0, sizeof(NSVGimage)); - - // Init style - nsvg__xformIdentity(p->attr[0].xform); - memset(p->attr[0].id, 0, sizeof p->attr[0].id); - p->attr[0].fillColor = NSVG_RGB(0,0,0); - p->attr[0].strokeColor = NSVG_RGB(0,0,0); - p->attr[0].opacity = 1; - p->attr[0].fillOpacity = 1; - p->attr[0].strokeOpacity = 1; - p->attr[0].stopOpacity = 1; - p->attr[0].strokeWidth = 1; - p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; - p->attr[0].strokeLineCap = NSVG_CAP_BUTT; - p->attr[0].miterLimit = 4; - p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; - p->attr[0].hasFill = 1; - p->attr[0].visible = 1; - - return p; +static int nsvg__ptInBounds(float *pt, float *bounds) { + return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; +} + +static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) { + double it = 1.0 - t; + return it * it * it * p0 + 3.0 * it * it * t * p1 + 3.0 * it * t * t * p2 + t * t * t * p3; +} + +static void nsvg__curveBounds(float *bounds, float *curve) { + int i, j, count; + double roots[2], a, b, c, b2ac, t, v; + float *v0 = &curve[0]; + float *v1 = &curve[2]; + float *v2 = &curve[4]; + float *v3 = &curve[6]; + + // Start the bounding box by end points + bounds[0] = nsvg__minf(v0[0], v3[0]); + bounds[1] = nsvg__minf(v0[1], v3[1]); + bounds[2] = nsvg__maxf(v0[0], v3[0]); + bounds[3] = nsvg__maxf(v0[1], v3[1]); + + // Bezier curve fits inside the convex hull of it's control points. + // If control points are inside the bounds, we're done. + if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) + return; + + // Add bezier curve inflection points in X and Y. + for (i = 0; i < 2; i++) { + a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; + b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; + c = 3.0 * v1[i] - 3.0 * v0[i]; + count = 0; + if (fabs(a) < NSVG_EPSILON) { + if (fabs(b) > NSVG_EPSILON) { + t = -c / b; + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + } + } else { + b2ac = b * b - 4.0 * c * a; + if (b2ac > NSVG_EPSILON) { + t = (-b + sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + t = (-b - sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + } + } + for (j = 0; j < count; j++) { + v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); + bounds[0 + i] = nsvg__minf(bounds[0 + i], (float)v); + bounds[2 + i] = nsvg__maxf(bounds[2 + i], (float)v); + } + } +} + +static NSVGparser *nsvg__createParser() { + NSVGparser *p; + p = (NSVGparser *)malloc(sizeof(NSVGparser)); + if (p == NULL) + goto error; + memset(p, 0, sizeof(NSVGparser)); + + p->image = (NSVGimage *)malloc(sizeof(NSVGimage)); + if (p->image == NULL) + goto error; + memset(p->image, 0, sizeof(NSVGimage)); + + // Init style + nsvg__xformIdentity(p->attr[0].xform); + memset(p->attr[0].id, 0, sizeof p->attr[0].id); + p->attr[0].fillColor = NSVG_RGB(0, 0, 0); + p->attr[0].strokeColor = NSVG_RGB(0, 0, 0); + p->attr[0].opacity = 1; + p->attr[0].fillOpacity = 1; + p->attr[0].strokeOpacity = 1; + p->attr[0].stopOpacity = 1; + p->attr[0].strokeWidth = 1; + p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; + p->attr[0].strokeLineCap = NSVG_CAP_BUTT; + p->attr[0].miterLimit = 4; + p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; + p->attr[0].hasFill = 1; + p->attr[0].visible = 1; + + return p; error: - if (p) { - if (p->image) free(p->image); - free(p); - } - return NULL; -} - -static void nsvg__deletePaths(NSVGpath* path) -{ - while (path) { - NSVGpath *next = path->next; - if (path->pts != NULL) - free(path->pts); - free(path); - path = next; - } -} - -static void nsvg__deletePaint(NSVGpaint* paint) -{ - if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) - free(paint->gradient); + if (p) { + if (p->image) + free(p->image); + free(p); + } + return NULL; } - -static void nsvg__deleteGradientData(NSVGgradientData* grad) -{ - NSVGgradientData* next; - while (grad != NULL) { - next = grad->next; - free(grad->stops); - free(grad); - grad = next; - } + +static void nsvg__deletePaths(NSVGpath *path) { + while (path) { + NSVGpath *next = path->next; + if (path->pts != NULL) + free(path->pts); + free(path); + path = next; + } } -static void nsvg__deleteParser(NSVGparser* p) -{ - if (p != NULL) { - nsvg__deletePaths(p->plist); - nsvg__deleteGradientData(p->gradients); - nsvgDelete(p->image); - free(p->pts); - free(p); - } +static void nsvg__deletePaint(NSVGpaint *paint) { + if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) + free(paint->gradient); } -static void nsvg__resetPath(NSVGparser* p) -{ - p->npts = 0; -} - -static void nsvg__addPoint(NSVGparser* p, float x, float y) -{ - if (p->npts+1 > p->cpts) { - p->cpts = p->cpts ? p->cpts*2 : 8; - p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); - if (!p->pts) return; - } - p->pts[p->npts*2+0] = x; - p->pts[p->npts*2+1] = y; - p->npts++; -} - -static void nsvg__moveTo(NSVGparser* p, float x, float y) -{ - if (p->npts > 0) { - p->pts[(p->npts-1)*2+0] = x; - p->pts[(p->npts-1)*2+1] = y; - } else { - nsvg__addPoint(p, x, y); - } -} - -static void nsvg__lineTo(NSVGparser* p, float x, float y) -{ - float px,py, dx,dy; - if (p->npts > 0) { - px = p->pts[(p->npts-1)*2+0]; - py = p->pts[(p->npts-1)*2+1]; - dx = x - px; - dy = y - py; - nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); - nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); - nsvg__addPoint(p, x, y); - } -} - -static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) -{ - nsvg__addPoint(p, cpx1, cpy1); - nsvg__addPoint(p, cpx2, cpy2); - nsvg__addPoint(p, x, y); -} - -static NSVGattrib* nsvg__getAttr(NSVGparser* p) -{ - return &p->attr[p->attrHead]; -} - -static void nsvg__pushAttr(NSVGparser* p) -{ - if (p->attrHead < NSVG_MAX_ATTR-1) { - p->attrHead++; - memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); - } -} - -static void nsvg__popAttr(NSVGparser* p) -{ - if (p->attrHead > 0) - p->attrHead--; -} - -static float nsvg__actualOrigX(NSVGparser* p) -{ - return p->viewMinx; -} - -static float nsvg__actualOrigY(NSVGparser* p) -{ - return p->viewMiny; -} - -static float nsvg__actualWidth(NSVGparser* p) -{ - return p->viewWidth; -} - -static float nsvg__actualHeight(NSVGparser* p) -{ - return p->viewHeight; -} - -static float nsvg__actualLength(NSVGparser* p) -{ - float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); - return sqrtf(w*w + h*h) / sqrtf(2.0f); -} - -static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) -{ - NSVGattrib* attr = nsvg__getAttr(p); - switch (c.units) { - case NSVG_UNITS_USER: return c.value; - case NSVG_UNITS_PX: return c.value; - case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; - case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; - case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; - case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; - case NSVG_UNITS_IN: return c.value * p->dpi; - case NSVG_UNITS_EM: return c.value * attr->fontSize; - case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. - case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; - default: return c.value; - } - return c.value; -} - -static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) -{ - NSVGgradientData* grad = p->gradients; - while (grad) { - if (strcmp(grad->id, id) == 0) - return grad; - grad = grad->next; - } - return NULL; -} - -static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType) -{ - NSVGattrib* attr = nsvg__getAttr(p); - NSVGgradientData* data = NULL; - NSVGgradientData* ref = NULL; - NSVGgradientStop* stops = NULL; - NSVGgradient* grad; - float ox, oy, sw, sh, sl; - int nstops = 0; - - data = nsvg__findGradientData(p, id); - if (data == NULL) return NULL; - - // TODO: use ref to fill in all unset values too. - ref = data; - while (ref != NULL) { - if (stops == NULL && ref->stops != NULL) { - stops = ref->stops; - nstops = ref->nstops; - break; - } - ref = nsvg__findGradientData(p, ref->ref); - } - if (stops == NULL) return NULL; - - grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); - if (grad == NULL) return NULL; - - // The shape width and height. - if (data->units == NSVG_OBJECT_SPACE) { - ox = localBounds[0]; - oy = localBounds[1]; - sw = localBounds[2] - localBounds[0]; - sh = localBounds[3] - localBounds[1]; - } else { - ox = nsvg__actualOrigX(p); - oy = nsvg__actualOrigY(p); - sw = nsvg__actualWidth(p); - sh = nsvg__actualHeight(p); - } - sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); - - if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { - float x1, y1, x2, y2, dx, dy; - x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); - y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); - x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); - y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); - // Calculate transform aligned to the line - dx = x2 - x1; - dy = y2 - y1; - grad->xform[0] = dy; grad->xform[1] = -dx; - grad->xform[2] = dx; grad->xform[3] = dy; - grad->xform[4] = x1; grad->xform[5] = y1; - } else { - float cx, cy, fx, fy, r; - cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); - cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); - fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); - fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); - r = nsvg__convertToPixels(p, data->radial.r, 0, sl); - // Calculate transform aligned to the circle - grad->xform[0] = r; grad->xform[1] = 0; - grad->xform[2] = 0; grad->xform[3] = r; - grad->xform[4] = cx; grad->xform[5] = cy; - grad->fx = fx / r; - grad->fy = fy / r; - } - - nsvg__xformMultiply(grad->xform, data->xform); - nsvg__xformMultiply(grad->xform, attr->xform); - - grad->spread = data->spread; - memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); - grad->nstops = nstops; - - *paintType = data->type; - - return grad; -} - -static float nsvg__getAverageScale(float* t) -{ - float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); - float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); - return (sx + sy) * 0.5f; -} - -static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) -{ - NSVGpath* path; - float curve[4*2], curveBounds[4]; - int i, first = 1; - for (path = shape->paths; path != NULL; path = path->next) { - nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); - for (i = 0; i < path->npts-1; i += 3) { - nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); - nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); - nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); - nsvg__curveBounds(curveBounds, curve); - if (first) { - bounds[0] = curveBounds[0]; - bounds[1] = curveBounds[1]; - bounds[2] = curveBounds[2]; - bounds[3] = curveBounds[3]; - first = 0; - } else { - bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); - bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); - bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); - bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); - } - curve[0] = curve[6]; - curve[1] = curve[7]; - } - } -} - -static void nsvg__addShape(NSVGparser* p) -{ - NSVGattrib* attr = nsvg__getAttr(p); - float scale = 1.0f; - NSVGshape* shape; - NSVGpath* path; - int i; - - if (p->plist == NULL) - return; - - shape = (NSVGshape*)malloc(sizeof(NSVGshape)); - if (shape == NULL) goto error; - memset(shape, 0, sizeof(NSVGshape)); - - memcpy(shape->id, attr->id, sizeof shape->id); - scale = nsvg__getAverageScale(attr->xform); - shape->strokeWidth = attr->strokeWidth * scale; - shape->strokeDashOffset = attr->strokeDashOffset * scale; - shape->strokeDashCount = (char)attr->strokeDashCount; - for (i = 0; i < attr->strokeDashCount; i++) - shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; - shape->strokeLineJoin = attr->strokeLineJoin; - shape->strokeLineCap = attr->strokeLineCap; - shape->miterLimit = attr->miterLimit; - shape->fillRule = attr->fillRule; - shape->opacity = attr->opacity; - - shape->paths = p->plist; - p->plist = NULL; - - // Calculate shape bounds - shape->bounds[0] = shape->paths->bounds[0]; - shape->bounds[1] = shape->paths->bounds[1]; - shape->bounds[2] = shape->paths->bounds[2]; - shape->bounds[3] = shape->paths->bounds[3]; - for (path = shape->paths->next; path != NULL; path = path->next) { - shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); - shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); - shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); - shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); - } - - // Set fill - if (attr->hasFill == 0) { - shape->fill.type = NSVG_PAINT_NONE; - } else if (attr->hasFill == 1) { - shape->fill.type = NSVG_PAINT_COLOR; - shape->fill.color = attr->fillColor; - shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; - } else if (attr->hasFill == 2) { - float inv[6], localBounds[4]; - nsvg__xformInverse(inv, attr->xform); - nsvg__getLocalBounds(localBounds, shape, inv); - shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); - if (shape->fill.gradient == NULL) { - shape->fill.type = NSVG_PAINT_NONE; - } - } - - // Set stroke - if (attr->hasStroke == 0) { - shape->stroke.type = NSVG_PAINT_NONE; - } else if (attr->hasStroke == 1) { - shape->stroke.type = NSVG_PAINT_COLOR; - shape->stroke.color = attr->strokeColor; - shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; - } else if (attr->hasStroke == 2) { - float inv[6], localBounds[4]; - nsvg__xformInverse(inv, attr->xform); - nsvg__getLocalBounds(localBounds, shape, inv); - shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); - if (shape->stroke.gradient == NULL) - shape->stroke.type = NSVG_PAINT_NONE; - } - - // Set flags - shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); - - // Add to tail - if (p->image->shapes == NULL) - p->image->shapes = shape; - else - p->shapesTail->next = shape; - p->shapesTail = shape; - - return; +static void nsvg__deleteGradientData(NSVGgradientData *grad) { + NSVGgradientData *next; + while (grad != NULL) { + next = grad->next; + free(grad->stops); + free(grad); + grad = next; + } +} + +static void nsvg__deleteParser(NSVGparser *p) { + if (p != NULL) { + nsvg__deletePaths(p->plist); + nsvg__deleteGradientData(p->gradients); + nsvgDelete(p->image); + free(p->pts); + free(p); + } +} + +static void nsvg__resetPath(NSVGparser *p) { p->npts = 0; } + +static void nsvg__addPoint(NSVGparser *p, float x, float y) { + if (p->npts + 1 > p->cpts) { + p->cpts = p->cpts ? p->cpts * 2 : 8; + p->pts = (float *)realloc(p->pts, p->cpts * 2 * sizeof(float)); + if (!p->pts) + return; + } + p->pts[p->npts * 2 + 0] = x; + p->pts[p->npts * 2 + 1] = y; + p->npts++; +} + +static void nsvg__moveTo(NSVGparser *p, float x, float y) { + if (p->npts > 0) { + p->pts[(p->npts - 1) * 2 + 0] = x; + p->pts[(p->npts - 1) * 2 + 1] = y; + } else { + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__lineTo(NSVGparser *p, float x, float y) { + float px, py, dx, dy; + if (p->npts > 0) { + px = p->pts[(p->npts - 1) * 2 + 0]; + py = p->pts[(p->npts - 1) * 2 + 1]; + dx = x - px; + dy = y - py; + nsvg__addPoint(p, px + dx / 3.0f, py + dy / 3.0f); + nsvg__addPoint(p, x - dx / 3.0f, y - dy / 3.0f); + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__cubicBezTo(NSVGparser *p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) { + nsvg__addPoint(p, cpx1, cpy1); + nsvg__addPoint(p, cpx2, cpy2); + nsvg__addPoint(p, x, y); +} + +static NSVGattrib *nsvg__getAttr(NSVGparser *p) { return &p->attr[p->attrHead]; } + +static void nsvg__pushAttr(NSVGparser *p) { + if (p->attrHead < NSVG_MAX_ATTR - 1) { + p->attrHead++; + memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead - 1], sizeof(NSVGattrib)); + } +} + +static void nsvg__popAttr(NSVGparser *p) { + if (p->attrHead > 0) + p->attrHead--; +} + +static float nsvg__actualOrigX(NSVGparser *p) { return p->viewMinx; } + +static float nsvg__actualOrigY(NSVGparser *p) { return p->viewMiny; } + +static float nsvg__actualWidth(NSVGparser *p) { return p->viewWidth; } + +static float nsvg__actualHeight(NSVGparser *p) { return p->viewHeight; } + +static float nsvg__actualLength(NSVGparser *p) { + float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); + return sqrtf(w * w + h * h) / sqrtf(2.0f); +} + +static float nsvg__convertToPixels(NSVGparser *p, NSVGcoordinate c, float orig, float length) { + NSVGattrib *attr = nsvg__getAttr(p); + switch (c.units) { + case NSVG_UNITS_USER: + return c.value; + case NSVG_UNITS_PX: + return c.value; + case NSVG_UNITS_PT: + return c.value / 72.0f * p->dpi; + case NSVG_UNITS_PC: + return c.value / 6.0f * p->dpi; + case NSVG_UNITS_MM: + return c.value / 25.4f * p->dpi; + case NSVG_UNITS_CM: + return c.value / 2.54f * p->dpi; + case NSVG_UNITS_IN: + return c.value * p->dpi; + case NSVG_UNITS_EM: + return c.value * attr->fontSize; + case NSVG_UNITS_EX: + return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. + case NSVG_UNITS_PERCENT: + return orig + c.value / 100.0f * length; + default: + return c.value; + } + return c.value; +} + +static NSVGgradientData *nsvg__findGradientData(NSVGparser *p, const char *id) { + NSVGgradientData *grad = p->gradients; + while (grad) { + if (strcmp(grad->id, id) == 0) + return grad; + grad = grad->next; + } + return NULL; +} + +static NSVGgradient *nsvg__createGradient(NSVGparser *p, const char *id, const float *localBounds, char *paintType) { + NSVGattrib *attr = nsvg__getAttr(p); + NSVGgradientData *data = NULL; + NSVGgradientData *ref = NULL; + NSVGgradientStop *stops = NULL; + NSVGgradient *grad; + float ox, oy, sw, sh, sl; + int nstops = 0; + + data = nsvg__findGradientData(p, id); + if (data == NULL) + return NULL; + + // TODO: use ref to fill in all unset values too. + ref = data; + while (ref != NULL) { + if (stops == NULL && ref->stops != NULL) { + stops = ref->stops; + nstops = ref->nstops; + break; + } + ref = nsvg__findGradientData(p, ref->ref); + } + if (stops == NULL) + return NULL; + + grad = (NSVGgradient *)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop) * (nstops - 1)); + if (grad == NULL) + return NULL; + + // The shape width and height. + if (data->units == NSVG_OBJECT_SPACE) { + ox = localBounds[0]; + oy = localBounds[1]; + sw = localBounds[2] - localBounds[0]; + sh = localBounds[3] - localBounds[1]; + } else { + ox = nsvg__actualOrigX(p); + oy = nsvg__actualOrigY(p); + sw = nsvg__actualWidth(p); + sh = nsvg__actualHeight(p); + } + sl = sqrtf(sw * sw + sh * sh) / sqrtf(2.0f); + + if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { + float x1, y1, x2, y2, dx, dy; + x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); + y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); + x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); + y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); + // Calculate transform aligned to the line + dx = x2 - x1; + dy = y2 - y1; + grad->xform[0] = dy; + grad->xform[1] = -dx; + grad->xform[2] = dx; + grad->xform[3] = dy; + grad->xform[4] = x1; + grad->xform[5] = y1; + } else { + float cx, cy, fx, fy, r; + cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); + cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); + fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); + fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); + r = nsvg__convertToPixels(p, data->radial.r, 0, sl); + // Calculate transform aligned to the circle + grad->xform[0] = r; + grad->xform[1] = 0; + grad->xform[2] = 0; + grad->xform[3] = r; + grad->xform[4] = cx; + grad->xform[5] = cy; + grad->fx = fx / r; + grad->fy = fy / r; + } + + nsvg__xformMultiply(grad->xform, data->xform); + nsvg__xformMultiply(grad->xform, attr->xform); + + grad->spread = data->spread; + memcpy(grad->stops, stops, nstops * sizeof(NSVGgradientStop)); + grad->nstops = nstops; + + *paintType = data->type; + + return grad; +} + +static float nsvg__getAverageScale(float *t) { + float sx = sqrtf(t[0] * t[0] + t[2] * t[2]); + float sy = sqrtf(t[1] * t[1] + t[3] * t[3]); + return (sx + sy) * 0.5f; +} + +static void nsvg__getLocalBounds(float *bounds, NSVGshape *shape, float *xform) { + NSVGpath *path; + float curve[4 * 2], curveBounds[4]; + int i, first = 1; + for (path = shape->paths; path != NULL; path = path->next) { + nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); + for (i = 0; i < path->npts - 1; i += 3) { + nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i + 1) * 2], path->pts[(i + 1) * 2 + 1], xform); + nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i + 2) * 2], path->pts[(i + 2) * 2 + 1], xform); + nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i + 3) * 2], path->pts[(i + 3) * 2 + 1], xform); + nsvg__curveBounds(curveBounds, curve); + if (first) { + bounds[0] = curveBounds[0]; + bounds[1] = curveBounds[1]; + bounds[2] = curveBounds[2]; + bounds[3] = curveBounds[3]; + first = 0; + } else { + bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); + bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); + bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); + bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); + } + curve[0] = curve[6]; + curve[1] = curve[7]; + } + } +} + +static void nsvg__addShape(NSVGparser *p) { + NSVGattrib *attr = nsvg__getAttr(p); + float scale = 1.0f; + NSVGshape *shape; + NSVGpath *path; + int i; + + if (p->plist == NULL) + return; + + shape = (NSVGshape *)malloc(sizeof(NSVGshape)); + if (shape == NULL) + goto error; + memset(shape, 0, sizeof(NSVGshape)); + + memcpy(shape->id, attr->id, sizeof shape->id); + scale = nsvg__getAverageScale(attr->xform); + shape->strokeWidth = attr->strokeWidth * scale; + shape->strokeDashOffset = attr->strokeDashOffset * scale; + shape->strokeDashCount = (char)attr->strokeDashCount; + for (i = 0; i < attr->strokeDashCount; i++) + shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; + shape->strokeLineJoin = attr->strokeLineJoin; + shape->strokeLineCap = attr->strokeLineCap; + shape->miterLimit = attr->miterLimit; + shape->fillRule = attr->fillRule; + shape->opacity = attr->opacity; + + shape->paths = p->plist; + p->plist = NULL; + + // Calculate shape bounds + shape->bounds[0] = shape->paths->bounds[0]; + shape->bounds[1] = shape->paths->bounds[1]; + shape->bounds[2] = shape->paths->bounds[2]; + shape->bounds[3] = shape->paths->bounds[3]; + for (path = shape->paths->next; path != NULL; path = path->next) { + shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); + shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); + shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); + shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); + } + + // Set fill + if (attr->hasFill == 0) { + shape->fill.type = NSVG_PAINT_NONE; + } else if (attr->hasFill == 1) { + shape->fill.type = NSVG_PAINT_COLOR; + shape->fill.color = attr->fillColor; + shape->fill.color |= (unsigned int)(attr->fillOpacity * 255) << 24; + } else if (attr->hasFill == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); + if (shape->fill.gradient == NULL) { + shape->fill.type = NSVG_PAINT_NONE; + } + } + + // Set stroke + if (attr->hasStroke == 0) { + shape->stroke.type = NSVG_PAINT_NONE; + } else if (attr->hasStroke == 1) { + shape->stroke.type = NSVG_PAINT_COLOR; + shape->stroke.color = attr->strokeColor; + shape->stroke.color |= (unsigned int)(attr->strokeOpacity * 255) << 24; + } else if (attr->hasStroke == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); + if (shape->stroke.gradient == NULL) + shape->stroke.type = NSVG_PAINT_NONE; + } + + // Set flags + shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); + + // Add to tail + if (p->image->shapes == NULL) + p->image->shapes = shape; + else + p->shapesTail->next = shape; + p->shapesTail = shape; + + return; error: - if (shape) free(shape); -} - -static void nsvg__addPath(NSVGparser* p, char closed) -{ - NSVGattrib* attr = nsvg__getAttr(p); - NSVGpath* path = NULL; - float bounds[4]; - float* curve; - int i; - - if (p->npts < 4) - return; - - if (closed) - nsvg__lineTo(p, p->pts[0], p->pts[1]); - - path = (NSVGpath*)malloc(sizeof(NSVGpath)); - if (path == NULL) goto error; - memset(path, 0, sizeof(NSVGpath)); - - path->pts = (float*)malloc(p->npts*2*sizeof(float)); - if (path->pts == NULL) goto error; - path->closed = closed; - path->npts = p->npts; - - // Transform path. - for (i = 0; i < p->npts; ++i) - nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); - - // Find bounds - for (i = 0; i < path->npts-1; i += 3) { - curve = &path->pts[i*2]; - nsvg__curveBounds(bounds, curve); - if (i == 0) { - path->bounds[0] = bounds[0]; - path->bounds[1] = bounds[1]; - path->bounds[2] = bounds[2]; - path->bounds[3] = bounds[3]; - } else { - path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); - path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); - path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); - path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); - } - } - - path->next = p->plist; - p->plist = path; - - return; + if (shape) + free(shape); +} + +static void nsvg__addPath(NSVGparser *p, char closed) { + NSVGattrib *attr = nsvg__getAttr(p); + NSVGpath *path = NULL; + float bounds[4]; + float *curve; + int i; + + if (p->npts < 4) + return; + + if (closed) + nsvg__lineTo(p, p->pts[0], p->pts[1]); + + path = (NSVGpath *)malloc(sizeof(NSVGpath)); + if (path == NULL) + goto error; + memset(path, 0, sizeof(NSVGpath)); + + path->pts = (float *)malloc(p->npts * 2 * sizeof(float)); + if (path->pts == NULL) + goto error; + path->closed = closed; + path->npts = p->npts; + + // Transform path. + for (i = 0; i < p->npts; ++i) + nsvg__xformPoint(&path->pts[i * 2], &path->pts[i * 2 + 1], p->pts[i * 2], p->pts[i * 2 + 1], attr->xform); + + // Find bounds + for (i = 0; i < path->npts - 1; i += 3) { + curve = &path->pts[i * 2]; + nsvg__curveBounds(bounds, curve); + if (i == 0) { + path->bounds[0] = bounds[0]; + path->bounds[1] = bounds[1]; + path->bounds[2] = bounds[2]; + path->bounds[3] = bounds[3]; + } else { + path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); + path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); + path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); + path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); + } + } + + path->next = p->plist; + p->plist = path; + + return; error: - if (path != NULL) { - if (path->pts != NULL) free(path->pts); - free(path); - } + if (path != NULL) { + if (path->pts != NULL) + free(path->pts); + free(path); + } } // We roll our own string to float because the std library one uses locale and messes things up. -static double nsvg__atof(const char* s) -{ - char* cur = (char*)s; - char* end = NULL; - double res = 0.0, sign = 1.0; - long long intPart = 0, fracPart = 0; - char hasIntPart = 0, hasFracPart = 0; - - // Parse optional sign - if (*cur == '+') { - cur++; - } else if (*cur == '-') { - sign = -1; - cur++; - } - - // Parse integer part - if (nsvg__isdigit(*cur)) { - // Parse digit sequence - intPart = (double)strtoll(cur, &end, 10); - if (cur != end) { - res = (double)intPart; - hasIntPart = 1; - cur = end; - } - } - - // Parse fractional part. - if (*cur == '.') { - cur++; // Skip '.' - if (nsvg__isdigit(*cur)) { - // Parse digit sequence - fracPart = strtoll(cur, &end, 10); - if (cur != end) { - res += (double)fracPart / pow(10.0, (double)(end - cur)); - hasFracPart = 1; - cur = end; - } - } - } - - // A valid number should have integer or fractional part. - if (!hasIntPart && !hasFracPart) - return 0.0; - - // Parse optional exponent - if (*cur == 'e' || *cur == 'E') { - long expPart = 0; - cur++; // skip 'E' - expPart = strtol(cur, &end, 10); // Parse digit sequence with sign - if (cur != end) { - res *= pow(10.0, (double)expPart); - } - } - - return res * sign; -} - - -static const char* nsvg__parseNumber(const char* s, char* it, const int size) -{ - const int last = size-1; - int i = 0; - - // sign - if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; - s++; - } - // integer part - // leading zero - if (*s == '0') { - if (i < last) it[i++] = *s; - s++; - } - else - while (nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - if (*s == '.') { - // decimal point - if (i < last) it[i++] = *s; - s++; - // fraction part - while (nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - } - // exponent - if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) { - if (i < last) it[i++] = *s; - s++; - if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; - s++; - } - while (nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - } - it[i] = '\0'; - - return s; -} - -static const char* nsvg__getNextPathItemWhenArcFlag(const char* s, char* it) -{ - it[0] = '\0'; - while (nsvg__isspace(*s) || *s == ',') s++; - if (*s == '0' || *s == '1') { - it[0] = *s++; - it[1] = '\0'; - return s; - } - return s; -} - -static const char* nsvg__getNextPathItem(const char* s, char* it) -{ - it[0] = '\0'; - // Skip white spaces and commas - while (nsvg__isspace(*s) || *s == ',') s++; - if (!*s) return s; - if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { - s = nsvg__parseNumber(s, it, 64); - } else { - // Parse command - it[0] = *s++; - it[1] = '\0'; - return s; - } - - return s; -} - -static unsigned int nsvg__parseColorHex(const char* str) -{ - unsigned int c = 0, r = 0, g = 0, b = 0; - int n = 0; - str++; // skip # - // Calculate number of characters. - while(str[n] && !nsvg__isspace(str[n])) - n++; - if (n == 6) { - sscanf(str, "%x", &c); - } else if (n == 3) { - sscanf(str, "%x", &c); - c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8); - c |= c<<4; - } - r = (c >> 16) & 0xff; - g = (c >> 8) & 0xff; - b = c & 0xff; - return NSVG_RGB(r,g,b); -} - -static unsigned int nsvg__parseColorRGB(const char* str) -{ - int r = -1, g = -1, b = -1; - char s1[32]="", s2[32]=""; - sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); - if (strchr(s1, '%')) { - return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100); - } else { - return NSVG_RGB(r,g,b); - } +static double nsvg__atof(const char *s) { + char *cur = (char *)s; + char *end = NULL; + double res = 0.0, sign = 1.0; + long long intPart = 0, fracPart = 0; + char hasIntPart = 0, hasFracPart = 0; + + // Parse optional sign + if (*cur == '+') { + cur++; + } else if (*cur == '-') { + sign = -1; + cur++; + } + + // Parse integer part + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + intPart = (double)strtoll(cur, &end, 10); + if (cur != end) { + res = (double)intPart; + hasIntPart = 1; + cur = end; + } + } + + // Parse fractional part. + if (*cur == '.') { + cur++; // Skip '.' + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + fracPart = strtoll(cur, &end, 10); + if (cur != end) { + res += (double)fracPart / pow(10.0, (double)(end - cur)); + hasFracPart = 1; + cur = end; + } + } + } + + // A valid number should have integer or fractional part. + if (!hasIntPart && !hasFracPart) + return 0.0; + + // Parse optional exponent + if (*cur == 'e' || *cur == 'E') { + long expPart = 0; + cur++; // skip 'E' + expPart = strtol(cur, &end, 10); // Parse digit sequence with sign + if (cur != end) { + res *= pow(10.0, (double)expPart); + } + } + + return res * sign; +} + +static const char *nsvg__parseNumber(const char *s, char *it, const int size) { + const int last = size - 1; + int i = 0; + + // sign + if (*s == '-' || *s == '+') { + if (i < last) + it[i++] = *s; + s++; + } + // integer part + // leading zero + if (*s == '0') { + if (i < last) + it[i++] = *s; + s++; + } else + while (nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + if (*s == '.') { + // decimal point + if (i < last) + it[i++] = *s; + s++; + // fraction part + while (nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + } + // exponent + if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) { + if (i < last) + it[i++] = *s; + s++; + if (*s == '-' || *s == '+') { + if (i < last) + it[i++] = *s; + s++; + } + while (nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + } + it[i] = '\0'; + + return s; +} + +static const char *nsvg__getNextPathItemWhenArcFlag(const char *s, char *it) { + it[0] = '\0'; + while (nsvg__isspace(*s) || *s == ',') + s++; + if (*s == '0' || *s == '1') { + it[0] = *s++; + it[1] = '\0'; + return s; + } + return s; +} + +static const char *nsvg__getNextPathItem(const char *s, char *it) { + it[0] = '\0'; + // Skip white spaces and commas + while (nsvg__isspace(*s) || *s == ',') + s++; + if (!*s) + return s; + if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { + s = nsvg__parseNumber(s, it, 64); + } else { + // Parse command + it[0] = *s++; + it[1] = '\0'; + return s; + } + + return s; +} + +static unsigned int nsvg__parseColorHex(const char *str) { + unsigned int c = 0, r = 0, g = 0, b = 0; + int n = 0; + str++; // skip # + // Calculate number of characters. + while (str[n] && !nsvg__isspace(str[n])) + n++; + if (n == 6) { + sscanf(str, "%x", &c); + } else if (n == 3) { + sscanf(str, "%x", &c); + c = (c & 0xf) | ((c & 0xf0) << 4) | ((c & 0xf00) << 8); + c |= c << 4; + } + r = (c >> 16) & 0xff; + g = (c >> 8) & 0xff; + b = c & 0xff; + return NSVG_RGB(r, g, b); +} + +static unsigned int nsvg__parseColorRGB(const char *str) { + int r = -1, g = -1, b = -1; + char s1[32] = "", s2[32] = ""; + sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); + if (strchr(s1, '%')) { + return NSVG_RGB((r * 255) / 100, (g * 255) / 100, (b * 255) / 100); + } else { + return NSVG_RGB(r, g, b); + } } typedef struct NSVGNamedColor { - const char* name; - unsigned int color; + const char *name; + unsigned int color; } NSVGNamedColor; NSVGNamedColor nsvg__colors[] = { - { "red", NSVG_RGB(255, 0, 0) }, - { "green", NSVG_RGB( 0, 128, 0) }, - { "blue", NSVG_RGB( 0, 0, 255) }, - { "yellow", NSVG_RGB(255, 255, 0) }, - { "cyan", NSVG_RGB( 0, 255, 255) }, - { "magenta", NSVG_RGB(255, 0, 255) }, - { "black", NSVG_RGB( 0, 0, 0) }, - { "grey", NSVG_RGB(128, 128, 128) }, - { "gray", NSVG_RGB(128, 128, 128) }, - { "white", NSVG_RGB(255, 255, 255) }, + {"red", NSVG_RGB(255, 0, 0)}, + {"green", NSVG_RGB(0, 128, 0)}, + {"blue", NSVG_RGB(0, 0, 255)}, + {"yellow", NSVG_RGB(255, 255, 0)}, + {"cyan", NSVG_RGB(0, 255, 255)}, + {"magenta", NSVG_RGB(255, 0, 255)}, + {"black", NSVG_RGB(0, 0, 0)}, + {"grey", NSVG_RGB(128, 128, 128)}, + {"gray", NSVG_RGB(128, 128, 128)}, + {"white", NSVG_RGB(255, 255, 255)}, #ifdef NANOSVG_ALL_COLOR_KEYWORDS - { "aliceblue", NSVG_RGB(240, 248, 255) }, - { "antiquewhite", NSVG_RGB(250, 235, 215) }, - { "aqua", NSVG_RGB( 0, 255, 255) }, - { "aquamarine", NSVG_RGB(127, 255, 212) }, - { "azure", NSVG_RGB(240, 255, 255) }, - { "beige", NSVG_RGB(245, 245, 220) }, - { "bisque", NSVG_RGB(255, 228, 196) }, - { "blanchedalmond", NSVG_RGB(255, 235, 205) }, - { "blueviolet", NSVG_RGB(138, 43, 226) }, - { "brown", NSVG_RGB(165, 42, 42) }, - { "burlywood", NSVG_RGB(222, 184, 135) }, - { "cadetblue", NSVG_RGB( 95, 158, 160) }, - { "chartreuse", NSVG_RGB(127, 255, 0) }, - { "chocolate", NSVG_RGB(210, 105, 30) }, - { "coral", NSVG_RGB(255, 127, 80) }, - { "cornflowerblue", NSVG_RGB(100, 149, 237) }, - { "cornsilk", NSVG_RGB(255, 248, 220) }, - { "crimson", NSVG_RGB(220, 20, 60) }, - { "darkblue", NSVG_RGB( 0, 0, 139) }, - { "darkcyan", NSVG_RGB( 0, 139, 139) }, - { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, - { "darkgray", NSVG_RGB(169, 169, 169) }, - { "darkgreen", NSVG_RGB( 0, 100, 0) }, - { "darkgrey", NSVG_RGB(169, 169, 169) }, - { "darkkhaki", NSVG_RGB(189, 183, 107) }, - { "darkmagenta", NSVG_RGB(139, 0, 139) }, - { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, - { "darkorange", NSVG_RGB(255, 140, 0) }, - { "darkorchid", NSVG_RGB(153, 50, 204) }, - { "darkred", NSVG_RGB(139, 0, 0) }, - { "darksalmon", NSVG_RGB(233, 150, 122) }, - { "darkseagreen", NSVG_RGB(143, 188, 143) }, - { "darkslateblue", NSVG_RGB( 72, 61, 139) }, - { "darkslategray", NSVG_RGB( 47, 79, 79) }, - { "darkslategrey", NSVG_RGB( 47, 79, 79) }, - { "darkturquoise", NSVG_RGB( 0, 206, 209) }, - { "darkviolet", NSVG_RGB(148, 0, 211) }, - { "deeppink", NSVG_RGB(255, 20, 147) }, - { "deepskyblue", NSVG_RGB( 0, 191, 255) }, - { "dimgray", NSVG_RGB(105, 105, 105) }, - { "dimgrey", NSVG_RGB(105, 105, 105) }, - { "dodgerblue", NSVG_RGB( 30, 144, 255) }, - { "firebrick", NSVG_RGB(178, 34, 34) }, - { "floralwhite", NSVG_RGB(255, 250, 240) }, - { "forestgreen", NSVG_RGB( 34, 139, 34) }, - { "fuchsia", NSVG_RGB(255, 0, 255) }, - { "gainsboro", NSVG_RGB(220, 220, 220) }, - { "ghostwhite", NSVG_RGB(248, 248, 255) }, - { "gold", NSVG_RGB(255, 215, 0) }, - { "goldenrod", NSVG_RGB(218, 165, 32) }, - { "greenyellow", NSVG_RGB(173, 255, 47) }, - { "honeydew", NSVG_RGB(240, 255, 240) }, - { "hotpink", NSVG_RGB(255, 105, 180) }, - { "indianred", NSVG_RGB(205, 92, 92) }, - { "indigo", NSVG_RGB( 75, 0, 130) }, - { "ivory", NSVG_RGB(255, 255, 240) }, - { "khaki", NSVG_RGB(240, 230, 140) }, - { "lavender", NSVG_RGB(230, 230, 250) }, - { "lavenderblush", NSVG_RGB(255, 240, 245) }, - { "lawngreen", NSVG_RGB(124, 252, 0) }, - { "lemonchiffon", NSVG_RGB(255, 250, 205) }, - { "lightblue", NSVG_RGB(173, 216, 230) }, - { "lightcoral", NSVG_RGB(240, 128, 128) }, - { "lightcyan", NSVG_RGB(224, 255, 255) }, - { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, - { "lightgray", NSVG_RGB(211, 211, 211) }, - { "lightgreen", NSVG_RGB(144, 238, 144) }, - { "lightgrey", NSVG_RGB(211, 211, 211) }, - { "lightpink", NSVG_RGB(255, 182, 193) }, - { "lightsalmon", NSVG_RGB(255, 160, 122) }, - { "lightseagreen", NSVG_RGB( 32, 178, 170) }, - { "lightskyblue", NSVG_RGB(135, 206, 250) }, - { "lightslategray", NSVG_RGB(119, 136, 153) }, - { "lightslategrey", NSVG_RGB(119, 136, 153) }, - { "lightsteelblue", NSVG_RGB(176, 196, 222) }, - { "lightyellow", NSVG_RGB(255, 255, 224) }, - { "lime", NSVG_RGB( 0, 255, 0) }, - { "limegreen", NSVG_RGB( 50, 205, 50) }, - { "linen", NSVG_RGB(250, 240, 230) }, - { "maroon", NSVG_RGB(128, 0, 0) }, - { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, - { "mediumblue", NSVG_RGB( 0, 0, 205) }, - { "mediumorchid", NSVG_RGB(186, 85, 211) }, - { "mediumpurple", NSVG_RGB(147, 112, 219) }, - { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, - { "mediumslateblue", NSVG_RGB(123, 104, 238) }, - { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, - { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, - { "mediumvioletred", NSVG_RGB(199, 21, 133) }, - { "midnightblue", NSVG_RGB( 25, 25, 112) }, - { "mintcream", NSVG_RGB(245, 255, 250) }, - { "mistyrose", NSVG_RGB(255, 228, 225) }, - { "moccasin", NSVG_RGB(255, 228, 181) }, - { "navajowhite", NSVG_RGB(255, 222, 173) }, - { "navy", NSVG_RGB( 0, 0, 128) }, - { "oldlace", NSVG_RGB(253, 245, 230) }, - { "olive", NSVG_RGB(128, 128, 0) }, - { "olivedrab", NSVG_RGB(107, 142, 35) }, - { "orange", NSVG_RGB(255, 165, 0) }, - { "orangered", NSVG_RGB(255, 69, 0) }, - { "orchid", NSVG_RGB(218, 112, 214) }, - { "palegoldenrod", NSVG_RGB(238, 232, 170) }, - { "palegreen", NSVG_RGB(152, 251, 152) }, - { "paleturquoise", NSVG_RGB(175, 238, 238) }, - { "palevioletred", NSVG_RGB(219, 112, 147) }, - { "papayawhip", NSVG_RGB(255, 239, 213) }, - { "peachpuff", NSVG_RGB(255, 218, 185) }, - { "peru", NSVG_RGB(205, 133, 63) }, - { "pink", NSVG_RGB(255, 192, 203) }, - { "plum", NSVG_RGB(221, 160, 221) }, - { "powderblue", NSVG_RGB(176, 224, 230) }, - { "purple", NSVG_RGB(128, 0, 128) }, - { "rosybrown", NSVG_RGB(188, 143, 143) }, - { "royalblue", NSVG_RGB( 65, 105, 225) }, - { "saddlebrown", NSVG_RGB(139, 69, 19) }, - { "salmon", NSVG_RGB(250, 128, 114) }, - { "sandybrown", NSVG_RGB(244, 164, 96) }, - { "seagreen", NSVG_RGB( 46, 139, 87) }, - { "seashell", NSVG_RGB(255, 245, 238) }, - { "sienna", NSVG_RGB(160, 82, 45) }, - { "silver", NSVG_RGB(192, 192, 192) }, - { "skyblue", NSVG_RGB(135, 206, 235) }, - { "slateblue", NSVG_RGB(106, 90, 205) }, - { "slategray", NSVG_RGB(112, 128, 144) }, - { "slategrey", NSVG_RGB(112, 128, 144) }, - { "snow", NSVG_RGB(255, 250, 250) }, - { "springgreen", NSVG_RGB( 0, 255, 127) }, - { "steelblue", NSVG_RGB( 70, 130, 180) }, - { "tan", NSVG_RGB(210, 180, 140) }, - { "teal", NSVG_RGB( 0, 128, 128) }, - { "thistle", NSVG_RGB(216, 191, 216) }, - { "tomato", NSVG_RGB(255, 99, 71) }, - { "turquoise", NSVG_RGB( 64, 224, 208) }, - { "violet", NSVG_RGB(238, 130, 238) }, - { "wheat", NSVG_RGB(245, 222, 179) }, - { "whitesmoke", NSVG_RGB(245, 245, 245) }, - { "yellowgreen", NSVG_RGB(154, 205, 50) }, + {"aliceblue", NSVG_RGB(240, 248, 255)}, + {"antiquewhite", NSVG_RGB(250, 235, 215)}, + {"aqua", NSVG_RGB(0, 255, 255)}, + {"aquamarine", NSVG_RGB(127, 255, 212)}, + {"azure", NSVG_RGB(240, 255, 255)}, + {"beige", NSVG_RGB(245, 245, 220)}, + {"bisque", NSVG_RGB(255, 228, 196)}, + {"blanchedalmond", NSVG_RGB(255, 235, 205)}, + {"blueviolet", NSVG_RGB(138, 43, 226)}, + {"brown", NSVG_RGB(165, 42, 42)}, + {"burlywood", NSVG_RGB(222, 184, 135)}, + {"cadetblue", NSVG_RGB(95, 158, 160)}, + {"chartreuse", NSVG_RGB(127, 255, 0)}, + {"chocolate", NSVG_RGB(210, 105, 30)}, + {"coral", NSVG_RGB(255, 127, 80)}, + {"cornflowerblue", NSVG_RGB(100, 149, 237)}, + {"cornsilk", NSVG_RGB(255, 248, 220)}, + {"crimson", NSVG_RGB(220, 20, 60)}, + {"darkblue", NSVG_RGB(0, 0, 139)}, + {"darkcyan", NSVG_RGB(0, 139, 139)}, + {"darkgoldenrod", NSVG_RGB(184, 134, 11)}, + {"darkgray", NSVG_RGB(169, 169, 169)}, + {"darkgreen", NSVG_RGB(0, 100, 0)}, + {"darkgrey", NSVG_RGB(169, 169, 169)}, + {"darkkhaki", NSVG_RGB(189, 183, 107)}, + {"darkmagenta", NSVG_RGB(139, 0, 139)}, + {"darkolivegreen", NSVG_RGB(85, 107, 47)}, + {"darkorange", NSVG_RGB(255, 140, 0)}, + {"darkorchid", NSVG_RGB(153, 50, 204)}, + {"darkred", NSVG_RGB(139, 0, 0)}, + {"darksalmon", NSVG_RGB(233, 150, 122)}, + {"darkseagreen", NSVG_RGB(143, 188, 143)}, + {"darkslateblue", NSVG_RGB(72, 61, 139)}, + {"darkslategray", NSVG_RGB(47, 79, 79)}, + {"darkslategrey", NSVG_RGB(47, 79, 79)}, + {"darkturquoise", NSVG_RGB(0, 206, 209)}, + {"darkviolet", NSVG_RGB(148, 0, 211)}, + {"deeppink", NSVG_RGB(255, 20, 147)}, + {"deepskyblue", NSVG_RGB(0, 191, 255)}, + {"dimgray", NSVG_RGB(105, 105, 105)}, + {"dimgrey", NSVG_RGB(105, 105, 105)}, + {"dodgerblue", NSVG_RGB(30, 144, 255)}, + {"firebrick", NSVG_RGB(178, 34, 34)}, + {"floralwhite", NSVG_RGB(255, 250, 240)}, + {"forestgreen", NSVG_RGB(34, 139, 34)}, + {"fuchsia", NSVG_RGB(255, 0, 255)}, + {"gainsboro", NSVG_RGB(220, 220, 220)}, + {"ghostwhite", NSVG_RGB(248, 248, 255)}, + {"gold", NSVG_RGB(255, 215, 0)}, + {"goldenrod", NSVG_RGB(218, 165, 32)}, + {"greenyellow", NSVG_RGB(173, 255, 47)}, + {"honeydew", NSVG_RGB(240, 255, 240)}, + {"hotpink", NSVG_RGB(255, 105, 180)}, + {"indianred", NSVG_RGB(205, 92, 92)}, + {"indigo", NSVG_RGB(75, 0, 130)}, + {"ivory", NSVG_RGB(255, 255, 240)}, + {"khaki", NSVG_RGB(240, 230, 140)}, + {"lavender", NSVG_RGB(230, 230, 250)}, + {"lavenderblush", NSVG_RGB(255, 240, 245)}, + {"lawngreen", NSVG_RGB(124, 252, 0)}, + {"lemonchiffon", NSVG_RGB(255, 250, 205)}, + {"lightblue", NSVG_RGB(173, 216, 230)}, + {"lightcoral", NSVG_RGB(240, 128, 128)}, + {"lightcyan", NSVG_RGB(224, 255, 255)}, + {"lightgoldenrodyellow", NSVG_RGB(250, 250, 210)}, + {"lightgray", NSVG_RGB(211, 211, 211)}, + {"lightgreen", NSVG_RGB(144, 238, 144)}, + {"lightgrey", NSVG_RGB(211, 211, 211)}, + {"lightpink", NSVG_RGB(255, 182, 193)}, + {"lightsalmon", NSVG_RGB(255, 160, 122)}, + {"lightseagreen", NSVG_RGB(32, 178, 170)}, + {"lightskyblue", NSVG_RGB(135, 206, 250)}, + {"lightslategray", NSVG_RGB(119, 136, 153)}, + {"lightslategrey", NSVG_RGB(119, 136, 153)}, + {"lightsteelblue", NSVG_RGB(176, 196, 222)}, + {"lightyellow", NSVG_RGB(255, 255, 224)}, + {"lime", NSVG_RGB(0, 255, 0)}, + {"limegreen", NSVG_RGB(50, 205, 50)}, + {"linen", NSVG_RGB(250, 240, 230)}, + {"maroon", NSVG_RGB(128, 0, 0)}, + {"mediumaquamarine", NSVG_RGB(102, 205, 170)}, + {"mediumblue", NSVG_RGB(0, 0, 205)}, + {"mediumorchid", NSVG_RGB(186, 85, 211)}, + {"mediumpurple", NSVG_RGB(147, 112, 219)}, + {"mediumseagreen", NSVG_RGB(60, 179, 113)}, + {"mediumslateblue", NSVG_RGB(123, 104, 238)}, + {"mediumspringgreen", NSVG_RGB(0, 250, 154)}, + {"mediumturquoise", NSVG_RGB(72, 209, 204)}, + {"mediumvioletred", NSVG_RGB(199, 21, 133)}, + {"midnightblue", NSVG_RGB(25, 25, 112)}, + {"mintcream", NSVG_RGB(245, 255, 250)}, + {"mistyrose", NSVG_RGB(255, 228, 225)}, + {"moccasin", NSVG_RGB(255, 228, 181)}, + {"navajowhite", NSVG_RGB(255, 222, 173)}, + {"navy", NSVG_RGB(0, 0, 128)}, + {"oldlace", NSVG_RGB(253, 245, 230)}, + {"olive", NSVG_RGB(128, 128, 0)}, + {"olivedrab", NSVG_RGB(107, 142, 35)}, + {"orange", NSVG_RGB(255, 165, 0)}, + {"orangered", NSVG_RGB(255, 69, 0)}, + {"orchid", NSVG_RGB(218, 112, 214)}, + {"palegoldenrod", NSVG_RGB(238, 232, 170)}, + {"palegreen", NSVG_RGB(152, 251, 152)}, + {"paleturquoise", NSVG_RGB(175, 238, 238)}, + {"palevioletred", NSVG_RGB(219, 112, 147)}, + {"papayawhip", NSVG_RGB(255, 239, 213)}, + {"peachpuff", NSVG_RGB(255, 218, 185)}, + {"peru", NSVG_RGB(205, 133, 63)}, + {"pink", NSVG_RGB(255, 192, 203)}, + {"plum", NSVG_RGB(221, 160, 221)}, + {"powderblue", NSVG_RGB(176, 224, 230)}, + {"purple", NSVG_RGB(128, 0, 128)}, + {"rosybrown", NSVG_RGB(188, 143, 143)}, + {"royalblue", NSVG_RGB(65, 105, 225)}, + {"saddlebrown", NSVG_RGB(139, 69, 19)}, + {"salmon", NSVG_RGB(250, 128, 114)}, + {"sandybrown", NSVG_RGB(244, 164, 96)}, + {"seagreen", NSVG_RGB(46, 139, 87)}, + {"seashell", NSVG_RGB(255, 245, 238)}, + {"sienna", NSVG_RGB(160, 82, 45)}, + {"silver", NSVG_RGB(192, 192, 192)}, + {"skyblue", NSVG_RGB(135, 206, 235)}, + {"slateblue", NSVG_RGB(106, 90, 205)}, + {"slategray", NSVG_RGB(112, 128, 144)}, + {"slategrey", NSVG_RGB(112, 128, 144)}, + {"snow", NSVG_RGB(255, 250, 250)}, + {"springgreen", NSVG_RGB(0, 255, 127)}, + {"steelblue", NSVG_RGB(70, 130, 180)}, + {"tan", NSVG_RGB(210, 180, 140)}, + {"teal", NSVG_RGB(0, 128, 128)}, + {"thistle", NSVG_RGB(216, 191, 216)}, + {"tomato", NSVG_RGB(255, 99, 71)}, + {"turquoise", NSVG_RGB(64, 224, 208)}, + {"violet", NSVG_RGB(238, 130, 238)}, + {"wheat", NSVG_RGB(245, 222, 179)}, + {"whitesmoke", NSVG_RGB(245, 245, 245)}, + {"yellowgreen", NSVG_RGB(154, 205, 50)}, #endif }; -static unsigned int nsvg__parseColorName(const char* str) -{ - int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); - - for (i = 0; i < ncolors; i++) { - if (strcmp(nsvg__colors[i].name, str) == 0) { - return nsvg__colors[i].color; - } - } - - return NSVG_RGB(128, 128, 128); -} - -static unsigned int nsvg__parseColor(const char* str) -{ - size_t len = 0; - while(*str == ' ') ++str; - len = strlen(str); - if (len >= 1 && *str == '#') - return nsvg__parseColorHex(str); - else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') - return nsvg__parseColorRGB(str); - return nsvg__parseColorName(str); -} - -static float nsvg__parseOpacity(const char* str) -{ - float val = nsvg__atof(str); - if (val < 0.0f) val = 0.0f; - if (val > 1.0f) val = 1.0f; - return val; -} - -static float nsvg__parseMiterLimit(const char* str) -{ - float val = nsvg__atof(str); - if (val < 0.0f) val = 0.0f; - return val; -} - -static int nsvg__parseUnits(const char* units) -{ - if (units[0] == 'p' && units[1] == 'x') - return NSVG_UNITS_PX; - else if (units[0] == 'p' && units[1] == 't') - return NSVG_UNITS_PT; - else if (units[0] == 'p' && units[1] == 'c') - return NSVG_UNITS_PC; - else if (units[0] == 'm' && units[1] == 'm') - return NSVG_UNITS_MM; - else if (units[0] == 'c' && units[1] == 'm') - return NSVG_UNITS_CM; - else if (units[0] == 'i' && units[1] == 'n') - return NSVG_UNITS_IN; - else if (units[0] == '%') - return NSVG_UNITS_PERCENT; - else if (units[0] == 'e' && units[1] == 'm') - return NSVG_UNITS_EM; - else if (units[0] == 'e' && units[1] == 'x') - return NSVG_UNITS_EX; - return NSVG_UNITS_USER; -} - -static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) -{ - NSVGcoordinate coord = {0, NSVG_UNITS_USER}; - char buf[64]; - coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); - coord.value = nsvg__atof(buf); - return coord; -} - -static NSVGcoordinate nsvg__coord(float v, int units) -{ - NSVGcoordinate coord = {v, units}; - return coord; -} - -static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) -{ - NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); - return nsvg__convertToPixels(p, coord, orig, length); -} - -static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) -{ - const char* end; - const char* ptr; - char it[64]; - - *na = 0; - ptr = str; - while (*ptr && *ptr != '(') ++ptr; - if (*ptr == 0) - return 1; - end = ptr; - while (*end && *end != ')') ++end; - if (*end == 0) - return 1; - - while (ptr < end) { - if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { - if (*na >= maxNa) return 0; - ptr = nsvg__parseNumber(ptr, it, 64); - args[(*na)++] = (float)nsvg__atof(it); - } else { - ++ptr; - } - } - return (int)(end - str); -} - - -static int nsvg__parseMatrix(float* xform, const char* str) -{ - float t[6]; - int na = 0; - int len = nsvg__parseTransformArgs(str, t, 6, &na); - if (na != 6) return len; - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseTranslate(float* xform, const char* str) -{ - float args[2]; - float t[6]; - int na = 0; - int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = 0.0; - - nsvg__xformSetTranslation(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseScale(float* xform, const char* str) -{ - float args[2]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = args[0]; - nsvg__xformSetScale(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseSkewX(float* xform, const char* str) -{ - float args[1]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseSkewY(float* xform, const char* str) -{ - float args[1]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseRotate(float* xform, const char* str) -{ - float args[3]; - int na = 0; - float m[6]; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 3, &na); - if (na == 1) - args[1] = args[2] = 0.0f; - nsvg__xformIdentity(m); - - if (na > 1) { - nsvg__xformSetTranslation(t, -args[1], -args[2]); - nsvg__xformMultiply(m, t); - } - - nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); - nsvg__xformMultiply(m, t); - - if (na > 1) { - nsvg__xformSetTranslation(t, args[1], args[2]); - nsvg__xformMultiply(m, t); - } - - memcpy(xform, m, sizeof(float)*6); - - return len; -} - -static void nsvg__parseTransform(float* xform, const char* str) -{ - float t[6]; - nsvg__xformIdentity(xform); - while (*str) - { - if (strncmp(str, "matrix", 6) == 0) - str += nsvg__parseMatrix(t, str); - else if (strncmp(str, "translate", 9) == 0) - str += nsvg__parseTranslate(t, str); - else if (strncmp(str, "scale", 5) == 0) - str += nsvg__parseScale(t, str); - else if (strncmp(str, "rotate", 6) == 0) - str += nsvg__parseRotate(t, str); - else if (strncmp(str, "skewX", 5) == 0) - str += nsvg__parseSkewX(t, str); - else if (strncmp(str, "skewY", 5) == 0) - str += nsvg__parseSkewY(t, str); - else{ - ++str; - continue; - } - - nsvg__xformPremultiply(xform, t); - } -} - -static void nsvg__parseUrl(char* id, const char* str) -{ - int i = 0; - str += 4; // "url("; - if (*str == '#') - str++; - while (i < 63 && *str != ')') { - id[i] = *str++; - i++; - } - id[i] = '\0'; -} - -static char nsvg__parseLineCap(const char* str) -{ - if (strcmp(str, "butt") == 0) - return NSVG_CAP_BUTT; - else if (strcmp(str, "round") == 0) - return NSVG_CAP_ROUND; - else if (strcmp(str, "square") == 0) - return NSVG_CAP_SQUARE; - // TODO: handle inherit. - return NSVG_CAP_BUTT; -} - -static char nsvg__parseLineJoin(const char* str) -{ - if (strcmp(str, "miter") == 0) - return NSVG_JOIN_MITER; - else if (strcmp(str, "round") == 0) - return NSVG_JOIN_ROUND; - else if (strcmp(str, "bevel") == 0) - return NSVG_JOIN_BEVEL; - // TODO: handle inherit. - return NSVG_JOIN_MITER; -} - -static char nsvg__parseFillRule(const char* str) -{ - if (strcmp(str, "nonzero") == 0) - return NSVG_FILLRULE_NONZERO; - else if (strcmp(str, "evenodd") == 0) - return NSVG_FILLRULE_EVENODD; - // TODO: handle inherit. - return NSVG_FILLRULE_NONZERO; -} - -static const char* nsvg__getNextDashItem(const char* s, char* it) -{ - int n = 0; - it[0] = '\0'; - // Skip white spaces and commas - while (nsvg__isspace(*s) || *s == ',') s++; - // Advance until whitespace, comma or end. - while (*s && (!nsvg__isspace(*s) && *s != ',')) { - if (n < 63) - it[n++] = *s; - s++; - } - it[n++] = '\0'; - return s; -} - -static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) -{ - char item[64]; - int count = 0, i; - float sum = 0.0f; - - // Handle "none" - if (str[0] == 'n') - return 0; - - // Parse dashes - while (*str) { - str = nsvg__getNextDashItem(str, item); - if (!*item) break; - if (count < NSVG_MAX_DASHES) - strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); - } - - for (i = 0; i < count; i++) - sum += strokeDashArray[i]; - if (sum <= 1e-6f) - count = 0; - - return count; -} - -static void nsvg__parseStyle(NSVGparser* p, const char* str); - -static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) -{ - float xform[6]; - NSVGattrib* attr = nsvg__getAttr(p); - if (!attr) return 0; - - if (strcmp(name, "style") == 0) { - nsvg__parseStyle(p, value); - } else if (strcmp(name, "display") == 0) { - if (strcmp(value, "none") == 0) - attr->visible = 0; - // Don't reset ->visible on display:inline, one display:none hides the whole subtree - - } else if (strcmp(name, "fill") == 0) { - if (strcmp(value, "none") == 0) { - attr->hasFill = 0; - } else if (strncmp(value, "url(", 4) == 0) { - attr->hasFill = 2; - nsvg__parseUrl(attr->fillGradient, value); - } else { - attr->hasFill = 1; - attr->fillColor = nsvg__parseColor(value); - } - } else if (strcmp(name, "opacity") == 0) { - attr->opacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "fill-opacity") == 0) { - attr->fillOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "stroke") == 0) { - if (strcmp(value, "none") == 0) { - attr->hasStroke = 0; - } else if (strncmp(value, "url(", 4) == 0) { - attr->hasStroke = 2; - nsvg__parseUrl(attr->strokeGradient, value); - } else { - attr->hasStroke = 1; - attr->strokeColor = nsvg__parseColor(value); - } - } else if (strcmp(name, "stroke-width") == 0) { - attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "stroke-dasharray") == 0) { - attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); - } else if (strcmp(name, "stroke-dashoffset") == 0) { - attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "stroke-opacity") == 0) { - attr->strokeOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "stroke-linecap") == 0) { - attr->strokeLineCap = nsvg__parseLineCap(value); - } else if (strcmp(name, "stroke-linejoin") == 0) { - attr->strokeLineJoin = nsvg__parseLineJoin(value); - } else if (strcmp(name, "stroke-miterlimit") == 0) { - attr->miterLimit = nsvg__parseMiterLimit(value); - } else if (strcmp(name, "fill-rule") == 0) { - attr->fillRule = nsvg__parseFillRule(value); - } else if (strcmp(name, "font-size") == 0) { - attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "transform") == 0) { - nsvg__parseTransform(xform, value); - nsvg__xformPremultiply(attr->xform, xform); - } else if (strcmp(name, "stop-color") == 0) { - attr->stopColor = nsvg__parseColor(value); - } else if (strcmp(name, "stop-opacity") == 0) { - attr->stopOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "offset") == 0) { - attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); - } else if (strcmp(name, "id") == 0) { - strncpy(attr->id, value, 63); - attr->id[63] = '\0'; - } else { - return 0; - } - return 1; -} - -static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) -{ - const char* str; - const char* val; - char name[512]; - char value[512]; - int n; - - str = start; - while (str < end && *str != ':') ++str; - - val = str; - - // Right Trim - while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; - ++str; - - n = (int)(str - start); - if (n > 511) n = 511; - if (n) memcpy(name, start, n); - name[n] = 0; - - while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; - - n = (int)(end - val); - if (n > 511) n = 511; - if (n) memcpy(value, val, n); - value[n] = 0; - - return nsvg__parseAttr(p, name, value); -} - -static void nsvg__parseStyle(NSVGparser* p, const char* str) -{ - const char* start; - const char* end; - - while (*str) { - // Left Trim - while(nsvg__isspace(*str)) ++str; - start = str; - while(*str && *str != ';') ++str; - end = str; - - // Right Trim - while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; - ++end; - - nsvg__parseNameValue(p, start, end); - if (*str) ++str; - } -} - -static void nsvg__parseAttribs(NSVGparser* p, const char** attr) -{ - int i; - for (i = 0; attr[i]; i += 2) - { - if (strcmp(attr[i], "style") == 0) - nsvg__parseStyle(p, attr[i + 1]); - else - nsvg__parseAttr(p, attr[i], attr[i + 1]); - } -} - -static int nsvg__getArgsPerElement(char cmd) -{ - switch (cmd) { - case 'v': - case 'V': - case 'h': - case 'H': - return 1; - case 'm': - case 'M': - case 'l': - case 'L': - case 't': - case 'T': - return 2; - case 'q': - case 'Q': - case 's': - case 'S': - return 4; - case 'c': - case 'C': - return 6; - case 'a': - case 'A': - return 7; - } - return 0; -} - -static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) { - *cpx += args[0]; - *cpy += args[1]; - } else { - *cpx = args[0]; - *cpy = args[1]; - } - nsvg__moveTo(p, *cpx, *cpy); -} - -static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) { - *cpx += args[0]; - *cpy += args[1]; - } else { - *cpx = args[0]; - *cpy = args[1]; - } - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) - *cpx += args[0]; - else - *cpx = args[0]; - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) - *cpy += args[0]; - else - *cpy = args[0]; - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x2, y2, cx1, cy1, cx2, cy2; - - if (rel) { - cx1 = *cpx + args[0]; - cy1 = *cpy + args[1]; - cx2 = *cpx + args[2]; - cy2 = *cpy + args[3]; - x2 = *cpx + args[4]; - y2 = *cpy + args[5]; - } else { - cx1 = args[0]; - cy1 = args[1]; - cx2 = args[2]; - cy2 = args[3]; - x2 = args[4]; - y2 = args[5]; - } - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx2; - *cpy2 = cy2; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - cx2 = *cpx + args[0]; - cy2 = *cpy + args[1]; - x2 = *cpx + args[2]; - y2 = *cpy + args[3]; - } else { - cx2 = args[0]; - cy2 = args[1]; - x2 = args[2]; - y2 = args[3]; - } - - cx1 = 2*x1 - *cpx2; - cy1 = 2*y1 - *cpy2; - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx2; - *cpy2 = cy2; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx, cy; - float cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - cx = *cpx + args[0]; - cy = *cpy + args[1]; - x2 = *cpx + args[2]; - y2 = *cpy + args[3]; - } else { - cx = args[0]; - cy = args[1]; - x2 = args[2]; - y2 = args[3]; - } - - // Convert to cubic bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx; - *cpy2 = cy; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx, cy; - float cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - x2 = *cpx + args[0]; - y2 = *cpy + args[1]; - } else { - x2 = args[0]; - y2 = args[1]; - } - - cx = 2*x1 - *cpx2; - cy = 2*y1 - *cpy2; - - // Convert to cubix bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx; - *cpy2 = cy; - *cpx = x2; - *cpy = y2; -} - -static float nsvg__sqr(float x) { return x*x; } -static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } - -static float nsvg__vecrat(float ux, float uy, float vx, float vy) -{ - return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); -} - -static float nsvg__vecang(float ux, float uy, float vx, float vy) -{ - float r = nsvg__vecrat(ux,uy, vx,vy); - if (r < -1.0f) r = -1.0f; - if (r > 1.0f) r = 1.0f; - return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); -} - -static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - // Ported from canvg (https://code.google.com/p/canvg/) - float rx, ry, rotx; - float x1, y1, x2, y2, cx, cy, dx, dy, d; - float x1p, y1p, cxp, cyp, s, sa, sb; - float ux, uy, vx, vy, a1, da; - float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; - float sinrx, cosrx; - int fa, fs; - int i, ndivs; - float hda, kappa; - - rx = fabsf(args[0]); // y radius - ry = fabsf(args[1]); // x radius - rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle - fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc - fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction - x1 = *cpx; // start point - y1 = *cpy; - if (rel) { // end point - x2 = *cpx + args[5]; - y2 = *cpy + args[6]; - } else { - x2 = args[5]; - y2 = args[6]; - } - - dx = x1 - x2; - dy = y1 - y2; - d = sqrtf(dx*dx + dy*dy); - if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { - // The arc degenerates to a line - nsvg__lineTo(p, x2, y2); - *cpx = x2; - *cpy = y2; - return; - } - - sinrx = sinf(rotx); - cosrx = cosf(rotx); - - // Convert to center point parameterization. - // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - // 1) Compute x1', y1' - x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; - y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; - d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); - if (d > 1) { - d = sqrtf(d); - rx *= d; - ry *= d; - } - // 2) Compute cx', cy' - s = 0.0f; - sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); - sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); - if (sa < 0.0f) sa = 0.0f; - if (sb > 0.0f) - s = sqrtf(sa / sb); - if (fa == fs) - s = -s; - cxp = s * rx * y1p / ry; - cyp = s * -ry * x1p / rx; - - // 3) Compute cx,cy from cx',cy' - cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; - cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; - - // 4) Calculate theta1, and delta theta. - ux = (x1p - cxp) / rx; - uy = (y1p - cyp) / ry; - vx = (-x1p - cxp) / rx; - vy = (-y1p - cyp) / ry; - a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle - da = nsvg__vecang(ux,uy, vx,vy); // Delta angle - -// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; -// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; - - if (fs == 0 && da > 0) - da -= 2 * NSVG_PI; - else if (fs == 1 && da < 0) - da += 2 * NSVG_PI; - - // Approximate the arc using cubic spline segments. - t[0] = cosrx; t[1] = sinrx; - t[2] = -sinrx; t[3] = cosrx; - t[4] = cx; t[5] = cy; - - // Split arc into max 90 degree segments. - // The loop assumes an iteration per end point (including start and end), this +1. - ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); - hda = (da / (float)ndivs) / 2.0f; - kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); - if (da < 0.0f) - kappa = -kappa; - - for (i = 0; i <= ndivs; i++) { - a = a1 + da * ((float)i/(float)ndivs); - dx = cosf(a); - dy = sinf(a); - nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position - nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent - if (i > 0) - nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); - px = x; - py = y; - ptanx = tanx; - ptany = tany; - } - - *cpx = x2; - *cpy = y2; -} - -static void nsvg__parsePath(NSVGparser* p, const char** attr) -{ - const char* s = NULL; - char cmd = '\0'; - float args[10]; - int nargs; - int rargs = 0; - float cpx, cpy, cpx2, cpy2; - const char* tmp[4]; - char closedFlag; - int i; - char item[64]; - - for (i = 0; attr[i]; i += 2) { - if (strcmp(attr[i], "d") == 0) { - s = attr[i + 1]; - } else { - tmp[0] = attr[i]; - tmp[1] = attr[i + 1]; - tmp[2] = 0; - tmp[3] = 0; - nsvg__parseAttribs(p, tmp); - } - } - - if (s) { - nsvg__resetPath(p); - cpx = 0; cpy = 0; - cpx2 = 0; cpy2 = 0; - closedFlag = 0; - nargs = 0; - - while (*s) { - item[0] = '\0'; - if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4)) - s = nsvg__getNextPathItemWhenArcFlag(s, item); - if (!*item) - s = nsvg__getNextPathItem(s, item); - if (!*item) break; - if (nsvg__isnum(item[0])) { - if (nargs < 10) - args[nargs++] = (float)nsvg__atof(item); - if (nargs >= rargs) { - switch (cmd) { - case 'm': - case 'M': - nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); - // Moveto can be followed by multiple coordinate pairs, - // which should be treated as linetos. - cmd = (cmd == 'm') ? 'l' : 'L'; - rargs = nsvg__getArgsPerElement(cmd); - cpx2 = cpx; cpy2 = cpy; - break; - case 'l': - case 'L': - nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'H': - case 'h': - nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'V': - case 'v': - nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'C': - case 'c': - nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); - break; - case 'S': - case 's': - nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); - break; - case 'Q': - case 'q': - nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); - break; - case 'T': - case 't': - nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); - break; - case 'A': - case 'a': - nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - default: - if (nargs >= 2) { - cpx = args[nargs-2]; - cpy = args[nargs-1]; - cpx2 = cpx; cpy2 = cpy; - } - break; - } - nargs = 0; - } - } else { - // New command - if (nargs) { - NANOSVG_DEBUG("unfinished command '%c' %d/%d args\n", cmd, nargs, rargs); - } - cmd = item[0]; - rargs = nsvg__getArgsPerElement(cmd); - if (cmd == 'M' || cmd == 'm') { - // Commit path. - if (p->npts > 0) - nsvg__addPath(p, closedFlag); - // Start new subpath. - nsvg__resetPath(p); - closedFlag = 0; - nargs = 0; - } else if (cmd == 'Z' || cmd == 'z') { - closedFlag = 1; - // Commit path. - if (p->npts > 0) { - // Move current point to first point - cpx = p->pts[0]; - cpy = p->pts[1]; - cpx2 = cpx; cpy2 = cpy; - nsvg__addPath(p, closedFlag); - } - // Start new subpath. - nsvg__resetPath(p); - nsvg__moveTo(p, cpx, cpy); - closedFlag = 0; - nargs = 0; - } - } - } - // Commit path. - if (p->npts) - nsvg__addPath(p, closedFlag); - } - - nsvg__addShape(p); -} - -static void nsvg__parseRect(NSVGparser* p, const char** attr) -{ - float x = 0.0f; - float y = 0.0f; - float w = 0.0f; - float h = 0.0f; - float rx = -1.0f; // marks not set - float ry = -1.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); - if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); - } - } - - if (rx < 0.0f && ry > 0.0f) rx = ry; - if (ry < 0.0f && rx > 0.0f) ry = rx; - if (rx < 0.0f) rx = 0.0f; - if (ry < 0.0f) ry = 0.0f; - if (rx > w/2.0f) rx = w/2.0f; - if (ry > h/2.0f) ry = h/2.0f; - - if (w != 0.0f && h != 0.0f) { - nsvg__resetPath(p); - - if (rx < 0.00001f || ry < 0.0001f) { - nsvg__moveTo(p, x, y); - nsvg__lineTo(p, x+w, y); - nsvg__lineTo(p, x+w, y+h); - nsvg__lineTo(p, x, y+h); - } else { - // Rounded rectangle - nsvg__moveTo(p, x+rx, y); - nsvg__lineTo(p, x+w-rx, y); - nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); - nsvg__lineTo(p, x+w, y+h-ry); - nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); - nsvg__lineTo(p, x+rx, y+h); - nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); - nsvg__lineTo(p, x, y+ry); - nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); - } - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseCircle(NSVGparser* p, const char** attr) -{ - float cx = 0.0f; - float cy = 0.0f; - float r = 0.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); - } - } - - if (r > 0.0f) { - nsvg__resetPath(p); - - nsvg__moveTo(p, cx+r, cy); - nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); - nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); - nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); - nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseEllipse(NSVGparser* p, const char** attr) -{ - float cx = 0.0f; - float cy = 0.0f; - float rx = 0.0f; - float ry = 0.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); - } - } - - if (rx > 0.0f && ry > 0.0f) { - - nsvg__resetPath(p); - - nsvg__moveTo(p, cx+rx, cy); - nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); - nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); - nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); - nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseLine(NSVGparser* p, const char** attr) -{ - float x1 = 0.0; - float y1 = 0.0; - float x2 = 0.0; - float y2 = 0.0; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - } - } - - nsvg__resetPath(p); - - nsvg__moveTo(p, x1, y1); - nsvg__lineTo(p, x2, y2); - - nsvg__addPath(p, 0); - - nsvg__addShape(p); -} - -static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) -{ - int i; - const char* s; - float args[2]; - int nargs, npts = 0; - char item[64]; - - nsvg__resetPath(p); - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "points") == 0) { - s = attr[i + 1]; - nargs = 0; - while (*s) { - s = nsvg__getNextPathItem(s, item); - args[nargs++] = (float)nsvg__atof(item); - if (nargs >= 2) { - if (npts == 0) - nsvg__moveTo(p, args[0], args[1]); - else - nsvg__lineTo(p, args[0], args[1]); - nargs = 0; - npts++; - } - } - } - } - } - - nsvg__addPath(p, (char)closeFlag); - - nsvg__addShape(p); -} - -static void nsvg__parseSVG(NSVGparser* p, const char** attr) -{ - int i; - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "width") == 0) { - p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); - } else if (strcmp(attr[i], "height") == 0) { - p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); - } else if (strcmp(attr[i], "viewBox") == 0) { - const char *s = attr[i + 1]; - char buf[64]; - s = nsvg__parseNumber(s, buf, 64); - p->viewMinx = nsvg__atof(buf); - while (nsvg__isspace(*s) || *s == '%' || *s == ',') s++; - if (!*s) return; - s = nsvg__parseNumber(s, buf, 64); - p->viewMiny = nsvg__atof(buf); - while (nsvg__isspace(*s) || *s == '%' || *s == ',') s++; - if (!*s) return; - s = nsvg__parseNumber(s, buf, 64); - p->viewWidth = nsvg__atof(buf); - while (nsvg__isspace(*s) || *s == '%' || *s == ',') s++; - if (!*s) return; - s = nsvg__parseNumber(s, buf, 64); - p->viewHeight = nsvg__atof(buf); - } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { - if (strstr(attr[i + 1], "none") != 0) { - // No uniform scaling - p->alignType = NSVG_ALIGN_NONE; - } else { - // Parse X align - if (strstr(attr[i + 1], "xMin") != 0) - p->alignX = NSVG_ALIGN_MIN; - else if (strstr(attr[i + 1], "xMid") != 0) - p->alignX = NSVG_ALIGN_MID; - else if (strstr(attr[i + 1], "xMax") != 0) - p->alignX = NSVG_ALIGN_MAX; - // Parse X align - if (strstr(attr[i + 1], "yMin") != 0) - p->alignY = NSVG_ALIGN_MIN; - else if (strstr(attr[i + 1], "yMid") != 0) - p->alignY = NSVG_ALIGN_MID; - else if (strstr(attr[i + 1], "yMax") != 0) - p->alignY = NSVG_ALIGN_MAX; - // Parse meet/slice - p->alignType = NSVG_ALIGN_MEET; - if (strstr(attr[i + 1], "slice") != 0) - p->alignType = NSVG_ALIGN_SLICE; - } - } - } - } -} - -static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) -{ - int i; - NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); - if (grad == NULL) return; - memset(grad, 0, sizeof(NSVGgradientData)); - grad->units = NSVG_OBJECT_SPACE; - grad->type = type; - if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { - grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); - grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { - grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - } - - nsvg__xformIdentity(grad->xform); - - for (i = 0; attr[i]; i += 2) { - if (strcmp(attr[i], "id") == 0) { - strncpy(grad->id, attr[i+1], 63); - grad->id[63] = '\0'; - } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "gradientUnits") == 0) { - if (strcmp(attr[i+1], "objectBoundingBox") == 0) - grad->units = NSVG_OBJECT_SPACE; - else - grad->units = NSVG_USER_SPACE; - } else if (strcmp(attr[i], "gradientTransform") == 0) { - nsvg__parseTransform(grad->xform, attr[i + 1]); - } else if (strcmp(attr[i], "cx") == 0) { - grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "cy") == 0) { - grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "r") == 0) { - grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "fx") == 0) { - grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "fy") == 0) { - grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "x1") == 0) { - grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "y1") == 0) { - grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "x2") == 0) { - grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "y2") == 0) { - grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "spreadMethod") == 0) { - if (strcmp(attr[i+1], "pad") == 0) - grad->spread = NSVG_SPREAD_PAD; - else if (strcmp(attr[i+1], "reflect") == 0) - grad->spread = NSVG_SPREAD_REFLECT; - else if (strcmp(attr[i+1], "repeat") == 0) - grad->spread = NSVG_SPREAD_REPEAT; - } else if (strcmp(attr[i], "xlink:href") == 0) { - const char *href = attr[i+1]; - strncpy(grad->ref, href+1, 62); - grad->ref[62] = '\0'; - } - } - } - - grad->next = p->gradients; - p->gradients = grad; -} - -static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) -{ - NSVGattrib* curAttr = nsvg__getAttr(p); - NSVGgradientData* grad; - NSVGgradientStop* stop; - int i, idx; - - curAttr->stopOffset = 0; - curAttr->stopColor = 0; - curAttr->stopOpacity = 1.0f; - - for (i = 0; attr[i]; i += 2) { - nsvg__parseAttr(p, attr[i], attr[i + 1]); - } - - // Add stop to the last gradient. - grad = p->gradients; - if (grad == NULL) return; - - grad->nstops++; - grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); - if (grad->stops == NULL) return; - - // Insert - idx = grad->nstops-1; - for (i = 0; i < grad->nstops-1; i++) { - if (curAttr->stopOffset < grad->stops[i].offset) { - idx = i; - break; - } - } - if (idx != grad->nstops-1) { - for (i = grad->nstops-1; i > idx; i--) - grad->stops[i] = grad->stops[i-1]; - } - - stop = &grad->stops[idx]; - stop->color = curAttr->stopColor; - stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; - stop->offset = curAttr->stopOffset; -} - -static void nsvg__startElement(void* ud, const char* el, const char** attr) -{ - NSVGparser* p = (NSVGparser*)ud; - - if (p->defsFlag) { - // Skip everything but gradients in defs - if (strcmp(el, "linearGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); - } else if (strcmp(el, "radialGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); - } else if (strcmp(el, "stop") == 0) { - nsvg__parseGradientStop(p, attr); - } - return; - } - - if (strcmp(el, "g") == 0) { - nsvg__pushAttr(p); - nsvg__parseAttribs(p, attr); - } else if (strcmp(el, "path") == 0) { - if (p->pathFlag) // Do not allow nested paths. - return; - nsvg__pushAttr(p); - nsvg__parsePath(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "rect") == 0) { - nsvg__pushAttr(p); - nsvg__parseRect(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "circle") == 0) { - nsvg__pushAttr(p); - nsvg__parseCircle(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "ellipse") == 0) { - nsvg__pushAttr(p); - nsvg__parseEllipse(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "line") == 0) { - nsvg__pushAttr(p); - nsvg__parseLine(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "polyline") == 0) { - nsvg__pushAttr(p); - nsvg__parsePoly(p, attr, 0); - nsvg__popAttr(p); - } else if (strcmp(el, "polygon") == 0) { - nsvg__pushAttr(p); - nsvg__parsePoly(p, attr, 1); - nsvg__popAttr(p); - } else if (strcmp(el, "linearGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); - } else if (strcmp(el, "radialGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); - } else if (strcmp(el, "stop") == 0) { - nsvg__parseGradientStop(p, attr); - } else if (strcmp(el, "defs") == 0) { - p->defsFlag = 1; - } else if (strcmp(el, "svg") == 0) { - nsvg__parseSVG(p, attr); - } -} - -static void nsvg__endElement(void* ud, const char* el) -{ - NSVGparser* p = (NSVGparser*)ud; - - if (strcmp(el, "g") == 0) { - nsvg__popAttr(p); - } else if (strcmp(el, "path") == 0) { - p->pathFlag = 0; - } else if (strcmp(el, "defs") == 0) { - p->defsFlag = 0; - } -} - -static void nsvg__content(void* ud, const char* s) -{ - NSVG_NOTUSED(ud); - NSVG_NOTUSED(s); - // empty -} - -static void nsvg__imageBounds(NSVGparser* p, float* bounds) -{ - NSVGshape* shape; - shape = p->image->shapes; - if (shape == NULL) { - bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; - return; - } - bounds[0] = shape->bounds[0]; - bounds[1] = shape->bounds[1]; - bounds[2] = shape->bounds[2]; - bounds[3] = shape->bounds[3]; - for (shape = shape->next; shape != NULL; shape = shape->next) { - bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); - bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); - bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); - bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); - } -} - -static float nsvg__viewAlign(float content, float container, int type) -{ - if (type == NSVG_ALIGN_MIN) - return 0; - else if (type == NSVG_ALIGN_MAX) - return container - content; - // mid - return (container - content) * 0.5f; -} - -static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) -{ - float t[6]; - nsvg__xformSetTranslation(t, tx, ty); - nsvg__xformMultiply (grad->xform, t); - - nsvg__xformSetScale(t, sx, sy); - nsvg__xformMultiply (grad->xform, t); -} - -static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) -{ - NSVGshape* shape; - NSVGpath* path; - float tx, ty, sx, sy, us, bounds[4], t[6], avgs; - int i; - float* pt; - - // Guess image size if not set completely. - nsvg__imageBounds(p, bounds); - - if (p->viewWidth == 0) { - if (p->image->width > 0) { - p->viewWidth = p->image->width; - } else { - p->viewMinx = bounds[0]; - p->viewWidth = bounds[2] - bounds[0]; - } - } - if (p->viewHeight == 0) { - if (p->image->height > 0) { - p->viewHeight = p->image->height; - } else { - p->viewMiny = bounds[1]; - p->viewHeight = bounds[3] - bounds[1]; - } - } - if (p->image->width == 0) - p->image->width = p->viewWidth; - if (p->image->height == 0) - p->image->height = p->viewHeight; - - tx = -p->viewMinx; - ty = -p->viewMiny; - sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; - sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; - // Unit scaling - us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); - - // Fix aspect ratio - if (p->alignType == NSVG_ALIGN_MEET) { - // fit whole image into viewbox - sx = sy = nsvg__minf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; - } else if (p->alignType == NSVG_ALIGN_SLICE) { - // fill whole viewbox with image - sx = sy = nsvg__maxf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; - } - - // Transform - sx *= us; - sy *= us; - avgs = (sx+sy) / 2.0f; - for (shape = p->image->shapes; shape != NULL; shape = shape->next) { - shape->bounds[0] = (shape->bounds[0] + tx) * sx; - shape->bounds[1] = (shape->bounds[1] + ty) * sy; - shape->bounds[2] = (shape->bounds[2] + tx) * sx; - shape->bounds[3] = (shape->bounds[3] + ty) * sy; - for (path = shape->paths; path != NULL; path = path->next) { - path->bounds[0] = (path->bounds[0] + tx) * sx; - path->bounds[1] = (path->bounds[1] + ty) * sy; - path->bounds[2] = (path->bounds[2] + tx) * sx; - path->bounds[3] = (path->bounds[3] + ty) * sy; - for (i =0; i < path->npts; i++) { - pt = &path->pts[i*2]; - pt[0] = (pt[0] + tx) * sx; - pt[1] = (pt[1] + ty) * sy; - } - } - - if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); - memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); - nsvg__xformInverse(shape->fill.gradient->xform, t); - } - if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); - memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); - nsvg__xformInverse(shape->stroke.gradient->xform, t); - } - - shape->strokeWidth *= avgs; - shape->strokeDashOffset *= avgs; - for (i = 0; i < shape->strokeDashCount; i++) - shape->strokeDashArray[i] *= avgs; - } -} - -NSVGimage* nsvgParse(char* input, const char* units, float dpi) -{ - NSVGparser* p; - NSVGimage* ret = 0; - - p = nsvg__createParser(); - if (p == NULL) { - return NULL; - } - p->dpi = dpi; - - nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); - - // Scale to viewBox - nsvg__scaleToViewbox(p, units); - - ret = p->image; - p->image = NULL; - - nsvg__deleteParser(p); - - return ret; -} - -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) -{ - FILE* fp = NULL; - size_t size; - char* data = NULL; - NSVGimage* image = NULL; - - fp = fopen(filename, "rb"); - if (!fp) goto error; - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, 0, SEEK_SET); - data = (char*)malloc(size+1); - if (data == NULL) goto error; - if (fread(data, 1, size, fp) != size) goto error; - data[size] = '\0'; // Must be null terminated. - fclose(fp); - image = nsvgParse(data, units, dpi); - free(data); - - return image; +static unsigned int nsvg__parseColorName(const char *str) { + int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); + + for (i = 0; i < ncolors; i++) { + if (strcmp(nsvg__colors[i].name, str) == 0) { + return nsvg__colors[i].color; + } + } + + return NSVG_RGB(128, 128, 128); +} + +static unsigned int nsvg__parseColor(const char *str) { + size_t len = 0; + while (*str == ' ') + ++str; + len = strlen(str); + if (len >= 1 && *str == '#') + return nsvg__parseColorHex(str); + else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') + return nsvg__parseColorRGB(str); + return nsvg__parseColorName(str); +} + +static float nsvg__parseOpacity(const char *str) { + float val = nsvg__atof(str); + if (val < 0.0f) + val = 0.0f; + if (val > 1.0f) + val = 1.0f; + return val; +} + +static float nsvg__parseMiterLimit(const char *str) { + float val = nsvg__atof(str); + if (val < 0.0f) + val = 0.0f; + return val; +} + +static int nsvg__parseUnits(const char *units) { + if (units[0] == 'p' && units[1] == 'x') + return NSVG_UNITS_PX; + else if (units[0] == 'p' && units[1] == 't') + return NSVG_UNITS_PT; + else if (units[0] == 'p' && units[1] == 'c') + return NSVG_UNITS_PC; + else if (units[0] == 'm' && units[1] == 'm') + return NSVG_UNITS_MM; + else if (units[0] == 'c' && units[1] == 'm') + return NSVG_UNITS_CM; + else if (units[0] == 'i' && units[1] == 'n') + return NSVG_UNITS_IN; + else if (units[0] == '%') + return NSVG_UNITS_PERCENT; + else if (units[0] == 'e' && units[1] == 'm') + return NSVG_UNITS_EM; + else if (units[0] == 'e' && units[1] == 'x') + return NSVG_UNITS_EX; + return NSVG_UNITS_USER; +} + +static NSVGcoordinate nsvg__parseCoordinateRaw(const char *str) { + NSVGcoordinate coord = {0, NSVG_UNITS_USER}; + char buf[64]; + coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); + coord.value = nsvg__atof(buf); + return coord; +} + +static NSVGcoordinate nsvg__coord(float v, int units) { + NSVGcoordinate coord = {v, units}; + return coord; +} + +static float nsvg__parseCoordinate(NSVGparser *p, const char *str, float orig, float length) { + NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); + return nsvg__convertToPixels(p, coord, orig, length); +} + +static int nsvg__parseTransformArgs(const char *str, float *args, int maxNa, int *na) { + const char *end; + const char *ptr; + char it[64]; + + *na = 0; + ptr = str; + while (*ptr && *ptr != '(') + ++ptr; + if (*ptr == 0) + return 1; + end = ptr; + while (*end && *end != ')') + ++end; + if (*end == 0) + return 1; + + while (ptr < end) { + if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { + if (*na >= maxNa) + return 0; + ptr = nsvg__parseNumber(ptr, it, 64); + args[(*na)++] = (float)nsvg__atof(it); + } else { + ++ptr; + } + } + return (int)(end - str); +} + +static int nsvg__parseMatrix(float *xform, const char *str) { + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, t, 6, &na); + if (na != 6) + return len; + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseTranslate(float *xform, const char *str) { + float args[2]; + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) + args[1] = 0.0; + + nsvg__xformSetTranslation(t, args[0], args[1]); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseScale(float *xform, const char *str) { + float args[2]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) + args[1] = args[0]; + nsvg__xformSetScale(t, args[0], args[1]); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseSkewX(float *xform, const char *str) { + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewX(t, args[0] / 180.0f * NSVG_PI); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseSkewY(float *xform, const char *str) { + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewY(t, args[0] / 180.0f * NSVG_PI); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseRotate(float *xform, const char *str) { + float args[3]; + int na = 0; + float m[6]; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 3, &na); + if (na == 1) + args[1] = args[2] = 0.0f; + nsvg__xformIdentity(m); + + if (na > 1) { + nsvg__xformSetTranslation(t, -args[1], -args[2]); + nsvg__xformMultiply(m, t); + } + + nsvg__xformSetRotation(t, args[0] / 180.0f * NSVG_PI); + nsvg__xformMultiply(m, t); + + if (na > 1) { + nsvg__xformSetTranslation(t, args[1], args[2]); + nsvg__xformMultiply(m, t); + } + + memcpy(xform, m, sizeof(float) * 6); + + return len; +} + +static void nsvg__parseTransform(float *xform, const char *str) { + float t[6]; + nsvg__xformIdentity(xform); + while (*str) { + if (strncmp(str, "matrix", 6) == 0) + str += nsvg__parseMatrix(t, str); + else if (strncmp(str, "translate", 9) == 0) + str += nsvg__parseTranslate(t, str); + else if (strncmp(str, "scale", 5) == 0) + str += nsvg__parseScale(t, str); + else if (strncmp(str, "rotate", 6) == 0) + str += nsvg__parseRotate(t, str); + else if (strncmp(str, "skewX", 5) == 0) + str += nsvg__parseSkewX(t, str); + else if (strncmp(str, "skewY", 5) == 0) + str += nsvg__parseSkewY(t, str); + else { + ++str; + continue; + } + + nsvg__xformPremultiply(xform, t); + } +} + +static void nsvg__parseUrl(char *id, const char *str) { + int i = 0; + str += 4; // "url("; + if (*str == '#') + str++; + while (i < 63 && *str != ')') { + id[i] = *str++; + i++; + } + id[i] = '\0'; +} + +static char nsvg__parseLineCap(const char *str) { + if (strcmp(str, "butt") == 0) + return NSVG_CAP_BUTT; + else if (strcmp(str, "round") == 0) + return NSVG_CAP_ROUND; + else if (strcmp(str, "square") == 0) + return NSVG_CAP_SQUARE; + // TODO: handle inherit. + return NSVG_CAP_BUTT; +} + +static char nsvg__parseLineJoin(const char *str) { + if (strcmp(str, "miter") == 0) + return NSVG_JOIN_MITER; + else if (strcmp(str, "round") == 0) + return NSVG_JOIN_ROUND; + else if (strcmp(str, "bevel") == 0) + return NSVG_JOIN_BEVEL; + // TODO: handle inherit. + return NSVG_JOIN_MITER; +} + +static char nsvg__parseFillRule(const char *str) { + if (strcmp(str, "nonzero") == 0) + return NSVG_FILLRULE_NONZERO; + else if (strcmp(str, "evenodd") == 0) + return NSVG_FILLRULE_EVENODD; + // TODO: handle inherit. + return NSVG_FILLRULE_NONZERO; +} + +static const char *nsvg__getNextDashItem(const char *s, char *it) { + int n = 0; + it[0] = '\0'; + // Skip white spaces and commas + while (nsvg__isspace(*s) || *s == ',') + s++; + // Advance until whitespace, comma or end. + while (*s && (!nsvg__isspace(*s) && *s != ',')) { + if (n < 63) + it[n++] = *s; + s++; + } + it[n++] = '\0'; + return s; +} + +static int nsvg__parseStrokeDashArray(NSVGparser *p, const char *str, float *strokeDashArray) { + char item[64]; + int count = 0, i; + float sum = 0.0f; + + // Handle "none" + if (str[0] == 'n') + return 0; + + // Parse dashes + while (*str) { + str = nsvg__getNextDashItem(str, item); + if (!*item) + break; + if (count < NSVG_MAX_DASHES) + strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); + } + + for (i = 0; i < count; i++) + sum += strokeDashArray[i]; + if (sum <= 1e-6f) + count = 0; + + return count; +} + +static void nsvg__parseStyle(NSVGparser *p, const char *str); + +static int nsvg__parseAttr(NSVGparser *p, const char *name, const char *value) { + float xform[6]; + NSVGattrib *attr = nsvg__getAttr(p); + if (!attr) + return 0; + + if (strcmp(name, "style") == 0) { + nsvg__parseStyle(p, value); + } else if (strcmp(name, "display") == 0) { + if (strcmp(value, "none") == 0) + attr->visible = 0; + // Don't reset ->visible on display:inline, one display:none hides the whole subtree + + } else if (strcmp(name, "fill") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasFill = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasFill = 2; + nsvg__parseUrl(attr->fillGradient, value); + } else { + attr->hasFill = 1; + attr->fillColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "opacity") == 0) { + attr->opacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "fill-opacity") == 0) { + attr->fillOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasStroke = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasStroke = 2; + nsvg__parseUrl(attr->strokeGradient, value); + } else { + attr->hasStroke = 1; + attr->strokeColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "stroke-width") == 0) { + attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-dasharray") == 0) { + attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); + } else if (strcmp(name, "stroke-dashoffset") == 0) { + attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-opacity") == 0) { + attr->strokeOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke-linecap") == 0) { + attr->strokeLineCap = nsvg__parseLineCap(value); + } else if (strcmp(name, "stroke-linejoin") == 0) { + attr->strokeLineJoin = nsvg__parseLineJoin(value); + } else if (strcmp(name, "stroke-miterlimit") == 0) { + attr->miterLimit = nsvg__parseMiterLimit(value); + } else if (strcmp(name, "fill-rule") == 0) { + attr->fillRule = nsvg__parseFillRule(value); + } else if (strcmp(name, "font-size") == 0) { + attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "transform") == 0) { + nsvg__parseTransform(xform, value); + nsvg__xformPremultiply(attr->xform, xform); + } else if (strcmp(name, "stop-color") == 0) { + attr->stopColor = nsvg__parseColor(value); + } else if (strcmp(name, "stop-opacity") == 0) { + attr->stopOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "offset") == 0) { + attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); + } else if (strcmp(name, "id") == 0) { + strncpy(attr->id, value, 63); + attr->id[63] = '\0'; + } else { + return 0; + } + return 1; +} + +static int nsvg__parseNameValue(NSVGparser *p, const char *start, const char *end) { + const char *str; + const char *val; + char name[512]; + char value[512]; + int n; + + str = start; + while (str < end && *str != ':') + ++str; + + val = str; + + // Right Trim + while (str > start && (*str == ':' || nsvg__isspace(*str))) + --str; + ++str; + + n = (int)(str - start); + if (n > 511) + n = 511; + if (n) + memcpy(name, start, n); + name[n] = 0; + + while (val < end && (*val == ':' || nsvg__isspace(*val))) + ++val; + + n = (int)(end - val); + if (n > 511) + n = 511; + if (n) + memcpy(value, val, n); + value[n] = 0; + + return nsvg__parseAttr(p, name, value); +} + +static void nsvg__parseStyle(NSVGparser *p, const char *str) { + const char *start; + const char *end; + + while (*str) { + // Left Trim + while (nsvg__isspace(*str)) + ++str; + start = str; + while (*str && *str != ';') + ++str; + end = str; + + // Right Trim + while (end > start && (*end == ';' || nsvg__isspace(*end))) + --end; + ++end; + + nsvg__parseNameValue(p, start, end); + if (*str) + ++str; + } +} + +static void nsvg__parseAttribs(NSVGparser *p, const char **attr) { + int i; + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "style") == 0) + nsvg__parseStyle(p, attr[i + 1]); + else + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } +} + +static int nsvg__getArgsPerElement(char cmd) { + switch (cmd) { + case 'v': + case 'V': + case 'h': + case 'H': + return 1; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + return 2; + case 'q': + case 'Q': + case 's': + case 'S': + return 4; + case 'c': + case 'C': + return 6; + case 'a': + case 'A': + return 7; + } + return 0; +} + +static void nsvg__pathMoveTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__moveTo(p, *cpx, *cpy); +} + +static void nsvg__pathLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathHLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) + *cpx += args[0]; + else + *cpx = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathVLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) + *cpy += args[0]; + else + *cpy = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathCubicBezTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, + int rel) { + float x2, y2, cx1, cy1, cx2, cy2; + + if (rel) { + cx1 = *cpx + args[0]; + cy1 = *cpy + args[1]; + cx2 = *cpx + args[2]; + cy2 = *cpy + args[3]; + x2 = *cpx + args[4]; + y2 = *cpy + args[5]; + } else { + cx1 = args[0]; + cy1 = args[1]; + cx2 = args[2]; + cy2 = args[3]; + x2 = args[4]; + y2 = args[5]; + } + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathCubicBezShortTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, + int rel) { + float x1, y1, x2, y2, cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx2 = *cpx + args[0]; + cy2 = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx2 = args[0]; + cy2 = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + cx1 = 2 * x1 - *cpx2; + cy1 = 2 * y1 - *cpy2; + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel) { + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx = *cpx + args[0]; + cy = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx = args[0]; + cy = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + // Convert to cubic bezier + cx1 = x1 + 2.0f / 3.0f * (cx - x1); + cy1 = y1 + 2.0f / 3.0f * (cy - y1); + cx2 = x2 + 2.0f / 3.0f * (cx - x2); + cy2 = y2 + 2.0f / 3.0f * (cy - y2); + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezShortTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, + int rel) { + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + x2 = *cpx + args[0]; + y2 = *cpy + args[1]; + } else { + x2 = args[0]; + y2 = args[1]; + } + + cx = 2 * x1 - *cpx2; + cy = 2 * y1 - *cpy2; + + // Convert to cubix bezier + cx1 = x1 + 2.0f / 3.0f * (cx - x1); + cy1 = y1 + 2.0f / 3.0f * (cy - y1); + cx2 = x2 + 2.0f / 3.0f * (cx - x2); + cy2 = y2 + 2.0f / 3.0f * (cy - y2); + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static float nsvg__sqr(float x) { return x * x; } +static float nsvg__vmag(float x, float y) { return sqrtf(x * x + y * y); } + +static float nsvg__vecrat(float ux, float uy, float vx, float vy) { + return (ux * vx + uy * vy) / (nsvg__vmag(ux, uy) * nsvg__vmag(vx, vy)); +} + +static float nsvg__vecang(float ux, float uy, float vx, float vy) { + float r = nsvg__vecrat(ux, uy, vx, vy); + if (r < -1.0f) + r = -1.0f; + if (r > 1.0f) + r = 1.0f; + return ((ux * vy < uy * vx) ? -1.0f : 1.0f) * acosf(r); +} + +static void nsvg__pathArcTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + // Ported from canvg (https://code.google.com/p/canvg/) + float rx, ry, rotx; + float x1, y1, x2, y2, cx, cy, dx, dy, d; + float x1p, y1p, cxp, cyp, s, sa, sb; + float ux, uy, vx, vy, a1, da; + float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; + float sinrx, cosrx; + int fa, fs; + int i, ndivs; + float hda, kappa; + + rx = fabsf(args[0]); // y radius + ry = fabsf(args[1]); // x radius + rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle + fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc + fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction + x1 = *cpx; // start point + y1 = *cpy; + if (rel) { // end point + x2 = *cpx + args[5]; + y2 = *cpy + args[6]; + } else { + x2 = args[5]; + y2 = args[6]; + } + + dx = x1 - x2; + dy = y1 - y2; + d = sqrtf(dx * dx + dy * dy); + if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { + // The arc degenerates to a line + nsvg__lineTo(p, x2, y2); + *cpx = x2; + *cpy = y2; + return; + } + + sinrx = sinf(rotx); + cosrx = cosf(rotx); + + // Convert to center point parameterization. + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + // 1) Compute x1', y1' + x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; + y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; + d = nsvg__sqr(x1p) / nsvg__sqr(rx) + nsvg__sqr(y1p) / nsvg__sqr(ry); + if (d > 1) { + d = sqrtf(d); + rx *= d; + ry *= d; + } + // 2) Compute cx', cy' + s = 0.0f; + sa = nsvg__sqr(rx) * nsvg__sqr(ry) - nsvg__sqr(rx) * nsvg__sqr(y1p) - nsvg__sqr(ry) * nsvg__sqr(x1p); + sb = nsvg__sqr(rx) * nsvg__sqr(y1p) + nsvg__sqr(ry) * nsvg__sqr(x1p); + if (sa < 0.0f) + sa = 0.0f; + if (sb > 0.0f) + s = sqrtf(sa / sb); + if (fa == fs) + s = -s; + cxp = s * rx * y1p / ry; + cyp = s * -ry * x1p / rx; + + // 3) Compute cx,cy from cx',cy' + cx = (x1 + x2) / 2.0f + cosrx * cxp - sinrx * cyp; + cy = (y1 + y2) / 2.0f + sinrx * cxp + cosrx * cyp; + + // 4) Calculate theta1, and delta theta. + ux = (x1p - cxp) / rx; + uy = (y1p - cyp) / ry; + vx = (-x1p - cxp) / rx; + vy = (-y1p - cyp) / ry; + a1 = nsvg__vecang(1.0f, 0.0f, ux, uy); // Initial angle + da = nsvg__vecang(ux, uy, vx, vy); // Delta angle + + // if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; + // if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; + + if (fs == 0 && da > 0) + da -= 2 * NSVG_PI; + else if (fs == 1 && da < 0) + da += 2 * NSVG_PI; + + // Approximate the arc using cubic spline segments. + t[0] = cosrx; + t[1] = sinrx; + t[2] = -sinrx; + t[3] = cosrx; + t[4] = cx; + t[5] = cy; + + // Split arc into max 90 degree segments. + // The loop assumes an iteration per end point (including start and end), this +1. + ndivs = (int)(fabsf(da) / (NSVG_PI * 0.5f) + 1.0f); + hda = (da / (float)ndivs) / 2.0f; + kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); + if (da < 0.0f) + kappa = -kappa; + + for (i = 0; i <= ndivs; i++) { + a = a1 + da * ((float)i / (float)ndivs); + dx = cosf(a); + dy = sinf(a); + nsvg__xformPoint(&x, &y, dx * rx, dy * ry, t); // position + nsvg__xformVec(&tanx, &tany, -dy * rx * kappa, dx * ry * kappa, t); // tangent + if (i > 0) + nsvg__cubicBezTo(p, px + ptanx, py + ptany, x - tanx, y - tany, x, y); + px = x; + py = y; + ptanx = tanx; + ptany = tany; + } + + *cpx = x2; + *cpy = y2; +} + +static void nsvg__parsePath(NSVGparser *p, const char **attr) { + const char *s = NULL; + char cmd = '\0'; + float args[10]; + int nargs; + int rargs = 0; + float cpx, cpy, cpx2, cpy2; + const char *tmp[4]; + char closedFlag; + int i; + char item[64]; + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "d") == 0) { + s = attr[i + 1]; + } else { + tmp[0] = attr[i]; + tmp[1] = attr[i + 1]; + tmp[2] = 0; + tmp[3] = 0; + nsvg__parseAttribs(p, tmp); + } + } + + if (s) { + nsvg__resetPath(p); + cpx = 0; + cpy = 0; + cpx2 = 0; + cpy2 = 0; + closedFlag = 0; + nargs = 0; + + while (*s) { + item[0] = '\0'; + if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4)) + s = nsvg__getNextPathItemWhenArcFlag(s, item); + if (!*item) + s = nsvg__getNextPathItem(s, item); + if (!*item) + break; + if (nsvg__isnum(item[0])) { + if (nargs < 10) + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= rargs) { + switch (cmd) { + case 'm': + case 'M': + nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); + // Moveto can be followed by multiple coordinate pairs, + // which should be treated as linetos. + cmd = (cmd == 'm') ? 'l' : 'L'; + rargs = nsvg__getArgsPerElement(cmd); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'l': + case 'L': + nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'H': + case 'h': + nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'V': + case 'v': + nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'C': + case 'c': + nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); + break; + case 'S': + case 's': + nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); + break; + case 'Q': + case 'q': + nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); + break; + case 'T': + case 't': + nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); + break; + case 'A': + case 'a': + nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + default: + if (nargs >= 2) { + cpx = args[nargs - 2]; + cpy = args[nargs - 1]; + cpx2 = cpx; + cpy2 = cpy; + } + break; + } + nargs = 0; + } + } else { + // New command + if (nargs) { + NANOSVG_DEBUG("unfinished command '%c' %d/%d args\n", cmd, nargs, rargs); + } + cmd = item[0]; + rargs = nsvg__getArgsPerElement(cmd); + if (cmd == 'M' || cmd == 'm') { + // Commit path. + if (p->npts > 0) + nsvg__addPath(p, closedFlag); + // Start new subpath. + nsvg__resetPath(p); + closedFlag = 0; + nargs = 0; + } else if (cmd == 'Z' || cmd == 'z') { + closedFlag = 1; + // Commit path. + if (p->npts > 0) { + // Move current point to first point + cpx = p->pts[0]; + cpy = p->pts[1]; + cpx2 = cpx; + cpy2 = cpy; + nsvg__addPath(p, closedFlag); + } + // Start new subpath. + nsvg__resetPath(p); + nsvg__moveTo(p, cpx, cpy); + closedFlag = 0; + nargs = 0; + } + } + } + // Commit path. + if (p->npts) + nsvg__addPath(p, closedFlag); + } + + nsvg__addShape(p); +} + +static void nsvg__parseRect(NSVGparser *p, const char **attr) { + float x = 0.0f; + float y = 0.0f; + float w = 0.0f; + float h = 0.0f; + float rx = -1.0f; // marks not set + float ry = -1.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x") == 0) + x = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y") == 0) + y = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "width") == 0) + w = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p)); + if (strcmp(attr[i], "height") == 0) + h = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) + rx = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) + ry = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx < 0.0f && ry > 0.0f) + rx = ry; + if (ry < 0.0f && rx > 0.0f) + ry = rx; + if (rx < 0.0f) + rx = 0.0f; + if (ry < 0.0f) + ry = 0.0f; + if (rx > w / 2.0f) + rx = w / 2.0f; + if (ry > h / 2.0f) + ry = h / 2.0f; + + if (w != 0.0f && h != 0.0f) { + nsvg__resetPath(p); + + if (rx < 0.00001f || ry < 0.0001f) { + nsvg__moveTo(p, x, y); + nsvg__lineTo(p, x + w, y); + nsvg__lineTo(p, x + w, y + h); + nsvg__lineTo(p, x, y + h); + } else { + // Rounded rectangle + nsvg__moveTo(p, x + rx, y); + nsvg__lineTo(p, x + w - rx, y); + nsvg__cubicBezTo(p, x + w - rx * (1 - NSVG_KAPPA90), y, x + w, y + ry * (1 - NSVG_KAPPA90), x + w, y + ry); + nsvg__lineTo(p, x + w, y + h - ry); + nsvg__cubicBezTo(p, x + w, y + h - ry * (1 - NSVG_KAPPA90), x + w - rx * (1 - NSVG_KAPPA90), y + h, + x + w - rx, y + h); + nsvg__lineTo(p, x + rx, y + h); + nsvg__cubicBezTo(p, x + rx * (1 - NSVG_KAPPA90), y + h, x, y + h - ry * (1 - NSVG_KAPPA90), x, y + h - ry); + nsvg__lineTo(p, x, y + ry); + nsvg__cubicBezTo(p, x, y + ry * (1 - NSVG_KAPPA90), x + rx * (1 - NSVG_KAPPA90), y, x + rx, y); + } + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseCircle(NSVGparser *p, const char **attr) { + float cx = 0.0f; + float cy = 0.0f; + float r = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) + cx = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) + cy = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "r") == 0) + r = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualLength(p))); + } + } + + if (r > 0.0f) { + nsvg__resetPath(p); + + nsvg__moveTo(p, cx + r, cy); + nsvg__cubicBezTo(p, cx + r, cy + r * NSVG_KAPPA90, cx + r * NSVG_KAPPA90, cy + r, cx, cy + r); + nsvg__cubicBezTo(p, cx - r * NSVG_KAPPA90, cy + r, cx - r, cy + r * NSVG_KAPPA90, cx - r, cy); + nsvg__cubicBezTo(p, cx - r, cy - r * NSVG_KAPPA90, cx - r * NSVG_KAPPA90, cy - r, cx, cy - r); + nsvg__cubicBezTo(p, cx + r * NSVG_KAPPA90, cy - r, cx + r, cy - r * NSVG_KAPPA90, cx + r, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseEllipse(NSVGparser *p, const char **attr) { + float cx = 0.0f; + float cy = 0.0f; + float rx = 0.0f; + float ry = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) + cx = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) + cy = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) + rx = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) + ry = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx > 0.0f && ry > 0.0f) { + + nsvg__resetPath(p); + + nsvg__moveTo(p, cx + rx, cy); + nsvg__cubicBezTo(p, cx + rx, cy + ry * NSVG_KAPPA90, cx + rx * NSVG_KAPPA90, cy + ry, cx, cy + ry); + nsvg__cubicBezTo(p, cx - rx * NSVG_KAPPA90, cy + ry, cx - rx, cy + ry * NSVG_KAPPA90, cx - rx, cy); + nsvg__cubicBezTo(p, cx - rx, cy - ry * NSVG_KAPPA90, cx - rx * NSVG_KAPPA90, cy - ry, cx, cy - ry); + nsvg__cubicBezTo(p, cx + rx * NSVG_KAPPA90, cy - ry, cx + rx, cy - ry * NSVG_KAPPA90, cx + rx, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseLine(NSVGparser *p, const char **attr) { + float x1 = 0.0; + float y1 = 0.0; + float x2 = 0.0; + float y2 = 0.0; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x1") == 0) + x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y1") == 0) + y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "x2") == 0) + x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y2") == 0) + y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + } + } + + nsvg__resetPath(p); + + nsvg__moveTo(p, x1, y1); + nsvg__lineTo(p, x2, y2); + + nsvg__addPath(p, 0); + + nsvg__addShape(p); +} + +static void nsvg__parsePoly(NSVGparser *p, const char **attr, int closeFlag) { + int i; + const char *s; + float args[2]; + int nargs, npts = 0; + char item[64]; + + nsvg__resetPath(p); + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "points") == 0) { + s = attr[i + 1]; + nargs = 0; + while (*s) { + s = nsvg__getNextPathItem(s, item); + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= 2) { + if (npts == 0) + nsvg__moveTo(p, args[0], args[1]); + else + nsvg__lineTo(p, args[0], args[1]); + nargs = 0; + npts++; + } + } + } + } + } + + nsvg__addPath(p, (char)closeFlag); + + nsvg__addShape(p); +} + +static void nsvg__parseSVG(NSVGparser *p, const char **attr) { + int i; + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "width") == 0) { + p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "height") == 0) { + p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "viewBox") == 0) { + const char *s = attr[i + 1]; + char buf[64]; + s = nsvg__parseNumber(s, buf, 64); + p->viewMinx = nsvg__atof(buf); + while (nsvg__isspace(*s) || *s == '%' || *s == ',') + s++; + if (!*s) + return; + s = nsvg__parseNumber(s, buf, 64); + p->viewMiny = nsvg__atof(buf); + while (nsvg__isspace(*s) || *s == '%' || *s == ',') + s++; + if (!*s) + return; + s = nsvg__parseNumber(s, buf, 64); + p->viewWidth = nsvg__atof(buf); + while (nsvg__isspace(*s) || *s == '%' || *s == ',') + s++; + if (!*s) + return; + s = nsvg__parseNumber(s, buf, 64); + p->viewHeight = nsvg__atof(buf); + } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { + if (strstr(attr[i + 1], "none") != 0) { + // No uniform scaling + p->alignType = NSVG_ALIGN_NONE; + } else { + // Parse X align + if (strstr(attr[i + 1], "xMin") != 0) + p->alignX = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "xMid") != 0) + p->alignX = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "xMax") != 0) + p->alignX = NSVG_ALIGN_MAX; + // Parse X align + if (strstr(attr[i + 1], "yMin") != 0) + p->alignY = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "yMid") != 0) + p->alignY = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "yMax") != 0) + p->alignY = NSVG_ALIGN_MAX; + // Parse meet/slice + p->alignType = NSVG_ALIGN_MEET; + if (strstr(attr[i + 1], "slice") != 0) + p->alignType = NSVG_ALIGN_SLICE; + } + } + } + } +} + +static void nsvg__parseGradient(NSVGparser *p, const char **attr, char type) { + int i; + NSVGgradientData *grad = (NSVGgradientData *)malloc(sizeof(NSVGgradientData)); + if (grad == NULL) + return; + memset(grad, 0, sizeof(NSVGgradientData)); + grad->units = NSVG_OBJECT_SPACE; + grad->type = type; + if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { + grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); + grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { + grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + } + + nsvg__xformIdentity(grad->xform); + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "id") == 0) { + strncpy(grad->id, attr[i + 1], 63); + grad->id[63] = '\0'; + } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "gradientUnits") == 0) { + if (strcmp(attr[i + 1], "objectBoundingBox") == 0) + grad->units = NSVG_OBJECT_SPACE; + else + grad->units = NSVG_USER_SPACE; + } else if (strcmp(attr[i], "gradientTransform") == 0) { + nsvg__parseTransform(grad->xform, attr[i + 1]); + } else if (strcmp(attr[i], "cx") == 0) { + grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "cy") == 0) { + grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "r") == 0) { + grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fx") == 0) { + grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fy") == 0) { + grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x1") == 0) { + grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y1") == 0) { + grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x2") == 0) { + grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y2") == 0) { + grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "spreadMethod") == 0) { + if (strcmp(attr[i + 1], "pad") == 0) + grad->spread = NSVG_SPREAD_PAD; + else if (strcmp(attr[i + 1], "reflect") == 0) + grad->spread = NSVG_SPREAD_REFLECT; + else if (strcmp(attr[i + 1], "repeat") == 0) + grad->spread = NSVG_SPREAD_REPEAT; + } else if (strcmp(attr[i], "xlink:href") == 0) { + const char *href = attr[i + 1]; + strncpy(grad->ref, href + 1, 62); + grad->ref[62] = '\0'; + } + } + } + + grad->next = p->gradients; + p->gradients = grad; +} + +static void nsvg__parseGradientStop(NSVGparser *p, const char **attr) { + NSVGattrib *curAttr = nsvg__getAttr(p); + NSVGgradientData *grad; + NSVGgradientStop *stop; + int i, idx; + + curAttr->stopOffset = 0; + curAttr->stopColor = 0; + curAttr->stopOpacity = 1.0f; + + for (i = 0; attr[i]; i += 2) { + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } + + // Add stop to the last gradient. + grad = p->gradients; + if (grad == NULL) + return; + + grad->nstops++; + grad->stops = (NSVGgradientStop *)realloc(grad->stops, sizeof(NSVGgradientStop) * grad->nstops); + if (grad->stops == NULL) + return; + + // Insert + idx = grad->nstops - 1; + for (i = 0; i < grad->nstops - 1; i++) { + if (curAttr->stopOffset < grad->stops[i].offset) { + idx = i; + break; + } + } + if (idx != grad->nstops - 1) { + for (i = grad->nstops - 1; i > idx; i--) + grad->stops[i] = grad->stops[i - 1]; + } + + stop = &grad->stops[idx]; + stop->color = curAttr->stopColor; + stop->color |= (unsigned int)(curAttr->stopOpacity * 255) << 24; + stop->offset = curAttr->stopOffset; +} + +static void nsvg__startElement(void *ud, const char *el, const char **attr) { + NSVGparser *p = (NSVGparser *)ud; + + if (p->defsFlag) { + // Skip everything but gradients in defs + if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } + return; + } + + if (strcmp(el, "g") == 0) { + nsvg__pushAttr(p); + nsvg__parseAttribs(p, attr); + } else if (strcmp(el, "path") == 0) { + if (p->pathFlag) // Do not allow nested paths. + return; + nsvg__pushAttr(p); + nsvg__parsePath(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "rect") == 0) { + nsvg__pushAttr(p); + nsvg__parseRect(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "circle") == 0) { + nsvg__pushAttr(p); + nsvg__parseCircle(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "ellipse") == 0) { + nsvg__pushAttr(p); + nsvg__parseEllipse(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "line") == 0) { + nsvg__pushAttr(p); + nsvg__parseLine(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "polyline") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 0); + nsvg__popAttr(p); + } else if (strcmp(el, "polygon") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 1); + nsvg__popAttr(p); + } else if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 1; + } else if (strcmp(el, "svg") == 0) { + nsvg__parseSVG(p, attr); + } +} + +static void nsvg__endElement(void *ud, const char *el) { + NSVGparser *p = (NSVGparser *)ud; + + if (strcmp(el, "g") == 0) { + nsvg__popAttr(p); + } else if (strcmp(el, "path") == 0) { + p->pathFlag = 0; + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 0; + } +} + +static void nsvg__content(void *ud, const char *s) { + NSVG_NOTUSED(ud); + NSVG_NOTUSED(s); + // empty +} + +static void nsvg__imageBounds(NSVGparser *p, float *bounds) { + NSVGshape *shape; + shape = p->image->shapes; + if (shape == NULL) { + bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; + return; + } + bounds[0] = shape->bounds[0]; + bounds[1] = shape->bounds[1]; + bounds[2] = shape->bounds[2]; + bounds[3] = shape->bounds[3]; + for (shape = shape->next; shape != NULL; shape = shape->next) { + bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); + bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); + bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); + bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); + } +} + +static float nsvg__viewAlign(float content, float container, int type) { + if (type == NSVG_ALIGN_MIN) + return 0; + else if (type == NSVG_ALIGN_MAX) + return container - content; + // mid + return (container - content) * 0.5f; +} + +static void nsvg__scaleGradient(NSVGgradient *grad, float tx, float ty, float sx, float sy) { + float t[6]; + nsvg__xformSetTranslation(t, tx, ty); + nsvg__xformMultiply(grad->xform, t); + + nsvg__xformSetScale(t, sx, sy); + nsvg__xformMultiply(grad->xform, t); +} + +static void nsvg__scaleToViewbox(NSVGparser *p, const char *units) { + NSVGshape *shape; + NSVGpath *path; + float tx, ty, sx, sy, us, bounds[4], t[6], avgs; + int i; + float *pt; + + // Guess image size if not set completely. + nsvg__imageBounds(p, bounds); + + if (p->viewWidth == 0) { + if (p->image->width > 0) { + p->viewWidth = p->image->width; + } else { + p->viewMinx = bounds[0]; + p->viewWidth = bounds[2] - bounds[0]; + } + } + if (p->viewHeight == 0) { + if (p->image->height > 0) { + p->viewHeight = p->image->height; + } else { + p->viewMiny = bounds[1]; + p->viewHeight = bounds[3] - bounds[1]; + } + } + if (p->image->width == 0) + p->image->width = p->viewWidth; + if (p->image->height == 0) + p->image->height = p->viewHeight; + + tx = -p->viewMinx; + ty = -p->viewMiny; + sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; + sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; + // Unit scaling + us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); + + // Fix aspect ratio + if (p->alignType == NSVG_ALIGN_MEET) { + // fit whole image into viewbox + sx = sy = nsvg__minf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth * sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight * sy, p->image->height, p->alignY) / sy; + } else if (p->alignType == NSVG_ALIGN_SLICE) { + // fill whole viewbox with image + sx = sy = nsvg__maxf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth * sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight * sy, p->image->height, p->alignY) / sy; + } + + // Transform + sx *= us; + sy *= us; + avgs = (sx + sy) / 2.0f; + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + shape->bounds[0] = (shape->bounds[0] + tx) * sx; + shape->bounds[1] = (shape->bounds[1] + ty) * sy; + shape->bounds[2] = (shape->bounds[2] + tx) * sx; + shape->bounds[3] = (shape->bounds[3] + ty) * sy; + for (path = shape->paths; path != NULL; path = path->next) { + path->bounds[0] = (path->bounds[0] + tx) * sx; + path->bounds[1] = (path->bounds[1] + ty) * sy; + path->bounds[2] = (path->bounds[2] + tx) * sx; + path->bounds[3] = (path->bounds[3] + ty) * sy; + for (i = 0; i < path->npts; i++) { + pt = &path->pts[i * 2]; + pt[0] = (pt[0] + tx) * sx; + pt[1] = (pt[1] + ty) * sy; + } + } + + if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->fill.gradient, tx, ty, sx, sy); + memcpy(t, shape->fill.gradient->xform, sizeof(float) * 6); + nsvg__xformInverse(shape->fill.gradient->xform, t); + } + if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->stroke.gradient, tx, ty, sx, sy); + memcpy(t, shape->stroke.gradient->xform, sizeof(float) * 6); + nsvg__xformInverse(shape->stroke.gradient->xform, t); + } + + shape->strokeWidth *= avgs; + shape->strokeDashOffset *= avgs; + for (i = 0; i < shape->strokeDashCount; i++) + shape->strokeDashArray[i] *= avgs; + } +} + +NSVGimage *nsvgParse(char *input, const char *units, float dpi) { + NSVGparser *p; + NSVGimage *ret = 0; + + p = nsvg__createParser(); + if (p == NULL) { + return NULL; + } + p->dpi = dpi; + + nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); + + // Scale to viewBox + nsvg__scaleToViewbox(p, units); + + ret = p->image; + p->image = NULL; + + nsvg__deleteParser(p); + + return ret; +} + +NSVGimage *nsvgParseFromFile(const char *filename, const char *units, float dpi) { + FILE *fp = NULL; + size_t size; + char *data = NULL; + NSVGimage *image = NULL; + + fp = fopen(filename, "rb"); + if (!fp) + goto error; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + data = (char *)malloc(size + 1); + if (data == NULL) + goto error; + if (fread(data, 1, size, fp) != size) + goto error; + data[size] = '\0'; // Must be null terminated. + fclose(fp); + image = nsvgParse(data, units, dpi); + free(data); + + return image; error: - if (fp) fclose(fp); - if (data) free(data); - if (image) nsvgDelete(image); - return NULL; + if (fp) + fclose(fp); + if (data) + free(data); + if (image) + nsvgDelete(image); + return NULL; } -NSVGpath* nsvgDuplicatePath(NSVGpath* p) -{ - NSVGpath* res = NULL; +NSVGpath *nsvgDuplicatePath(NSVGpath *p) { + NSVGpath *res = NULL; - if (p == NULL) - return NULL; + if (p == NULL) + return NULL; - res = (NSVGpath*)malloc(sizeof(NSVGpath)); - if (res == NULL) goto error; - memset(res, 0, sizeof(NSVGpath)); + res = (NSVGpath *)malloc(sizeof(NSVGpath)); + if (res == NULL) + goto error; + memset(res, 0, sizeof(NSVGpath)); - res->pts = (float*)malloc(p->npts*2*sizeof(float)); - if (res->pts == NULL) goto error; - memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); - res->npts = p->npts; + res->pts = (float *)malloc(p->npts * 2 * sizeof(float)); + if (res->pts == NULL) + goto error; + memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); + res->npts = p->npts; - memcpy(res->bounds, p->bounds, sizeof(p->bounds)); + memcpy(res->bounds, p->bounds, sizeof(p->bounds)); - res->closed = p->closed; + res->closed = p->closed; - return res; + return res; error: - if (res != NULL) { - free(res->pts); - free(res); - } - return NULL; -} - -void nsvgDelete(NSVGimage* image) -{ - NSVGshape *snext, *shape; - if (image == NULL) return; - shape = image->shapes; - while (shape != NULL) { - snext = shape->next; - nsvg__deletePaths(shape->paths); - nsvg__deletePaint(&shape->fill); - nsvg__deletePaint(&shape->stroke); - free(shape); - shape = snext; - } - free(image); + if (res != NULL) { + free(res->pts); + free(res); + } + return NULL; +} + +void nsvgDelete(NSVGimage *image) { + NSVGshape *snext, *shape; + if (image == NULL) + return; + shape = image->shapes; + while (shape != NULL) { + snext = shape->next; + nsvg__deletePaths(shape->paths); + nsvg__deletePaint(&shape->fill); + nsvg__deletePaint(&shape->stroke); + free(shape); + shape = snext; + } + free(image); } #endif diff --git a/src/nsvg/vkvg_nsvg.c b/src/nsvg/vkvg_nsvg.c index 681471a..1e37caa 100644 --- a/src/nsvg/vkvg_nsvg.c +++ b/src/nsvg/vkvg_nsvg.c @@ -23,120 +23,114 @@ #include "vkvg_device_internal.h" #include "vkvg_context_internal.h" -#define NANOSVG_IMPLEMENTATION // Expands implementation +#define NANOSVG_IMPLEMENTATION // Expands implementation #include "nanosvg.h" #include "vkvg-svg.h" -void _svg_set_color (VkvgContext ctx, uint32_t c, float alpha) { - float a = (c >> 24 & 255) / 255.f; - float b = (c >> 16 & 255) / 255.f; - float g = (c >> 8 & 255) / 255.f; - float r = (c & 255) / 255.f; - vkvg_set_source_rgba(ctx,r,g,b,a*alpha); +void _svg_set_color(VkvgContext ctx, uint32_t c, float alpha) { + float a = (c >> 24 & 255) / 255.f; + float b = (c >> 16 & 255) / 255.f; + float g = (c >> 8 & 255) / 255.f; + float r = (c & 255) / 255.f; + vkvg_set_source_rgba(ctx, r, g, b, a * alpha); } -VkvgSurface _svg_load (VkvgDevice dev, NSVGimage* svg) { - if (svg == NULL) { - LOG(VKVG_LOG_ERR, "nsvg error"); - return NULL; - } - VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); - if (!surf) - return NULL; +VkvgSurface _svg_load(VkvgDevice dev, NSVGimage *svg) { + if (svg == NULL) { + LOG(VKVG_LOG_ERR, "nsvg error"); + return NULL; + } + VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); + if (!surf) + return NULL; - surf->width = (uint32_t)svg->width; - surf->height = (uint32_t)svg->height; - surf->newSurf = true; + surf->width = (uint32_t)svg->width; + surf->height = (uint32_t)svg->height; + surf->newSurf = true; - _create_surface_images (surf); + _create_surface_images(surf); - VkvgContext ctx = vkvg_create(surf); - vkvg_svg_render(svg, ctx, NULL); - vkvg_destroy(ctx); + VkvgContext ctx = vkvg_create(surf); + vkvg_svg_render(svg, ctx, NULL); + vkvg_destroy(ctx); - nsvgDelete(svg); + nsvgDelete(svg); - surf->references = 1; - vkvg_device_reference (surf->dev); + surf->references = 1; + vkvg_device_reference(surf->dev); - return surf; + return surf; } -VkvgSurface vkvg_surface_create_from_svg (VkvgDevice dev, uint32_t width, uint32_t height, const char* filePath) { - return _svg_load(dev, nsvgParseFromFile(filePath, "px", (float)dev->hdpi)); +VkvgSurface vkvg_surface_create_from_svg(VkvgDevice dev, uint32_t width, uint32_t height, const char *filePath) { + return _svg_load(dev, nsvgParseFromFile(filePath, "px", (float)dev->hdpi)); } -VkvgSurface vkvg_surface_create_from_svg_fragment (VkvgDevice dev, uint32_t width, uint32_t height, char* svgFragment) { - return _svg_load(dev, nsvgParse(svgFragment, "px", (float)dev->hdpi)); +VkvgSurface vkvg_surface_create_from_svg_fragment(VkvgDevice dev, uint32_t width, uint32_t height, char *svgFragment) { + return _svg_load(dev, nsvgParse(svgFragment, "px", (float)dev->hdpi)); } -VkvgSvg vkvg_svg_load (const char* svgFilePath) { - return nsvgParseFromFile(svgFilePath, "px", 96.0f); -} -VkvgSvg vkvg_svg_load_fragment (char* svgFragment) { - return nsvgParse (svgFragment, "px", 96.0f); -} -void vkvg_svg_destroy (VkvgSvg svg) { - nsvgDelete(svg); -} -void vkvg_svg_get_dimensions (VkvgSvg svg, uint32_t* width, uint32_t* height) { - *width = (uint32_t)svg->width; - *height = (uint32_t)svg->height; +VkvgSvg vkvg_svg_load(const char *svgFilePath) { return nsvgParseFromFile(svgFilePath, "px", 96.0f); } +VkvgSvg vkvg_svg_load_fragment(char *svgFragment) { return nsvgParse(svgFragment, "px", 96.0f); } +void vkvg_svg_destroy(VkvgSvg svg) { nsvgDelete(svg); } +void vkvg_svg_get_dimensions(VkvgSvg svg, uint32_t *width, uint32_t *height) { + *width = (uint32_t)svg->width; + *height = (uint32_t)svg->height; } -void vkvg_svg_render (VkvgSvg svg, VkvgContext ctx, const char* subId){ - NSVGshape* shape; - NSVGpath* path; - vkvg_save (ctx); - - vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_EVEN_ODD); - - vkvg_set_source_rgba(ctx,0.0,0.0,0.0,1); - - for (shape = svg->shapes; shape != NULL; shape = shape->next) { - if (subId != NULL) { - if (strcmp(shape->id, subId)!=0) - continue; - } - - vkvg_new_path(ctx); - - float o = shape->opacity; - - vkvg_set_line_width(ctx, shape->strokeWidth); - - for (path = shape->paths; path != NULL; path = path->next) { - float* p = path->pts; - vkvg_move_to(ctx, p[0],p[1]); - for (int i = 1; i < path->npts; i += 3) { - p = &path->pts[i*2]; - vkvg_curve_to(ctx, p[0],p[1], p[2],p[3], p[4],p[5]); - } - if (path->closed) - vkvg_close_path(ctx); - } - - if (shape->fill.type == NSVG_PAINT_COLOR) - _svg_set_color(ctx, shape->fill.color, o); - else if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT){ - NSVGgradient* g = shape->fill.gradient; - _svg_set_color(ctx, g->stops[0].color, o); - } - - if (shape->fill.type != NSVG_PAINT_NONE){ - if (shape->stroke.type == NSVG_PAINT_NONE){ - vkvg_fill(ctx); - continue; - } - vkvg_fill_preserve (ctx); - } - - if (shape->stroke.type == NSVG_PAINT_COLOR) - _svg_set_color(ctx, shape->stroke.color, o); - else if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT){ - NSVGgradient* g = shape->stroke.gradient; - _svg_set_color(ctx, g->stops[0].color, o); - } - - vkvg_stroke(ctx); - } - vkvg_restore (ctx); +void vkvg_svg_render(VkvgSvg svg, VkvgContext ctx, const char *subId) { + NSVGshape *shape; + NSVGpath *path; + vkvg_save(ctx); + + vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_EVEN_ODD); + + vkvg_set_source_rgba(ctx, 0.0, 0.0, 0.0, 1); + + for (shape = svg->shapes; shape != NULL; shape = shape->next) { + if (subId != NULL) { + if (strcmp(shape->id, subId) != 0) + continue; + } + + vkvg_new_path(ctx); + + float o = shape->opacity; + + vkvg_set_line_width(ctx, shape->strokeWidth); + + for (path = shape->paths; path != NULL; path = path->next) { + float *p = path->pts; + vkvg_move_to(ctx, p[0], p[1]); + for (int i = 1; i < path->npts; i += 3) { + p = &path->pts[i * 2]; + vkvg_curve_to(ctx, p[0], p[1], p[2], p[3], p[4], p[5]); + } + if (path->closed) + vkvg_close_path(ctx); + } + + if (shape->fill.type == NSVG_PAINT_COLOR) + _svg_set_color(ctx, shape->fill.color, o); + else if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT) { + NSVGgradient *g = shape->fill.gradient; + _svg_set_color(ctx, g->stops[0].color, o); + } + + if (shape->fill.type != NSVG_PAINT_NONE) { + if (shape->stroke.type == NSVG_PAINT_NONE) { + vkvg_fill(ctx); + continue; + } + vkvg_fill_preserve(ctx); + } + + if (shape->stroke.type == NSVG_PAINT_COLOR) + _svg_set_color(ctx, shape->stroke.color, o); + else if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT) { + NSVGgradient *g = shape->stroke.gradient; + _svg_set_color(ctx, g->stops[0].color, o); + } + + vkvg_stroke(ctx); + } + vkvg_restore(ctx); } diff --git a/src/recording/vkvg_record.c b/src/recording/vkvg_record.c index a70ee18..9184b5f 100644 --- a/src/recording/vkvg_record.c +++ b/src/recording/vkvg_record.c @@ -25,53 +25,52 @@ #include "vkvg_record_internal.h" #ifdef VKVG_RECORDING -void vkvg_start_recording (VkvgContext ctx) { - if (ctx->status) - return; - _start_recording(ctx); +void vkvg_start_recording(VkvgContext ctx) { + if (ctx->status) + return; + _start_recording(ctx); } -VkvgRecording vkvg_stop_recording (VkvgContext ctx) { - if (ctx->status) - return NULL; - return _stop_recording (ctx); +VkvgRecording vkvg_stop_recording(VkvgContext ctx) { + if (ctx->status) + return NULL; + return _stop_recording(ctx); } -uint32_t vkvg_recording_get_count (VkvgRecording rec) { - if (!rec) - return 0; - return rec->commandsCount; +uint32_t vkvg_recording_get_count(VkvgRecording rec) { + if (!rec) + return 0; + return rec->commandsCount; } -void* vkvg_recording_get_data (VkvgRecording rec) { - if (!rec) - return 0; - return rec->buffer; +void *vkvg_recording_get_data(VkvgRecording rec) { + if (!rec) + return 0; + return rec->buffer; } -void vkvg_recording_get_command (VkvgRecording rec, uint32_t cmdIndex, uint32_t* cmd, void** dataOffset) { - if (!rec) - return; - if (cmdIndex < rec->commandsCount) { - *cmd = rec->commands[cmdIndex].cmd; - *dataOffset = (void*)rec->commands[cmdIndex].dataOffset; - } else { - *cmd = 0; - *dataOffset = NULL; - } - +void vkvg_recording_get_command(VkvgRecording rec, uint32_t cmdIndex, uint32_t *cmd, void **dataOffset) { + if (!rec) + return; + if (cmdIndex < rec->commandsCount) { + *cmd = rec->commands[cmdIndex].cmd; + *dataOffset = (void *)rec->commands[cmdIndex].dataOffset; + } else { + *cmd = 0; + *dataOffset = NULL; + } } -void vkvg_replay (VkvgContext ctx, VkvgRecording rec) { - if (!rec) - return; - for (uint32_t i=0; icommandsCount; i++) - _replay_command(ctx, rec, i); +void vkvg_replay(VkvgContext ctx, VkvgRecording rec) { + if (!rec) + return; + for (uint32_t i = 0; i < rec->commandsCount; i++) + _replay_command(ctx, rec, i); } -void vkvg_replay_command (VkvgContext ctx, VkvgRecording rec, uint32_t cmdIndex) { - if (!rec) - return; - if (cmdIndex < rec->commandsCount) - _replay_command(ctx, rec, cmdIndex); +void vkvg_replay_command(VkvgContext ctx, VkvgRecording rec, uint32_t cmdIndex) { + if (!rec) + return; + if (cmdIndex < rec->commandsCount) + _replay_command(ctx, rec, cmdIndex); } -void vkvg_recording_destroy (VkvgRecording rec) { - if (!rec) - return; - _destroy_recording(rec); +void vkvg_recording_destroy(VkvgRecording rec) { + if (!rec) + return; + _destroy_recording(rec); } #endif diff --git a/src/recording/vkvg_record_internal.c b/src/recording/vkvg_record_internal.c index 29c91c9..e30363c 100644 --- a/src/recording/vkvg_record_internal.c +++ b/src/recording/vkvg_record_internal.c @@ -24,429 +24,419 @@ #include "vkvg_record_internal.h" #include "vkvg_context_internal.h" -#define VKVG_RECORDING_INIT_BUFFER_SIZE_TRESHOLD 64 -#define VKVG_RECORDING_INIT_BUFFER_SIZE 1024 -#define VKVG_RECORDING_INIT_COMMANDS_COUNT 64 +#define VKVG_RECORDING_INIT_BUFFER_SIZE_TRESHOLD 64 +#define VKVG_RECORDING_INIT_BUFFER_SIZE 1024 +#define VKVG_RECORDING_INIT_COMMANDS_COUNT 64 -vkvg_recording_t* _new_recording () { +vkvg_recording_t *_new_recording() { - vkvg_recording_t* rec = (vkvg_recording_t*)calloc(1,sizeof (vkvg_recording_t)); + vkvg_recording_t *rec = (vkvg_recording_t *)calloc(1, sizeof(vkvg_recording_t)); - rec->commandsReservedCount = VKVG_RECORDING_INIT_COMMANDS_COUNT; - rec->bufferReservedSize = VKVG_RECORDING_INIT_BUFFER_SIZE; - rec->commands = (vkvg_record_t*)malloc(rec->commandsReservedCount * sizeof (vkvg_record_t)); - rec->buffer = malloc (rec->bufferReservedSize); + rec->commandsReservedCount = VKVG_RECORDING_INIT_COMMANDS_COUNT; + rec->bufferReservedSize = VKVG_RECORDING_INIT_BUFFER_SIZE; + rec->commands = (vkvg_record_t *)malloc(rec->commandsReservedCount * sizeof(vkvg_record_t)); + rec->buffer = malloc(rec->bufferReservedSize); - return rec; + return rec; } -void _destroy_recording (vkvg_recording_t* rec) { - if (!rec) - return; - for (uint32_t i=0; icommandsCount; i++) { - if (rec->commands[i].cmd == VKVG_CMD_SET_SOURCE) - vkvg_pattern_destroy((VkvgPattern)(rec->buffer + rec->commands[i].dataOffset)); - else if (rec->commands[i].cmd == VKVG_CMD_SET_SOURCE_SURFACE) - vkvg_surface_destroy ((VkvgSurface)(rec->buffer + rec->commands[i].dataOffset + 2 * sizeof(float))); - } - free(rec->commands); - free(rec->buffer); - free(rec); +void _destroy_recording(vkvg_recording_t *rec) { + if (!rec) + return; + for (uint32_t i = 0; i < rec->commandsCount; i++) { + if (rec->commands[i].cmd == VKVG_CMD_SET_SOURCE) + vkvg_pattern_destroy((VkvgPattern)(rec->buffer + rec->commands[i].dataOffset)); + else if (rec->commands[i].cmd == VKVG_CMD_SET_SOURCE_SURFACE) + vkvg_surface_destroy((VkvgSurface)(rec->buffer + rec->commands[i].dataOffset + 2 * sizeof(float))); + } + free(rec->commands); + free(rec->buffer); + free(rec); } -void _start_recording (VkvgContext ctx) { - if (ctx->recording) - _destroy_recording(ctx->recording); - ctx->recording = _new_recording(); +void _start_recording(VkvgContext ctx) { + if (ctx->recording) + _destroy_recording(ctx->recording); + ctx->recording = _new_recording(); } -vkvg_recording_t* _stop_recording (VkvgContext ctx) { - vkvg_recording_t* rec = ctx->recording; - if (!rec) - return NULL; - if (!rec->commandsCount) { - _destroy_recording(rec); - ctx->recording = NULL; - return NULL; - } - /*rec->buffer = realloc(rec->buffer, rec->bufferSize); - rec->commands = (vkvg_record_t*)realloc(rec->commands, rec->commandsCount * sizeof (vkvg_record_t));*/ - ctx->recording = NULL; - return rec; +vkvg_recording_t *_stop_recording(VkvgContext ctx) { + vkvg_recording_t *rec = ctx->recording; + if (!rec) + return NULL; + if (!rec->commandsCount) { + _destroy_recording(rec); + ctx->recording = NULL; + return NULL; + } + /*rec->buffer = realloc(rec->buffer, rec->bufferSize); + rec->commands = (vkvg_record_t*)realloc(rec->commands, rec->commandsCount * sizeof (vkvg_record_t));*/ + ctx->recording = NULL; + return rec; } -void* _ensure_recording_buffer (vkvg_recording_t* rec, size_t size) { - if (rec->bufferReservedSize >= rec->bufferSize - VKVG_RECORDING_INIT_BUFFER_SIZE_TRESHOLD - size) { - rec->bufferReservedSize += VKVG_RECORDING_INIT_BUFFER_SIZE; - rec->buffer = realloc(rec->buffer, rec->bufferReservedSize); - } - return rec->buffer + rec->bufferSize; +void *_ensure_recording_buffer(vkvg_recording_t *rec, size_t size) { + if (rec->bufferReservedSize >= rec->bufferSize - VKVG_RECORDING_INIT_BUFFER_SIZE_TRESHOLD - size) { + rec->bufferReservedSize += VKVG_RECORDING_INIT_BUFFER_SIZE; + rec->buffer = realloc(rec->buffer, rec->bufferReservedSize); + } + return rec->buffer + rec->bufferSize; } -void* _advance_recording_buffer_unchecked (vkvg_recording_t* rec, size_t size) { - rec->bufferSize += size; - return rec->buffer + rec->bufferSize; +void *_advance_recording_buffer_unchecked(vkvg_recording_t *rec, size_t size) { + rec->bufferSize += size; + return rec->buffer + rec->bufferSize; } -#define STORE_FLOATS(floatcount) \ - for (i=0; icommandsCount == rec->commandsReservedCount) { - rec->commandsReservedCount += VKVG_RECORDING_INIT_COMMANDS_COUNT; - rec->commands = (vkvg_record_t*)realloc(rec->commands, rec->commandsReservedCount * sizeof (vkvg_record_t)); - } - vkvg_record_t* r = &rec->commands[rec->commandsCount++]; - r->cmd = cmd; - r->dataOffset = rec->bufferSize; + if (rec->commandsCount == rec->commandsReservedCount) { + rec->commandsReservedCount += VKVG_RECORDING_INIT_COMMANDS_COUNT; + rec->commands = (vkvg_record_t *)realloc(rec->commands, rec->commandsReservedCount * sizeof(vkvg_record_t)); + } + vkvg_record_t *r = &rec->commands[rec->commandsCount++]; + r->cmd = cmd; + r->dataOffset = rec->bufferSize; - char* buff; - int i = 0; + char *buff; + int i = 0; - if (cmd & VKVG_CMD_PATH_COMMANDS) { - if ((cmd & VKVG_CMD_PATHPROPS_COMMANDS) == VKVG_CMD_PATHPROPS_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_SET_LINE_WIDTH: - case VKVG_CMD_SET_MITER_LIMIT: - STORE_FLOATS(1); - break; - case VKVG_CMD_SET_LINE_JOIN: - STORE_UINT32(1); - break; - case VKVG_CMD_SET_LINE_CAP: - STORE_UINT32(1); - break; - case VKVG_CMD_SET_OPERATOR: - STORE_UINT32(1); - break; - case VKVG_CMD_SET_FILL_RULE: - STORE_UINT32(1); - break; - case VKVG_CMD_SET_DASH: - break; - } - } else { - switch (cmd) { - case VKVG_CMD_MOVE_TO: - case VKVG_CMD_LINE_TO: - case VKVG_CMD_REL_MOVE_TO: - case VKVG_CMD_REL_LINE_TO: - STORE_FLOATS(2); - break; - case VKVG_CMD_RECTANGLE: - case VKVG_CMD_QUADRATIC_TO: - case VKVG_CMD_REL_QUADRATIC_TO: - STORE_FLOATS(4); - break; - case VKVG_CMD_ARC: - case VKVG_CMD_ARC_NEG: - STORE_FLOATS(5); - break; - case VKVG_CMD_CURVE_TO: - case VKVG_CMD_REL_CURVE_TO: - STORE_FLOATS(6); - break; - case VKVG_CMD_ELLIPTICAL_ARC_TO: - case VKVG_CMD_REL_ELLIPTICAL_ARC_TO: - STORE_FLOATS(5); - STORE_BOOLS(2); - break; - case VKVG_CMD_NEW_PATH: - case VKVG_CMD_NEW_SUB_PATH: - case VKVG_CMD_CLOSE_PATH: - break; - } - } - } else if (!(r->cmd & VKVG_CMD_DRAW_COMMANDS)) { - if (r->cmd & VKVG_CMD_TRANSFORM_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_TRANSLATE: - case VKVG_CMD_SCALE: - STORE_FLOATS(2); - break; - case VKVG_CMD_ROTATE: - STORE_FLOATS(1); - break; - case VKVG_CMD_IDENTITY_MATRIX: - break; - case VKVG_CMD_SET_MATRIX: - case VKVG_CMD_TRANSFORM: - { - buff = _ensure_recording_buffer (rec, sizeof(vkvg_matrix_t)); - vkvg_matrix_t* mat = (vkvg_matrix_t*)va_arg(args, vkvg_matrix_t*); - memcpy(buff, mat, sizeof(vkvg_matrix_t)); - buff = _advance_recording_buffer_unchecked (rec, sizeof(vkvg_matrix_t)); + if (cmd & VKVG_CMD_PATH_COMMANDS) { + if ((cmd & VKVG_CMD_PATHPROPS_COMMANDS) == VKVG_CMD_PATHPROPS_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_SET_LINE_WIDTH: + case VKVG_CMD_SET_MITER_LIMIT: + STORE_FLOATS(1); + break; + case VKVG_CMD_SET_LINE_JOIN: + STORE_UINT32(1); + break; + case VKVG_CMD_SET_LINE_CAP: + STORE_UINT32(1); + break; + case VKVG_CMD_SET_OPERATOR: + STORE_UINT32(1); + break; + case VKVG_CMD_SET_FILL_RULE: + STORE_UINT32(1); + break; + case VKVG_CMD_SET_DASH: + break; + } + } else { + switch (cmd) { + case VKVG_CMD_MOVE_TO: + case VKVG_CMD_LINE_TO: + case VKVG_CMD_REL_MOVE_TO: + case VKVG_CMD_REL_LINE_TO: + STORE_FLOATS(2); + break; + case VKVG_CMD_RECTANGLE: + case VKVG_CMD_QUADRATIC_TO: + case VKVG_CMD_REL_QUADRATIC_TO: + STORE_FLOATS(4); + break; + case VKVG_CMD_ARC: + case VKVG_CMD_ARC_NEG: + STORE_FLOATS(5); + break; + case VKVG_CMD_CURVE_TO: + case VKVG_CMD_REL_CURVE_TO: + STORE_FLOATS(6); + break; + case VKVG_CMD_ELLIPTICAL_ARC_TO: + case VKVG_CMD_REL_ELLIPTICAL_ARC_TO: + STORE_FLOATS(5); + STORE_BOOLS(2); + break; + case VKVG_CMD_NEW_PATH: + case VKVG_CMD_NEW_SUB_PATH: + case VKVG_CMD_CLOSE_PATH: + break; + } + } + } else if (!(r->cmd & VKVG_CMD_DRAW_COMMANDS)) { + if (r->cmd & VKVG_CMD_TRANSFORM_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_TRANSLATE: + case VKVG_CMD_SCALE: + STORE_FLOATS(2); + break; + case VKVG_CMD_ROTATE: + STORE_FLOATS(1); + break; + case VKVG_CMD_IDENTITY_MATRIX: + break; + case VKVG_CMD_SET_MATRIX: + case VKVG_CMD_TRANSFORM: { + buff = _ensure_recording_buffer(rec, sizeof(vkvg_matrix_t)); + vkvg_matrix_t *mat = (vkvg_matrix_t *)va_arg(args, vkvg_matrix_t *); + memcpy(buff, mat, sizeof(vkvg_matrix_t)); + buff = _advance_recording_buffer_unchecked(rec, sizeof(vkvg_matrix_t)); - } - break; - } - } else if (r->cmd & VKVG_CMD_PATTERN_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_SET_SOURCE_RGBA: - STORE_FLOATS(4); - break; - case VKVG_CMD_SET_SOURCE_RGB: - STORE_FLOATS(3); - break; - case VKVG_CMD_SET_SOURCE_COLOR: - STORE_UINT32(1); - break; - case VKVG_CMD_SET_SOURCE: - { - buff = _ensure_recording_buffer (rec, sizeof(VkvgPattern)); - VkvgPattern pat = (VkvgPattern)va_arg(args, VkvgPattern); - vkvg_pattern_reference(pat); - VkvgPattern* pPat = (VkvgPattern*)buff; - *pPat = pat; - _advance_recording_buffer_unchecked (rec, sizeof(VkvgPattern)); - } - break; - case VKVG_CMD_SET_SOURCE_SURFACE: - STORE_FLOATS(2); - { - buff = _ensure_recording_buffer (rec, sizeof(VkvgSurface)); - VkvgSurface surf = (VkvgSurface)va_arg(args, VkvgSurface); - vkvg_surface_reference(surf); - *(VkvgSurface*)buff = surf; - _advance_recording_buffer_unchecked (rec, sizeof(VkvgSurface)); - } - break; - } - } else if (r->cmd & VKVG_CMD_TEXT_COMMANDS) { - char* txt; - int txtLen; - switch (r->cmd) { - case VKVG_CMD_SET_FONT_SIZE: - STORE_UINT32(1); - break; - case VKVG_CMD_SHOW_TEXT: - case VKVG_CMD_SET_FONT_FACE: - txt = (char*)va_arg(args, char*); - txtLen = strlen(txt); - buff = _ensure_recording_buffer (rec, txtLen * sizeof(char)); - strcpy(buff, txt); - _advance_recording_buffer_unchecked (rec, txtLen * sizeof(char)); - break; - case VKVG_CMD_SET_FONT_PATH: - break; - } - } - } - va_end(args); + } break; + } + } else if (r->cmd & VKVG_CMD_PATTERN_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_SET_SOURCE_RGBA: + STORE_FLOATS(4); + break; + case VKVG_CMD_SET_SOURCE_RGB: + STORE_FLOATS(3); + break; + case VKVG_CMD_SET_SOURCE_COLOR: + STORE_UINT32(1); + break; + case VKVG_CMD_SET_SOURCE: { + buff = _ensure_recording_buffer(rec, sizeof(VkvgPattern)); + VkvgPattern pat = (VkvgPattern)va_arg(args, VkvgPattern); + vkvg_pattern_reference(pat); + VkvgPattern *pPat = (VkvgPattern *)buff; + *pPat = pat; + _advance_recording_buffer_unchecked(rec, sizeof(VkvgPattern)); + } break; + case VKVG_CMD_SET_SOURCE_SURFACE: + STORE_FLOATS(2); + { + buff = _ensure_recording_buffer(rec, sizeof(VkvgSurface)); + VkvgSurface surf = (VkvgSurface)va_arg(args, VkvgSurface); + vkvg_surface_reference(surf); + *(VkvgSurface *)buff = surf; + _advance_recording_buffer_unchecked(rec, sizeof(VkvgSurface)); + } + break; + } + } else if (r->cmd & VKVG_CMD_TEXT_COMMANDS) { + char *txt; + int txtLen; + switch (r->cmd) { + case VKVG_CMD_SET_FONT_SIZE: + STORE_UINT32(1); + break; + case VKVG_CMD_SHOW_TEXT: + case VKVG_CMD_SET_FONT_FACE: + txt = (char *)va_arg(args, char *); + txtLen = strlen(txt); + buff = _ensure_recording_buffer(rec, txtLen * sizeof(char)); + strcpy(buff, txt); + _advance_recording_buffer_unchecked(rec, txtLen * sizeof(char)); + break; + case VKVG_CMD_SET_FONT_PATH: + break; + } + } + } + va_end(args); } -void _replay_command (VkvgContext ctx, VkvgRecording rec, uint32_t index) { - vkvg_record_t* r = &rec->commands[index]; - float* floats = (float*)(rec->buffer + r->dataOffset); - uint32_t* uints = (uint32_t*)floats; - if (r->cmd&VKVG_CMD_PATH_COMMANDS) { - if ((r->cmd&VKVG_CMD_RELATIVE_COMMANDS)==VKVG_CMD_RELATIVE_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_REL_MOVE_TO: - vkvg_rel_move_to(ctx, floats[0], floats[1]); - return; - case VKVG_CMD_REL_LINE_TO: - vkvg_rel_line_to(ctx, floats[0], floats[1]); - return; - case VKVG_CMD_REL_CURVE_TO: - vkvg_rel_curve_to (ctx, floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]); - return; - case VKVG_CMD_REL_QUADRATIC_TO: - vkvg_rel_quadratic_to (ctx, floats[0], floats[1], floats[2], floats[3]); - return; - case VKVG_CMD_REL_ELLIPTICAL_ARC_TO: - { - bool* flags = (bool*)&floats[5]; - vkvg_rel_elliptic_arc_to (ctx, floats[0], floats[1], flags[0], flags[1], floats[2], floats[3], floats[4]); - } - return; - } - }else if ((r->cmd&VKVG_CMD_PATHPROPS_COMMANDS)==VKVG_CMD_PATHPROPS_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_SET_LINE_WIDTH: - vkvg_set_line_width (ctx, floats[0]); - return; - case VKVG_CMD_SET_MITER_LIMIT: - vkvg_set_miter_limit (ctx, floats[0]); - return; - case VKVG_CMD_SET_LINE_JOIN: - vkvg_set_line_join (ctx, (vkvg_line_join_t)uints[0]); - return; - case VKVG_CMD_SET_LINE_CAP: - vkvg_set_line_cap (ctx, (vkvg_line_cap_t)uints[0]); - return; - case VKVG_CMD_SET_OPERATOR: - vkvg_set_operator (ctx, (vkvg_operator_t)uints[0]); - return; - case VKVG_CMD_SET_FILL_RULE: - vkvg_set_fill_rule (ctx, (vkvg_fill_rule_t)uints[0]); - return; - case VKVG_CMD_SET_DASH: - vkvg_set_dash(ctx, &floats[2], uints[0], floats[1]); - return; - } - } else { - switch (r->cmd) { - case VKVG_CMD_NEW_PATH: - vkvg_new_path (ctx); - return; - case VKVG_CMD_NEW_SUB_PATH: - vkvg_new_sub_path (ctx); - return; - case VKVG_CMD_CLOSE_PATH: - vkvg_close_path (ctx); - return; - case VKVG_CMD_RECTANGLE: - vkvg_rectangle (ctx, floats[0], floats[1], floats[2], floats[3]); - return; - case VKVG_CMD_ARC: - vkvg_arc (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); - return; - case VKVG_CMD_ARC_NEG: - vkvg_arc (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); - return; - /*case VKVG_CMD_ELLIPSE: - vkvg_ellipse (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); - break;*/ - case VKVG_CMD_MOVE_TO: - vkvg_move_to(ctx, floats[0], floats[1]); - return; - case VKVG_CMD_LINE_TO: - vkvg_line_to(ctx, floats[0], floats[1]); - return; - case VKVG_CMD_CURVE_TO: - vkvg_curve_to (ctx, floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]); - return; - case VKVG_CMD_ELLIPTICAL_ARC_TO: - { - bool* flags = (bool*)&floats[5]; - vkvg_elliptic_arc_to (ctx, floats[0], floats[1], flags[0], flags[1], floats[2], floats[3], floats[4]); - } - return; - case VKVG_CMD_QUADRATIC_TO: - vkvg_quadratic_to (ctx, floats[0], floats[1], floats[2], floats[3]); - return; - } - } - } else if (r->cmd & VKVG_CMD_DRAW_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_PAINT: - vkvg_paint (ctx); - return; - case VKVG_CMD_FILL: - vkvg_fill (ctx); - return; - case VKVG_CMD_STROKE: - vkvg_stroke (ctx); - return; - case VKVG_CMD_CLIP: - vkvg_clip (ctx); - return; - case VKVG_CMD_CLEAR: - vkvg_clear (ctx); - return; - case VKVG_CMD_FILL_PRESERVE: - vkvg_fill_preserve (ctx); - return; - case VKVG_CMD_STROKE_PRESERVE: - vkvg_stroke_preserve (ctx); - return; - case VKVG_CMD_CLIP_PRESERVE: - vkvg_clip_preserve (ctx); - return; - } - } else if (r->cmd & VKVG_CMD_TRANSFORM_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_TRANSLATE: - vkvg_translate (ctx, floats[0], floats[1]); - return; - case VKVG_CMD_SCALE: - vkvg_scale (ctx, floats[0], floats[1]); - return; - case VKVG_CMD_ROTATE: - vkvg_rotate (ctx, floats[0]); - return; - case VKVG_CMD_IDENTITY_MATRIX: - vkvg_identity_matrix (ctx); - return; - case VKVG_CMD_TRANSFORM: - { - vkvg_matrix_t* mat = (vkvg_matrix_t*)&floats[0]; - vkvg_transform (ctx, mat); - } - return; - case VKVG_CMD_SET_MATRIX: - { - vkvg_matrix_t* mat = (vkvg_matrix_t*)&floats[0]; - vkvg_set_matrix (ctx, mat); - } - return; - } - } else if (r->cmd & VKVG_CMD_PATTERN_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_SET_SOURCE_RGB: - vkvg_set_source_rgb (ctx, floats[0], floats[1], floats[2]); - return; - case VKVG_CMD_SET_SOURCE_RGBA: - vkvg_set_source_rgba (ctx, floats[0], floats[1], floats[2], floats[3]); - return; - case VKVG_CMD_SET_SOURCE_COLOR: - vkvg_set_source_color (ctx, uints[0]); - return; - case VKVG_CMD_SET_SOURCE: - { - VkvgPattern pat = *((VkvgPattern*)(rec->buffer + r->dataOffset)); - vkvg_set_source (ctx, pat); - } - return; - case VKVG_CMD_SET_SOURCE_SURFACE: - { - VkvgSurface surf = *((VkvgSurface*)&floats[2]); - vkvg_set_source_surface (ctx, surf, floats[0], floats[1]); - } - return; - } - } else if (r->cmd & VKVG_CMD_TEXT_COMMANDS) { - char* txt = (char*)floats; - switch (r->cmd) { - case VKVG_CMD_SET_FONT_SIZE: - vkvg_set_font_size (ctx, uints[0]); - return; - case VKVG_CMD_SET_FONT_FACE: - vkvg_select_font_face (ctx, txt); - return; - /*case VKVG_CMD_SET_FONT_PATH: - vkvg_load_font_from_path (ctx, txt); - return; */ - case VKVG_CMD_SHOW_TEXT: - vkvg_show_text (ctx, txt); - return; - } - } else { - switch (r->cmd) { - case VKVG_CMD_SAVE: - vkvg_save (ctx); - return; - case VKVG_CMD_RESTORE: - vkvg_restore (ctx); - return; - } - } - LOG(VKVG_LOG_ERR, "[REPLAY] unimplemented command: %.4x\n", r->cmd); +void _replay_command(VkvgContext ctx, VkvgRecording rec, uint32_t index) { + vkvg_record_t *r = &rec->commands[index]; + float *floats = (float *)(rec->buffer + r->dataOffset); + uint32_t *uints = (uint32_t *)floats; + if (r->cmd & VKVG_CMD_PATH_COMMANDS) { + if ((r->cmd & VKVG_CMD_RELATIVE_COMMANDS) == VKVG_CMD_RELATIVE_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_REL_MOVE_TO: + vkvg_rel_move_to(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_REL_LINE_TO: + vkvg_rel_line_to(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_REL_CURVE_TO: + vkvg_rel_curve_to(ctx, floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]); + return; + case VKVG_CMD_REL_QUADRATIC_TO: + vkvg_rel_quadratic_to(ctx, floats[0], floats[1], floats[2], floats[3]); + return; + case VKVG_CMD_REL_ELLIPTICAL_ARC_TO: { + bool *flags = (bool *)&floats[5]; + vkvg_rel_elliptic_arc_to(ctx, floats[0], floats[1], flags[0], flags[1], floats[2], floats[3], + floats[4]); + } + return; + } + } else if ((r->cmd & VKVG_CMD_PATHPROPS_COMMANDS) == VKVG_CMD_PATHPROPS_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_SET_LINE_WIDTH: + vkvg_set_line_width(ctx, floats[0]); + return; + case VKVG_CMD_SET_MITER_LIMIT: + vkvg_set_miter_limit(ctx, floats[0]); + return; + case VKVG_CMD_SET_LINE_JOIN: + vkvg_set_line_join(ctx, (vkvg_line_join_t)uints[0]); + return; + case VKVG_CMD_SET_LINE_CAP: + vkvg_set_line_cap(ctx, (vkvg_line_cap_t)uints[0]); + return; + case VKVG_CMD_SET_OPERATOR: + vkvg_set_operator(ctx, (vkvg_operator_t)uints[0]); + return; + case VKVG_CMD_SET_FILL_RULE: + vkvg_set_fill_rule(ctx, (vkvg_fill_rule_t)uints[0]); + return; + case VKVG_CMD_SET_DASH: + vkvg_set_dash(ctx, &floats[2], uints[0], floats[1]); + return; + } + } else { + switch (r->cmd) { + case VKVG_CMD_NEW_PATH: + vkvg_new_path(ctx); + return; + case VKVG_CMD_NEW_SUB_PATH: + vkvg_new_sub_path(ctx); + return; + case VKVG_CMD_CLOSE_PATH: + vkvg_close_path(ctx); + return; + case VKVG_CMD_RECTANGLE: + vkvg_rectangle(ctx, floats[0], floats[1], floats[2], floats[3]); + return; + case VKVG_CMD_ARC: + vkvg_arc(ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); + return; + case VKVG_CMD_ARC_NEG: + vkvg_arc(ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); + return; + /*case VKVG_CMD_ELLIPSE: + vkvg_ellipse (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); + break;*/ + case VKVG_CMD_MOVE_TO: + vkvg_move_to(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_LINE_TO: + vkvg_line_to(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_CURVE_TO: + vkvg_curve_to(ctx, floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]); + return; + case VKVG_CMD_ELLIPTICAL_ARC_TO: { + bool *flags = (bool *)&floats[5]; + vkvg_elliptic_arc_to(ctx, floats[0], floats[1], flags[0], flags[1], floats[2], floats[3], floats[4]); + } + return; + case VKVG_CMD_QUADRATIC_TO: + vkvg_quadratic_to(ctx, floats[0], floats[1], floats[2], floats[3]); + return; + } + } + } else if (r->cmd & VKVG_CMD_DRAW_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_PAINT: + vkvg_paint(ctx); + return; + case VKVG_CMD_FILL: + vkvg_fill(ctx); + return; + case VKVG_CMD_STROKE: + vkvg_stroke(ctx); + return; + case VKVG_CMD_CLIP: + vkvg_clip(ctx); + return; + case VKVG_CMD_CLEAR: + vkvg_clear(ctx); + return; + case VKVG_CMD_FILL_PRESERVE: + vkvg_fill_preserve(ctx); + return; + case VKVG_CMD_STROKE_PRESERVE: + vkvg_stroke_preserve(ctx); + return; + case VKVG_CMD_CLIP_PRESERVE: + vkvg_clip_preserve(ctx); + return; + } + } else if (r->cmd & VKVG_CMD_TRANSFORM_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_TRANSLATE: + vkvg_translate(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_SCALE: + vkvg_scale(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_ROTATE: + vkvg_rotate(ctx, floats[0]); + return; + case VKVG_CMD_IDENTITY_MATRIX: + vkvg_identity_matrix(ctx); + return; + case VKVG_CMD_TRANSFORM: { + vkvg_matrix_t *mat = (vkvg_matrix_t *)&floats[0]; + vkvg_transform(ctx, mat); + } + return; + case VKVG_CMD_SET_MATRIX: { + vkvg_matrix_t *mat = (vkvg_matrix_t *)&floats[0]; + vkvg_set_matrix(ctx, mat); + } + return; + } + } else if (r->cmd & VKVG_CMD_PATTERN_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_SET_SOURCE_RGB: + vkvg_set_source_rgb(ctx, floats[0], floats[1], floats[2]); + return; + case VKVG_CMD_SET_SOURCE_RGBA: + vkvg_set_source_rgba(ctx, floats[0], floats[1], floats[2], floats[3]); + return; + case VKVG_CMD_SET_SOURCE_COLOR: + vkvg_set_source_color(ctx, uints[0]); + return; + case VKVG_CMD_SET_SOURCE: { + VkvgPattern pat = *((VkvgPattern *)(rec->buffer + r->dataOffset)); + vkvg_set_source(ctx, pat); + } + return; + case VKVG_CMD_SET_SOURCE_SURFACE: { + VkvgSurface surf = *((VkvgSurface *)&floats[2]); + vkvg_set_source_surface(ctx, surf, floats[0], floats[1]); + } + return; + } + } else if (r->cmd & VKVG_CMD_TEXT_COMMANDS) { + char *txt = (char *)floats; + switch (r->cmd) { + case VKVG_CMD_SET_FONT_SIZE: + vkvg_set_font_size(ctx, uints[0]); + return; + case VKVG_CMD_SET_FONT_FACE: + vkvg_select_font_face(ctx, txt); + return; + /*case VKVG_CMD_SET_FONT_PATH: + vkvg_load_font_from_path (ctx, txt); + return; */ + case VKVG_CMD_SHOW_TEXT: + vkvg_show_text(ctx, txt); + return; + } + } else { + switch (r->cmd) { + case VKVG_CMD_SAVE: + vkvg_save(ctx); + return; + case VKVG_CMD_RESTORE: + vkvg_restore(ctx); + return; + } + } + LOG(VKVG_LOG_ERR, "[REPLAY] unimplemented command: %.4x\n", r->cmd); } - diff --git a/src/recording/vkvg_record_internal.h b/src/recording/vkvg_record_internal.h index c18801a..fcc905f 100644 --- a/src/recording/vkvg_record_internal.h +++ b/src/recording/vkvg_record_internal.h @@ -25,110 +25,108 @@ #include "vkvg.h" #include "vkvg_internal.h" -#define VKVG_CMD_SAVE 0x0001 -#define VKVG_CMD_RESTORE 0x0002 - -#define VKVG_CMD_PATH_COMMANDS 0x0100 -#define VKVG_CMD_DRAW_COMMANDS 0x0200 -#define VKVG_CMD_RELATIVE_COMMANDS (0x0400|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_PATHPROPS_COMMANDS (0x1000|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_PRESERVE_COMMANDS (0x0400|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_PATTERN_COMMANDS 0x0800 -#define VKVG_CMD_TRANSFORM_COMMANDS 0x2000 -#define VKVG_CMD_TEXT_COMMANDS 0x4000 - -#define VKVG_CMD_NEW_PATH (0x0001|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_NEW_SUB_PATH (0x0002|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_CLOSE_PATH (0x0003|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_MOVE_TO (0x0004|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_LINE_TO (0x0005|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_RECTANGLE (0x0006|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_ARC (0x0007|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_ARC_NEG (0x0008|VKVG_CMD_PATH_COMMANDS) -//#define VKVG_CMD_ELLIPSE (0x0009|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_CURVE_TO (0x000A|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_QUADRATIC_TO (0x000B|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_ELLIPTICAL_ARC_TO (0x000C|VKVG_CMD_PATH_COMMANDS) - -#define VKVG_CMD_SET_LINE_WIDTH (0x0001|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_MITER_LIMIT (0x0002|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_LINE_JOIN (0x0003|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_LINE_CAP (0x0004|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_OPERATOR (0x0005|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_FILL_RULE (0x0006|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_DASH (0x0007|VKVG_CMD_PATHPROPS_COMMANDS) - -#define VKVG_CMD_TRANSLATE (0x0001|VKVG_CMD_TRANSFORM_COMMANDS) -#define VKVG_CMD_ROTATE (0x0002|VKVG_CMD_TRANSFORM_COMMANDS) -#define VKVG_CMD_SCALE (0x0003|VKVG_CMD_TRANSFORM_COMMANDS) -#define VKVG_CMD_TRANSFORM (0x0004|VKVG_CMD_TRANSFORM_COMMANDS) -#define VKVG_CMD_IDENTITY_MATRIX (0x0005|VKVG_CMD_TRANSFORM_COMMANDS) - -#define VKVG_CMD_SET_MATRIX (0x0006|VKVG_CMD_TRANSFORM_COMMANDS) - -#define VKVG_CMD_SET_FONT_SIZE (0x0001|VKVG_CMD_TEXT_COMMANDS) -#define VKVG_CMD_SET_FONT_FACE (0x0002|VKVG_CMD_TEXT_COMMANDS) -#define VKVG_CMD_SET_FONT_PATH (0x0003|VKVG_CMD_TEXT_COMMANDS) -#define VKVG_CMD_SHOW_TEXT (0x0004|VKVG_CMD_TEXT_COMMANDS) - -#define VKVG_CMD_REL_MOVE_TO (VKVG_CMD_MOVE_TO |VKVG_CMD_RELATIVE_COMMANDS) -#define VKVG_CMD_REL_LINE_TO (VKVG_CMD_LINE_TO |VKVG_CMD_RELATIVE_COMMANDS) -#define VKVG_CMD_REL_CURVE_TO (VKVG_CMD_CURVE_TO |VKVG_CMD_RELATIVE_COMMANDS) -#define VKVG_CMD_REL_QUADRATIC_TO (VKVG_CMD_QUADRATIC_TO |VKVG_CMD_RELATIVE_COMMANDS) -#define VKVG_CMD_REL_ELLIPTICAL_ARC_TO (VKVG_CMD_ELLIPTICAL_ARC_TO |VKVG_CMD_RELATIVE_COMMANDS) - -#define VKVG_CMD_PAINT (0x0001|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_FILL (0x0002|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_STROKE (0x0003|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_CLIP (0x0004|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_RESET_CLIP (0x0005|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_CLEAR (0x0006|VKVG_CMD_DRAW_COMMANDS) - -#define VKVG_CMD_FILL_PRESERVE (VKVG_CMD_FILL |VKVG_CMD_PRESERVE_COMMANDS) -#define VKVG_CMD_STROKE_PRESERVE (VKVG_CMD_STROKE |VKVG_CMD_PRESERVE_COMMANDS) -#define VKVG_CMD_CLIP_PRESERVE (VKVG_CMD_CLIP |VKVG_CMD_PRESERVE_COMMANDS) - -#define VKVG_CMD_SET_SOURCE_RGB (0x0001|VKVG_CMD_PATTERN_COMMANDS) -#define VKVG_CMD_SET_SOURCE_RGBA (0x0002|VKVG_CMD_PATTERN_COMMANDS) -#define VKVG_CMD_SET_SOURCE_COLOR (0x0003|VKVG_CMD_PATTERN_COMMANDS) -#define VKVG_CMD_SET_SOURCE (0x0004|VKVG_CMD_PATTERN_COMMANDS) -#define VKVG_CMD_SET_SOURCE_SURFACE (0x0005|VKVG_CMD_PATTERN_COMMANDS) - - - -typedef struct _vkvg_record_t{ - uint16_t cmd; - size_t dataOffset; -}vkvg_record_t; - -typedef struct _vkvg_recording_t{ - vkvg_record_t* commands; - uint32_t commandsCount; - uint32_t commandsReservedCount; - size_t bufferSize; - size_t bufferReservedSize; - char* buffer; -}vkvg_recording_t; - - -void _start_recording (VkvgContext ctx); -vkvg_recording_t* _stop_recording (VkvgContext ctx); -void _destroy_recording (vkvg_recording_t* rec); -void _replay_command (VkvgContext ctx, VkvgRecording rec, uint32_t index); -void _record (vkvg_recording_t* rec,...); - -#define RECORD(ctx,...) {\ - if (ctx->recording) {\ - _record (ctx->recording,__VA_ARGS__);\ - return;\ - }\ -} -#define RECORD2(ctx,...) {\ - if (ctx->recording) {\ - _record (ctx->recording,__VA_ARGS__);\ - return 0;\ - }\ -} - +#define VKVG_CMD_SAVE 0x0001 +#define VKVG_CMD_RESTORE 0x0002 + +#define VKVG_CMD_PATH_COMMANDS 0x0100 +#define VKVG_CMD_DRAW_COMMANDS 0x0200 +#define VKVG_CMD_RELATIVE_COMMANDS (0x0400 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_PATHPROPS_COMMANDS (0x1000 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_PRESERVE_COMMANDS (0x0400 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_PATTERN_COMMANDS 0x0800 +#define VKVG_CMD_TRANSFORM_COMMANDS 0x2000 +#define VKVG_CMD_TEXT_COMMANDS 0x4000 + +#define VKVG_CMD_NEW_PATH (0x0001 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_NEW_SUB_PATH (0x0002 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_CLOSE_PATH (0x0003 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_MOVE_TO (0x0004 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_LINE_TO (0x0005 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_RECTANGLE (0x0006 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_ARC (0x0007 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_ARC_NEG (0x0008 | VKVG_CMD_PATH_COMMANDS) +// #define VKVG_CMD_ELLIPSE (0x0009|VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_CURVE_TO (0x000A | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_QUADRATIC_TO (0x000B | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_ELLIPTICAL_ARC_TO (0x000C | VKVG_CMD_PATH_COMMANDS) + +#define VKVG_CMD_SET_LINE_WIDTH (0x0001 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_MITER_LIMIT (0x0002 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_LINE_JOIN (0x0003 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_LINE_CAP (0x0004 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_OPERATOR (0x0005 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_FILL_RULE (0x0006 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_DASH (0x0007 | VKVG_CMD_PATHPROPS_COMMANDS) + +#define VKVG_CMD_TRANSLATE (0x0001 | VKVG_CMD_TRANSFORM_COMMANDS) +#define VKVG_CMD_ROTATE (0x0002 | VKVG_CMD_TRANSFORM_COMMANDS) +#define VKVG_CMD_SCALE (0x0003 | VKVG_CMD_TRANSFORM_COMMANDS) +#define VKVG_CMD_TRANSFORM (0x0004 | VKVG_CMD_TRANSFORM_COMMANDS) +#define VKVG_CMD_IDENTITY_MATRIX (0x0005 | VKVG_CMD_TRANSFORM_COMMANDS) + +#define VKVG_CMD_SET_MATRIX (0x0006 | VKVG_CMD_TRANSFORM_COMMANDS) + +#define VKVG_CMD_SET_FONT_SIZE (0x0001 | VKVG_CMD_TEXT_COMMANDS) +#define VKVG_CMD_SET_FONT_FACE (0x0002 | VKVG_CMD_TEXT_COMMANDS) +#define VKVG_CMD_SET_FONT_PATH (0x0003 | VKVG_CMD_TEXT_COMMANDS) +#define VKVG_CMD_SHOW_TEXT (0x0004 | VKVG_CMD_TEXT_COMMANDS) + +#define VKVG_CMD_REL_MOVE_TO (VKVG_CMD_MOVE_TO | VKVG_CMD_RELATIVE_COMMANDS) +#define VKVG_CMD_REL_LINE_TO (VKVG_CMD_LINE_TO | VKVG_CMD_RELATIVE_COMMANDS) +#define VKVG_CMD_REL_CURVE_TO (VKVG_CMD_CURVE_TO | VKVG_CMD_RELATIVE_COMMANDS) +#define VKVG_CMD_REL_QUADRATIC_TO (VKVG_CMD_QUADRATIC_TO | VKVG_CMD_RELATIVE_COMMANDS) +#define VKVG_CMD_REL_ELLIPTICAL_ARC_TO (VKVG_CMD_ELLIPTICAL_ARC_TO | VKVG_CMD_RELATIVE_COMMANDS) + +#define VKVG_CMD_PAINT (0x0001 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_FILL (0x0002 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_STROKE (0x0003 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_CLIP (0x0004 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_RESET_CLIP (0x0005 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_CLEAR (0x0006 | VKVG_CMD_DRAW_COMMANDS) + +#define VKVG_CMD_FILL_PRESERVE (VKVG_CMD_FILL | VKVG_CMD_PRESERVE_COMMANDS) +#define VKVG_CMD_STROKE_PRESERVE (VKVG_CMD_STROKE | VKVG_CMD_PRESERVE_COMMANDS) +#define VKVG_CMD_CLIP_PRESERVE (VKVG_CMD_CLIP | VKVG_CMD_PRESERVE_COMMANDS) + +#define VKVG_CMD_SET_SOURCE_RGB (0x0001 | VKVG_CMD_PATTERN_COMMANDS) +#define VKVG_CMD_SET_SOURCE_RGBA (0x0002 | VKVG_CMD_PATTERN_COMMANDS) +#define VKVG_CMD_SET_SOURCE_COLOR (0x0003 | VKVG_CMD_PATTERN_COMMANDS) +#define VKVG_CMD_SET_SOURCE (0x0004 | VKVG_CMD_PATTERN_COMMANDS) +#define VKVG_CMD_SET_SOURCE_SURFACE (0x0005 | VKVG_CMD_PATTERN_COMMANDS) + +typedef struct _vkvg_record_t { + uint16_t cmd; + size_t dataOffset; +} vkvg_record_t; + +typedef struct _vkvg_recording_t { + vkvg_record_t *commands; + uint32_t commandsCount; + uint32_t commandsReservedCount; + size_t bufferSize; + size_t bufferReservedSize; + char *buffer; +} vkvg_recording_t; + +void _start_recording(VkvgContext ctx); +vkvg_recording_t *_stop_recording(VkvgContext ctx); +void _destroy_recording(vkvg_recording_t *rec); +void _replay_command(VkvgContext ctx, VkvgRecording rec, uint32_t index); +void _record(vkvg_recording_t *rec, ...); + +#define RECORD(ctx, ...) \ + { \ + if (ctx->recording) { \ + _record(ctx->recording, __VA_ARGS__); \ + return; \ + } \ + } +#define RECORD2(ctx, ...) \ + { \ + if (ctx->recording) { \ + _record(ctx->recording, __VA_ARGS__); \ + return 0; \ + } \ + } #endif diff --git a/src/shaders.h b/src/shaders.h index b4a8c8e..9e48365 100644 --- a/src/shaders.h +++ b/src/shaders.h @@ -1,2262 +1,1431 @@ unsigned char shader_comp_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, - 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, - 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, - 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, - 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, - 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, - 0x6c, 0x49, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x00, - 0x78, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x00, 0x00, - 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x6d, 0x00, 0x00, 0x00, - 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x76, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7b, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x84, 0x00, 0x00, 0x00, - 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x62, 0x75, 0x66, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0xa0, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x80, 0x0c, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x60, 0x09, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x45, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x16, 0x45, 0x17, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xe3, 0xbe, 0x2c, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x2b, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x8f, 0xc2, 0x15, 0x40, - 0x2c, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x43, 0x17, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x9a, 0x99, 0x99, 0x3e, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x77, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0x4c, 0xbe, 0x2b, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x9a, 0x99, 0x99, 0xbe, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xbf, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x06, 0x40, 0x2b, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, - 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0xcd, 0xcc, 0xcc, 0x3d, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x82, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x83, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, - 0xd0, 0x0f, 0xc9, 0x40, 0x19, 0x00, 0x09, 0x00, 0x95, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x96, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x96, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x99, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x9c, 0x00, 0x00, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, - 0x9f, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, - 0x76, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x83, 0x00, 0x00, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x39, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, - 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x47, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x47, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x4b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x4b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x94, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0xba, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x65, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x64, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x45, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x46, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, - 0x6f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x6d, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x76, 0x00, 0x00, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7b, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, - 0x7b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x89, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, - 0x89, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x8d, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x86, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x91, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, - 0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x82, 0x00, 0x00, 0x00, - 0x94, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, - 0x93, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x95, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x99, 0x00, 0x00, 0x00, - 0x9b, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x82, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0x98, 0x00, 0x00, 0x00, - 0x9d, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, - 0x38, 0x00, 0x01, 0x00 -}; -unsigned int shader_comp_spv_len = 3580; -unsigned char shader2_comp_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, - 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, - 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, - 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, - 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, - 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x46, - 0x72, 0x61, 0x6d, 0x65, 0x28, 0x76, 0x66, 0x32, 0x3b, 0x76, 0x66, 0x32, - 0x3b, 0x76, 0x66, 0x32, 0x3b, 0x66, 0x31, 0x3b, 0x66, 0x31, 0x3b, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x70, 0x6f, 0x73, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, 0x65, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x74, 0x68, 0x69, 0x63, 0x6b, 0x6e, 0x65, 0x73, - 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x67, 0x6c, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x49, 0x6e, 0x76, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x70, 0x6f, 0x73, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x54, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x61, 0x00, 0x00, 0x00, 0x62, 0x75, 0x66, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x61, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x33, 0x33, 0x73, 0x3f, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, - 0xcd, 0xcc, 0x4c, 0x3d, 0x14, 0x00, 0x02, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x80, 0x0c, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x60, 0x09, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x48, 0x45, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x45, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x9a, 0x99, 0x19, 0x3f, - 0x2c, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x4b, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0xcc, 0x3d, - 0x2c, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x6f, 0x12, 0x03, 0x3b, - 0x17, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x60, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x6a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, - 0x6a, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x35, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x3b, 0x00, 0x00, 0x00, - 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x50, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x53, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x55, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, - 0x39, 0x00, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x5b, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x57, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, - 0x67, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, - 0x38, 0x00, 0x01, 0x00, 0x36, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0xfe, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, 0x00 -}; -unsigned int shader2_comp_spv_len = 2604; + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, + 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, + 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, + 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x49, + 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1f, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, + 0x00, 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x03, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, 0x69, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0x73, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x76, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x03, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, + 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x84, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, 0x62, 0x75, 0x66, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x04, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x80, + 0x0c, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x60, 0x09, 0x00, 0x00, 0x16, 0x00, 0x03, + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x45, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x45, + 0x17, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, + 0x00, 0x2c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x34, + 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xe3, 0xbe, 0x2c, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x8f, 0xc2, + 0x15, 0x40, 0x2c, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, + 0x00, 0x3f, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x3f, 0x00, + 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x17, 0x00, + 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x72, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x9a, 0x99, 0x99, 0x3e, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, + 0x00, 0x74, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0x4c, 0xbe, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x9a, 0x99, 0x99, 0xbe, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xbf, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x7c, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x06, 0x40, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x40, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0xcd, 0xcc, 0xcc, 0x3d, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x32, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x82, 0x00, 0x00, 0x00, 0x1d, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x83, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x82, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0xd0, 0x0f, 0xc9, + 0x40, 0x19, 0x00, 0x09, 0x00, 0x95, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x96, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x99, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x3f, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, + 0x9f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x2d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, + 0x00, 0x73, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x76, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf8, 0x00, + 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, + 0x00, 0x1b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, + 0x02, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0a, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, + 0x00, 0x88, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2a, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, 0x2a, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, + 0x00, 0x2b, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, + 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, + 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, + 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x04, 0x00, 0x45, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, + 0x47, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x47, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4a, 0x00, + 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x44, + 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, + 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, + 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x50, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x52, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, + 0x00, 0x51, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x55, 0x00, + 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x57, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, + 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x5a, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x5b, + 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, + 0x00, 0x55, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x5e, 0x00, + 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5d, + 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x2b, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0xba, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x00, 0x65, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x64, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x45, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x67, + 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, + 0x67, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, + 0x00, 0xf9, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x3f, + 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, + 0x00, 0x45, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x31, 0x00, + 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x6f, + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x73, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x76, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7f, 0x00, + 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x73, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x71, 0x00, + 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x71, + 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, 0x00, + 0x8c, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, + 0x00, 0x8d, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x71, 0x00, + 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x85, + 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x81, 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, + 0x00, 0x51, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x82, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x84, 0x00, + 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x95, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x97, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x07, 0x00, 0x99, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9d, 0x00, + 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x82, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x84, + 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0x98, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; +unsigned int shader_comp_spv_len = 3580; +unsigned char shader2_comp_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, + 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, + 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, + 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x46, 0x72, 0x61, + 0x6d, 0x65, 0x28, 0x76, 0x66, 0x32, 0x3b, 0x76, 0x66, 0x32, 0x3b, 0x76, 0x66, 0x32, 0x3b, 0x66, 0x31, 0x3b, 0x66, + 0x31, 0x3b, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x70, 0x6f, 0x73, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, + 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x74, 0x68, 0x69, 0x63, 0x6b, 0x6e, 0x65, 0x73, 0x73, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, + 0x2b, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x49, 0x6e, 0x76, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x70, 0x6f, + 0x73, 0x00, 0x05, 0x00, 0x03, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x53, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x54, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x55, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0x61, 0x00, 0x00, 0x00, 0x62, 0x75, 0x66, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x61, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x61, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x03, 0x00, 0x61, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x6b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x21, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x33, + 0x33, 0x73, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0x4c, 0x3d, + 0x14, 0x00, 0x02, 0x00, 0x27, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2d, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x80, 0x0c, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x60, 0x09, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x45, 0x2b, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x45, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x9a, 0x99, 0x19, 0x3f, 0x2c, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4c, + 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x4d, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0xcc, 0x3d, 0x2c, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, + 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0x00, + 0x00, 0x00, 0x6f, 0x12, 0x03, 0x3b, 0x17, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x09, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2c, + 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, + 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2f, 0x00, + 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2f, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, + 0x31, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, + 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x33, 0x00, + 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x35, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, + 0xae, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0xf9, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf5, 0x00, + 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x39, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfa, 0x00, 0x04, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, + 0x00, 0x3b, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x43, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, + 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x46, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, + 0x00, 0x46, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x49, 0x00, + 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x49, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0x50, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, + 0x00, 0x4c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x53, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x55, 0x00, 0x00, 0x00, 0x4f, + 0x00, 0x00, 0x00, 0x39, 0x00, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5b, + 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, + 0x00, 0x50, 0x00, 0x07, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5b, 0x00, + 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x59, 0x00, 0x00, 0x00, 0x5e, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, + 0x00, 0x63, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x67, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x65, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, + 0x63, 0x00, 0x04, 0x00, 0x62, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, + 0x00, 0x38, 0x00, 0x01, 0x00, 0x36, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x37, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x37, + 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x37, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x37, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x37, 0x00, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x83, 0x00, + 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, + 0x00}; +unsigned int shader2_comp_spv_len = 2604; unsigned char vkvg_main_frag_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x00, - 0x94, 0x01, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, - 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, - 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, - 0x52, 0x42, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, - 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, - 0x61, 0x63, 0x6b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x45, - 0x58, 0x54, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x5f, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, - 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, - 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, - 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, - 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, - 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, 0x64, 0x69, 0x73, 0x74, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x70, 0x30, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x5f, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x70, - 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x63, 0x70, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x70, 0x31, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x9e, 0x00, 0x00, 0x00, 0x62, 0x62, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0xf2, 0x00, 0x00, 0x00, 0x63, 0x30, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0xf9, 0x00, 0x00, 0x00, 0x63, 0x31, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x72, 0x30, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x06, 0x01, 0x00, 0x00, 0x72, 0x31, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x0c, 0x01, 0x00, 0x00, 0x67, 0x72, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, - 0x74, 0x68, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0d, 0x01, 0x00, 0x00, - 0x64, 0x69, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x72, 0x61, 0x79, 0x44, 0x69, 0x72, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x16, 0x01, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x20, 0x01, 0x00, 0x00, 0x63, 0x63, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x28, 0x01, 0x00, 0x00, 0x64, 0x69, 0x73, 0x63, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x36, 0x01, 0x00, 0x00, - 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x40, 0x01, 0x00, 0x00, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x67, 0x72, 0x61, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x5f, 0x01, 0x00, 0x00, - 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x7f, 0x01, 0x00, 0x00, - 0x69, 0x6e, 0x46, 0x6f, 0x6e, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x88, 0x01, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, - 0x4d, 0x61, 0x70, 0x00, 0x05, 0x00, 0x05, 0x00, 0x8f, 0x01, 0x00, 0x00, - 0x69, 0x6e, 0x4f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x06, 0x00, 0x94, 0x01, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x46, - 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x96, 0x01, 0x00, 0x00, 0x4e, 0x55, 0x4d, 0x5f, - 0x53, 0x41, 0x4d, 0x50, 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x60, 0x01, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x88, 0x01, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x88, 0x01, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x94, 0x01, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x96, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, - 0x47, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x04, 0x00, 0x56, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x5b, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, - 0x7d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xc2, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0xcb, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xd5, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x40, 0x17, 0x00, 0x04, 0x00, 0x7d, 0x01, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x7e, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7d, 0x01, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x7e, 0x01, 0x00, 0x00, 0x7f, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x85, 0x01, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x86, 0x01, 0x00, 0x00, - 0x85, 0x01, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x87, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x87, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x93, 0x01, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x93, 0x01, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x96, 0x01, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0xf2, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x16, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x06, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x40, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfb, 0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x25, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, - 0x2e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x35, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x39, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0x6b, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x6d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, - 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x73, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x77, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, - 0x77, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x78, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x96, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, - 0xb8, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, - 0x82, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, - 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x84, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x87, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x89, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, - 0x89, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x85, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, - 0x90, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, - 0x93, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x85, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x85, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x96, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, - 0x9d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x9f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, - 0x9f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xa1, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xa3, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, - 0xa3, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xa5, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x9e, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, - 0xa9, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, - 0xa9, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xab, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, - 0xa7, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, - 0xac, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xb1, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, - 0xb3, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xb5, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, - 0xb5, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, - 0xb6, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, - 0xb7, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, - 0xb7, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, - 0xb9, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, - 0xbb, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xba, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xbd, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x52, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xbb, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0xbe, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xbf, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, - 0xc3, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, - 0xc5, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xc6, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, - 0xc6, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, - 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, - 0xc1, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xcd, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xcd, 0x00, 0x00, 0x00, - 0xf6, 0x00, 0x04, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xd1, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, - 0xd2, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xd5, 0x00, 0x00, 0x00, - 0xd6, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, - 0xd6, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x23, 0x00, 0x00, 0x00, - 0xd8, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0xb0, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, - 0xd3, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0xd9, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xce, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0xdc, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, - 0xdd, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0xdf, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0xc2, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0xe3, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, - 0xe4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xe6, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, - 0xe6, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xe8, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, - 0xe7, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2e, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, - 0xe8, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0xe9, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xd0, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, - 0xea, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xcd, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xcf, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xed, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, - 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, - 0xf0, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, - 0xf0, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, - 0xf1, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0xf3, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xf4, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, - 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xf2, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xfb, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, - 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, - 0xfe, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, - 0xfe, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xf9, 0x00, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0xc2, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, - 0x02, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0xc2, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, - 0x07, 0x01, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x09, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, - 0x09, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x0b, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x06, 0x01, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, - 0xf2, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x0f, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, - 0x0f, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x0d, 0x01, 0x00, 0x00, - 0x10, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x12, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, - 0x12, 0x01, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x19, 0x01, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x16, 0x01, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x1d, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, - 0x1d, 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x1f, 0x01, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, - 0x0d, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x22, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, - 0x22, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x24, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, - 0x24, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, - 0x26, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x27, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x29, 0x01, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, - 0x29, 0x01, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, - 0x2c, 0x01, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, - 0x2e, 0x01, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, - 0x30, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x28, 0x01, 0x00, 0x00, - 0x31, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x32, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0xbe, 0x00, 0x05, 0x00, - 0x7d, 0x00, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x35, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x33, 0x01, 0x00, 0x00, - 0x34, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x34, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x37, 0x01, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x37, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, - 0x28, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3a, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x39, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3b, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, - 0x3a, 0x01, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3c, 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x3b, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, - 0x16, 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3e, 0x01, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, - 0x3c, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x36, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x43, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, - 0x43, 0x01, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x45, 0x01, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x40, 0x01, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, - 0x40, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x47, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x4a, 0x01, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x35, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x35, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x4c, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, - 0x4d, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x4f, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, - 0x4f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x51, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, - 0x51, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x4b, 0x01, 0x00, 0x00, - 0x52, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x53, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x54, 0x01, 0x00, 0x00, 0x53, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, - 0x57, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, - 0x59, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x5a, 0x01, 0x00, 0x00, 0x59, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, - 0x5a, 0x01, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x5d, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, - 0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, - 0x56, 0x01, 0x00, 0x00, 0x5d, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x5f, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x60, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x60, 0x01, 0x00, 0x00, - 0xf6, 0x00, 0x04, 0x00, 0x62, 0x01, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x64, 0x01, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x64, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, - 0x7c, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, - 0x65, 0x01, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xd5, 0x00, 0x00, 0x00, - 0x67, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, - 0x67, 0x01, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, - 0x69, 0x01, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0x69, 0x01, 0x00, 0x00, 0x61, 0x01, 0x00, 0x00, - 0x62, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x61, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6a, 0x01, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x6b, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x6b, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x6e, 0x01, 0x00, 0x00, - 0x5f, 0x01, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x6f, 0x01, 0x00, 0x00, 0x6e, 0x01, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x71, 0x01, 0x00, 0x00, - 0x70, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x72, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0xc2, 0x00, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x72, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, - 0x4b, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x76, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x71, 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, - 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, - 0x76, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, - 0x76, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x78, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x6a, 0x01, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x63, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x63, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x79, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x7a, 0x01, 0x00, 0x00, 0x79, 0x01, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x5f, 0x01, 0x00, 0x00, - 0x7a, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x60, 0x01, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x62, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0x7f, 0x01, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0xbe, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, - 0x81, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, - 0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x82, 0x01, 0x00, 0x00, 0x83, 0x01, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x83, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x86, 0x01, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x7d, 0x01, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x00, - 0x7f, 0x01, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x8b, 0x01, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x00, - 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, - 0x8b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, - 0x8d, 0x01, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x84, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x84, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, - 0x8f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x91, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x91, 0x01, 0x00, 0x00, - 0x90, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x92, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x95, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x94, 0x01, 0x00, 0x00, 0x95, 0x01, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, - 0x38, 0x00, 0x01, 0x00 -}; -unsigned int vkvg_main_frag_spv_len = 9532; -unsigned char vkvg_main_vert_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, - 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, - 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, - 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, - 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, - 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, - 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, - 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x6f, 0x75, 0x74, 0x50, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x50, 0x75, 0x73, 0x68, - 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x66, 0x75, 0x6c, 0x6c, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x51, 0x75, - 0x61, 0x64, 0x5f, 0x73, 0x72, 0x63, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x6f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x00, 0x06, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x74, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x6d, 0x61, 0x74, 0x49, 0x6e, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x70, 0x63, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x4d, 0x61, 0x74, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x53, - 0x72, 0x63, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x69, 0x6e, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x4f, 0x70, 0x61, 0x63, 0x69, - 0x74, 0x79, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x00, 0x06, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74, - 0x53, 0x69, 0x7a, 0x65, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x43, - 0x6c, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x00, - 0x06, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x67, 0x6c, 0x5f, 0x43, 0x75, 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00, - 0x69, 0x6e, 0x50, 0x6f, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x51, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x55, 0x56, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x31, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x15, 0x00, 0x04, 0x00, - 0x3b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x17, 0x00, 0x04, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbf, - 0x2c, 0x00, 0x06, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2c, 0x00, 0x05, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, - 0x77, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x7a, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x05, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x29, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x29, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x25, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x33, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, - 0xaa, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, - 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x4e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x3a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x63, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x6b, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x74, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, - 0x76, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x7f, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x83, 0x00, 0x00, 0x00, - 0x82, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 -}; -unsigned int vkvg_main_vert_spv_len = 3704; + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x21, 0x00, 0x00, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x10, 0x00, + 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, + 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, + 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, + 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, + 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, 0x04, + 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x45, 0x58, 0x54, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x5f, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, + 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, + 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, + 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, + 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, + 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1e, 0x00, + 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4d, 0x61, 0x74, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, + 0x05, 0x00, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, 0x64, 0x69, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, + 0x00, 0x54, 0x00, 0x00, 0x00, 0x70, 0x30, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5f, 0x75, + 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x70, 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x5a, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x63, 0x70, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x75, + 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x05, 0x00, 0x03, 0x00, 0x64, 0x00, 0x00, 0x00, 0x70, 0x31, 0x00, 0x00, + 0x05, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x75, 0x00, 0x00, + 0x00, 0x75, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x03, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x62, 0x62, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x69, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x63, 0x30, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0xf9, 0x00, 0x00, 0x00, 0x63, 0x31, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x72, 0x30, 0x00, + 0x00, 0x05, 0x00, 0x03, 0x00, 0x06, 0x01, 0x00, 0x00, 0x72, 0x31, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0c, 0x01, + 0x00, 0x00, 0x67, 0x72, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0d, + 0x01, 0x00, 0x00, 0x64, 0x69, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x11, 0x01, 0x00, 0x00, + 0x72, 0x61, 0x79, 0x44, 0x69, 0x72, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x16, 0x01, 0x00, 0x00, 0x61, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x03, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x20, 0x01, + 0x00, 0x00, 0x63, 0x63, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x28, 0x01, 0x00, 0x00, 0x64, 0x69, 0x73, 0x63, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x36, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x40, 0x01, 0x00, 0x00, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x05, 0x00, 0x04, + 0x00, 0x4b, 0x01, 0x00, 0x00, 0x67, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x5f, 0x01, + 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x69, 0x6e, 0x46, 0x6f, 0x6e, + 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x88, 0x01, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, + 0x4d, 0x61, 0x70, 0x00, 0x05, 0x00, 0x05, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x69, 0x6e, 0x4f, 0x70, 0x61, 0x63, 0x69, + 0x74, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x94, 0x01, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x46, 0x72, 0x61, + 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x96, 0x01, 0x00, 0x00, 0x4e, + 0x55, 0x4d, 0x5f, 0x53, 0x41, 0x4d, 0x50, 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x47, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, + 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x21, + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x56, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, + 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, + 0x00, 0x5a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, + 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x48, + 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, + 0x47, 0x00, 0x03, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x88, 0x01, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x88, 0x01, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, + 0x00, 0x8f, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x1e, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x94, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x96, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0e, + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x23, 0x00, + 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x34, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x47, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x49, + 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x56, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x55, 0x00, + 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x2b, + 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, 0x5a, 0x00, 0x00, + 0x00, 0x56, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x5b, + 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xc2, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xd5, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, + 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2b, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x17, 0x00, 0x04, 0x00, 0x7d, + 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x7e, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x7d, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x7e, 0x01, 0x00, 0x00, 0x7f, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x85, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x86, 0x01, 0x00, 0x00, 0x85, 0x01, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x87, 0x01, 0x00, + 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x8f, 0x01, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x93, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x93, 0x01, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x96, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, + 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xcb, + 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, + 0xf2, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, + 0x00, 0x11, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x16, 0x01, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x4b, + 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfb, 0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, + 0x00, 0x25, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x81, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x36, 0x00, + 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, + 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3a, 0x00, + 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3f, + 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, + 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, + 0x00, 0x37, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x46, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4e, + 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, + 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, + 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x5c, + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x5f, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0x62, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x22, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x68, 0x00, + 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x68, + 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, + 0x00, 0x64, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6b, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x6b, + 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x6e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x6e, + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x72, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x73, 0x00, + 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, + 0x00, 0x64, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x54, 0x00, + 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x75, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, + 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0xb4, + 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0xf7, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x7e, 0x00, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x05, 0x00, + 0x7d, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, + 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, + 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x84, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, + 0x00, 0x88, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8a, + 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x8b, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x8b, 0x00, + 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0xf9, + 0x00, 0x02, 0x00, 0x85, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x93, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x94, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x95, 0x00, + 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x95, + 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x85, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x85, 0x00, 0x00, 0x00, + 0xf9, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x96, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x9b, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x9d, 0x00, + 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, 0x9d, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x9e, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa6, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xa7, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, + 0x00, 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xa9, + 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, + 0xaa, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, + 0x00, 0xab, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x9e, 0x00, + 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xad, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x81, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0xb2, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, + 0x00, 0xb3, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x70, 0x00, + 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xb5, + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x28, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x05, 0x00, 0x7d, 0x00, + 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0xbb, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, + 0xbb, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xba, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xbc, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xbd, 0x00, + 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xf9, + 0x00, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, + 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, + 0x00, 0xbe, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, + 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xc4, + 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, + 0xc9, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, + 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0xf9, 0x00, 0x02, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, + 0x00, 0xcf, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xd1, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xd2, + 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, + 0xd2, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0xd4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0xd6, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x2f, + 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, + 0xd8, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x02, 0x00, 0xce, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xda, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0xcc, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xde, 0x00, + 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0xcc, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0xcc, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x2c, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, + 0x00, 0xe4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x52, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, + 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, + 0x07, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, + 0x00, 0xe7, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xd0, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, + 0x00, 0xcc, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xea, 0x00, + 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xf9, + 0x00, 0x02, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, + 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, + 0x00, 0xed, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0xee, 0x00, + 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, + 0x15, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0xee, 0x00, + 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, + 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, + 0xf6, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, + 0x00, 0x15, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0xf2, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0xfa, + 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, + 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xf9, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, + 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x01, + 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x02, + 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, + 0x41, 0x00, 0x07, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, + 0x00, 0x2c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x01, + 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, + 0x09, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, + 0x00, 0x0a, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x06, 0x01, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0e, + 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, + 0xf9, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x00, + 0x00, 0x0f, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x14, 0x01, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x15, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x11, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, + 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, + 0x11, 0x01, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00, 0x17, 0x01, 0x00, + 0x00, 0x18, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x16, 0x01, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x1e, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x1f, 0x01, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1a, 0x01, + 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x0d, + 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x22, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, + 0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x22, 0x01, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, + 0x00, 0x20, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x29, 0x01, + 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, 0x1a, + 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, + 0x2a, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x16, 0x01, 0x00, + 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x2d, 0x01, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00, + 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, 0x30, 0x01, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x28, 0x01, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0xbe, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x33, + 0x01, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x35, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x33, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, + 0x00, 0xf8, 0x00, 0x02, 0x00, 0x34, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x01, + 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x37, + 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, + 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x39, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3c, + 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x3d, 0x01, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3e, 0x01, 0x00, + 0x00, 0x1b, 0x01, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3f, 0x01, + 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x36, 0x01, 0x00, 0x00, 0x3f, + 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x15, 0x00, + 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x40, 0x01, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, + 0x00, 0x40, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0xf2, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, + 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x49, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4a, 0x01, 0x00, + 0x00, 0x48, 0x01, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x4a, 0x01, + 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x35, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x35, 0x01, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x4e, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x4d, 0x01, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x83, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x53, + 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x53, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, + 0x00, 0x55, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0xc2, + 0x00, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, + 0x00, 0xc2, 0x00, 0x00, 0x00, 0x59, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2c, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5a, 0x01, 0x00, 0x00, 0x59, 0x01, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, + 0x00, 0x5a, 0x01, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5d, 0x01, + 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0c, + 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, + 0x54, 0x01, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x5d, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x5e, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf9, 0x00, + 0x02, 0x00, 0x60, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x60, 0x01, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x62, + 0x01, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x64, 0x01, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x64, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x65, 0x01, 0x00, + 0x00, 0x5f, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x65, 0x01, + 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xd5, 0x00, 0x00, 0x00, 0x67, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xd4, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x67, 0x01, 0x00, 0x00, + 0xb0, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x69, 0x01, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, + 0x00, 0xfa, 0x00, 0x04, 0x00, 0x69, 0x01, 0x00, 0x00, 0x61, 0x01, 0x00, 0x00, 0x62, 0x01, 0x00, 0x00, 0xf8, 0x00, + 0x02, 0x00, 0x61, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6a, 0x01, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x6b, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, + 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x6b, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x6c, 0x01, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x6e, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x82, + 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, 0x6e, 0x01, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0x6f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x71, 0x01, 0x00, 0x00, 0x70, 0x01, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x72, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x41, + 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x72, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x73, 0x01, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x71, + 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x77, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, + 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, + 0x00, 0x00, 0x6a, 0x01, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x63, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, + 0x63, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, + 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x7a, 0x01, 0x00, 0x00, 0x79, 0x01, 0x00, 0x00, 0x2c, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x7a, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x60, + 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x62, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x7f, 0x01, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x81, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xbe, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, 0x81, + 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfa, 0x00, 0x04, 0x00, 0x82, 0x01, 0x00, 0x00, 0x83, 0x01, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, + 0x00, 0x83, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x86, 0x01, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x88, 0x01, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x7d, 0x01, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x57, + 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x8b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8e, 0x00, + 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x3e, + 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x84, 0x01, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x84, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, + 0x00, 0x8f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x91, 0x01, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x91, 0x01, 0x00, 0x00, 0x90, + 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x95, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x94, 0x01, 0x00, + 0x00, 0x95, 0x01, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; +unsigned int vkvg_main_frag_spv_len = 9532; +unsigned char vkvg_main_vert_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, + 0x00, 0x27, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x4c, 0x00, + 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, + 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, + 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, + 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, + 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, + 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, + 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x50, + 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x50, 0x75, 0x73, + 0x68, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x66, 0x75, 0x6c, 0x6c, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x51, 0x75, 0x61, 0x64, 0x5f, + 0x73, 0x72, 0x63, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x6f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x00, 0x06, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x6d, 0x61, 0x74, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x74, 0x49, 0x6e, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x70, 0x63, 0x00, + 0x00, 0x05, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x4d, 0x61, 0x74, 0x00, 0x00, 0x05, 0x00, + 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x53, 0x72, 0x63, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x69, 0x6e, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x05, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x6f, 0x75, 0x74, 0x4f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x3e, 0x00, 0x00, + 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x06, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x00, 0x06, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x43, 0x6c, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x00, 0x06, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x43, 0x75, + 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x6f, 0x73, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x04, 0x00, 0x51, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x54, + 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, + 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, + 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, + 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x48, + 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x48, 0x00, + 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2f, + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, + 0x3e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x51, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x08, 0x00, 0x0d, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x26, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x31, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x15, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x06, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x45, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x17, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbf, 0x2c, 0x00, 0x06, 0x00, 0x4a, 0x00, + 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x53, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2c, 0x00, 0x05, 0x00, 0x0b, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x7a, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, + 0x00, 0x1a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x05, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x00, 0x29, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x05, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, + 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2f, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, + 0x00, 0x34, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x35, 0x00, + 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x37, + 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfa, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, + 0x00, 0x39, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x42, 0x00, + 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, + 0x00, 0x47, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1c, 0x00, + 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x49, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, + 0x00, 0x52, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x52, 0x00, + 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x55, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, + 0x00, 0x42, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5b, 0x00, + 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x58, + 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x62, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x63, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, + 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, + 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, + 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x68, + 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x68, 0x00, + 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, + 0x00, 0x6e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x71, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, + 0x00, 0x72, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x81, + 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, + 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x79, + 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x7a, 0x00, 0x00, 0x00, + 0x7b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x7d, 0x00, + 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x45, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x83, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, + 0x00, 0x2e, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; +unsigned int vkvg_main_vert_spv_len = 3704; unsigned char vkvg_main_lcd_frag_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x25, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, - 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, - 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, - 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x45, 0x58, 0x54, 0x5f, 0x73, - 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, - 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, - 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, - 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, - 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, - 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, - 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x46, - 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4d, 0x61, - 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x5f, 0x75, 0x62, 0x6f, - 0x47, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, - 0x72, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x70, 0x73, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x63, 0x70, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x75, 0x62, 0x6f, 0x47, - 0x72, 0x61, 0x64, 0x00, 0x05, 0x00, 0x09, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0x67, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x50, 0x6f, 0x73, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x58, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x78, 0x00, 0x00, 0x00, - 0x67, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x64, 0x50, - 0x6f, 0x73, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x58, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x88, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x78, 0x4c, 0x6f, 0x63, - 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x00, 0x05, 0x00, 0x03, 0x00, - 0xae, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0xdc, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x46, 0x6f, 0x6e, 0x74, 0x55, 0x56, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0xe5, 0x00, 0x00, 0x00, - 0x66, 0x6f, 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x00, 0x05, 0x00, 0x06, 0x00, - 0xec, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x46, 0x72, 0x61, 0x67, 0x43, - 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0xee, 0x00, 0x00, 0x00, 0x4e, 0x55, 0x4d, 0x5f, 0x53, 0x41, 0x4d, 0x50, - 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x4e, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0xdc, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xe5, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0xec, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0xee, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, - 0x4b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, - 0x5b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x06, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x98, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xad, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0xda, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xdb, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0xdb, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x19, 0x00, 0x09, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x03, 0x00, 0xe3, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe3, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xe4, 0x00, 0x00, 0x00, - 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0xeb, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0xee, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xad, 0x00, 0x00, 0x00, - 0xae, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfb, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x19, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x25, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, - 0x4e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x19, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x69, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x69, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x6b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, - 0x6d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x6f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x74, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x76, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x7b, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x82, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, - 0x7d, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x78, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x87, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x88, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x90, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x91, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x93, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, - 0x93, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, - 0x96, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x98, 0x00, 0x00, 0x00, - 0x99, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x9e, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x9f, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, - 0x9f, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, - 0xa1, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xa3, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xa7, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, - 0xa3, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, - 0xa8, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, - 0xaa, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0xae, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xaf, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xaf, 0x00, 0x00, 0x00, - 0xf6, 0x00, 0x04, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xb3, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, - 0xb4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xb7, 0x00, 0x00, 0x00, - 0xb8, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, - 0xb8, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, - 0xba, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0xb0, 0x00, 0x05, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, - 0xb5, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0xbc, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, - 0xae, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0xbf, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x98, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xc2, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, - 0xc4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xc6, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, - 0xc6, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xc8, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0xca, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0xcb, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xcd, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, - 0xcd, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, - 0xcf, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xd1, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, - 0xd1, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xd3, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, - 0xd2, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2e, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, - 0xd3, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0xd4, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xb2, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, - 0xd5, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0xae, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xaf, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xb1, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x13, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x29, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xde, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x05, 0x00, - 0xbb, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0xe1, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0xdf, 0x00, 0x00, 0x00, - 0xe0, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0xe0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0xe3, 0x00, 0x00, 0x00, - 0xe6, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0xda, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, - 0xe6, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, - 0xe9, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xe1, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xe1, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xec, 0x00, 0x00, 0x00, - 0xed, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 -}; -unsigned int vkvg_main_lcd_frag_spv_len = 5784; -unsigned char wired_frag_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, - 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, - 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, - 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x45, 0x58, 0x54, 0x5f, 0x73, - 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, - 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, - 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, - 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, - 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, - 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, - 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x46, - 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, - 0x4d, 0x61, 0x70, 0x00, 0x05, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x5f, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x00, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x73, 0x74, 0x6f, 0x70, 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x63, 0x70, 0x00, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x46, 0x6f, - 0x6e, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4f, 0x70, 0x61, 0x63, 0x69, 0x74, - 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x4e, 0x55, 0x4d, 0x5f, 0x53, 0x41, 0x4d, 0x50, - 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x24, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x3f, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 -}; + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x25, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, + 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, + 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, + 0x4c, 0x5f, 0x45, 0x58, 0x54, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, + 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, + 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, + 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0e, 0x00, + 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x16, + 0x00, 0x00, 0x00, 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, + 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00, 0x75, 0x76, + 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0x5f, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5c, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x70, 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, + 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x63, 0x70, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x5e, 0x00, + 0x00, 0x00, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x05, 0x00, 0x09, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x67, + 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x6f, 0x73, 0x52, 0x6f, 0x74, 0x61, + 0x74, 0x65, 0x64, 0x58, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x78, 0x00, 0x00, 0x00, 0x67, 0x72, 0x61, + 0x64, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x64, 0x50, 0x6f, 0x73, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x58, + 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x88, + 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x05, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x78, 0x4c, 0x6f, 0x63, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, + 0x00, 0x05, 0x00, 0x03, 0x00, 0xae, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0xdc, 0x00, + 0x00, 0x00, 0x69, 0x6e, 0x46, 0x6f, 0x6e, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0xe5, + 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x00, 0x05, 0x00, 0x06, 0x00, 0xec, 0x00, 0x00, 0x00, + 0x6f, 0x75, 0x74, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, + 0x00, 0xee, 0x00, 0x00, 0x00, 0x4e, 0x55, 0x4d, 0x5f, 0x53, 0x41, 0x4d, 0x50, 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, + 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0x47, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, + 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4e, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x04, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x5e, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xdc, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xec, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0xee, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, + 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, + 0x00, 0x27, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x04, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x57, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x06, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0x3b, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x98, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xad, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0xda, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xda, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xdb, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x19, 0x00, 0x09, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, + 0x00, 0x03, 0x00, 0xe3, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xe4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x32, + 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0x6c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x78, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, + 0x00, 0x2c, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xad, 0x00, + 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0xf7, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, + 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2a, 0x00, + 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, + 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x31, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, + 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x35, 0x00, + 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x36, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, + 0x00, 0x39, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x37, 0x00, + 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x25, + 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, + 0x00, 0x1b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3f, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x42, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x43, 0x00, + 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, + 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x47, 0x00, + 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, + 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x4e, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, + 0x00, 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, + 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, + 0x62, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, + 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, + 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x69, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x6b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6f, + 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x71, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, + 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x33, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x74, 0x00, + 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x75, + 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, + 0x76, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, + 0x00, 0x5f, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x79, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x7b, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7a, 0x00, + 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x5e, + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x81, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x85, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x6c, + 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, + 0x86, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, + 0x00, 0x29, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x88, + 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, + 0x00, 0x8c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x91, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x95, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x83, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x03, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x98, 0x00, 0x00, 0x00, + 0x99, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x98, 0x00, + 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, + 0x00, 0x9e, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xa1, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xa2, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, 0xa4, + 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xa6, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa7, 0x00, + 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa8, + 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xa9, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa9, 0x00, + 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xaa, + 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, + 0xac, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, + 0x00, 0xab, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0xae, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x02, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xb3, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x7c, 0x00, + 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xb7, + 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x27, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, + 0x00, 0xba, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00, 0xbb, 0x00, + 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0xbc, + 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xb0, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x98, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, 0xc4, + 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc7, 0x00, + 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc8, + 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xc9, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, + 0x00, 0xae, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xca, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x5e, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xcd, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, + 0x00, 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xcd, 0x00, + 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xc9, + 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x31, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x50, 0x00, + 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xd2, + 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xb2, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xd5, + 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, + 0xd5, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xae, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, + 0x00, 0xf9, 0x00, 0x02, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xf9, 0x00, + 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x14, + 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, + 0xdd, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xde, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x05, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xdf, 0x00, + 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0xdf, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0xe3, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, + 0x00, 0xe5, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0xda, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xdc, 0x00, + 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe7, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xe1, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xed, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xec, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; +unsigned int vkvg_main_lcd_frag_spv_len = 5784; +unsigned char wired_frag_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, + 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, + 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, + 0x4c, 0x5f, 0x45, 0x58, 0x54, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, + 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, + 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, + 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, + 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x4d, + 0x61, 0x70, 0x00, 0x05, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, + 0x05, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x5f, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, + 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x70, 0x73, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x63, 0x70, 0x00, 0x00, + 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x05, 0x00, + 0x05, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x46, 0x6f, 0x6e, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, + 0x00, 0x26, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x2b, + 0x00, 0x00, 0x00, 0x4e, 0x55, 0x4d, 0x5f, 0x53, 0x41, 0x4d, 0x50, 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, + 0x00, 0x17, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x19, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x1a, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x47, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, + 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x24, + 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, + 0x00, 0x26, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2a, 0x00, + 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x19, 0x00, + 0x09, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x03, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, + 0x00, 0x17, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x14, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x36, + 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; unsigned int wired_frag_spv_len = 1700; diff --git a/src/stb_image.h b/src/stb_image.h index 8b4af4d..b79dd50 100644 --- a/src/stb_image.h +++ b/src/stb_image.h @@ -1,8 +1,8 @@ /* stb_image - v2.19 - public domain image loader - http://nothings.org/stb - no warranty implied; use at your own risk + no warranty implied; use at your own risk Do this: - #define STB_IMAGE_IMPLEMENTATION + #define STB_IMAGE_IMPLEMENTATION before you include this file in *one* C or C++ file to create the implementation. // i.e. it should look like this: @@ -17,27 +17,27 @@ QUICK NOTES: - Primarily of interest to game developers and other people who can - avoid problematic images and only need the trivial interface + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface - JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) - PNG 1/2/4/8/16-bit-per-channel + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel - TGA (not sure what subset, if a subset) - BMP non-1bpp, non-RLE - PSD (composited view only, no extra channels, 8/16 bit-per-channel) + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) - GIF (*comp always reports as 4-channel) - HDR (radiance rgbE format) - PIC (Softimage PIC) - PNM (PPM and PGM binary only) + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) - Animated GIF still needs a proper API, but here's one way to do it: - http://gist.github.com/urraka/685d9a6340b26b830d49 + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 - - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - - decode from arbitrary I/O callbacks - - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) Full documentation under "DOCUMENTATION" below. @@ -48,20 +48,20 @@ LICENSE RECENT REVISION HISTORY: - 2.19 (2018-02-11) fix warning - 2.18 (2018-01-30) fix warnings - 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings - 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes - 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 - RGB-format JPEG; remove white matting in PSD; - allocate large structures on the stack; - correct channel count for PNG & BMP - 2.10 (2016-01-22) avoid warning introduced in 2.09 - 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED See end of file for full revision history. @@ -69,38 +69,38 @@ RECENT REVISION HISTORY: ============================ Contributors ========================= Image formats Extensions, features - Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) - Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) - Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) - Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) - Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) - Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) - Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) - github:urraka (animated gif) Junggon Kim (PNM comments) - Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) - socks-the-fox (16-bit PNG) - Jeremy Sawicki (handle all ImageNet JPGs) + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) - Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) - Arseny Kapoulkine - John-Mark Allen + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine + John-Mark Allen Bug & warning fixes - Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan - Dave Moore Roy Eltham Hayaki Saito Nathan Reed - Won Chun Luke Graham Johan Duparc Nick Verigakis - the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh - Janez Zemva John Bartholomew Michal Cichon github:romigrou - Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar - Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex - Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 - Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw - Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus - Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo - Christian Floisand Kevin Schmidt github:darealshinji - Blazej Dariusz Roszkowski github:Michaelangel007 + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan + Dave Moore Roy Eltham Hayaki Saito Nathan Reed + Won Chun Luke Graham Johan Duparc Nick Verigakis + the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar + Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex + Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 + Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw + Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus + Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo + Christian Floisand Kevin Schmidt github:darealshinji + Blazej Dariusz Roszkowski github:Michaelangel007 */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -302,24 +302,22 @@ RECENT REVISION HISTORY: // want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB // - #ifndef STBI_NO_STDIO #include #endif // STBI_NO_STDIO #define STBI_VERSION 1 -enum -{ - STBI_default = 0, // only used for desired_channels +enum { + STBI_default = 0, // only used for desired_channels - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 }; -typedef unsigned char stbi_uc; +typedef unsigned char stbi_uc; typedef unsigned short stbi_us; #ifdef __cplusplus @@ -341,11 +339,11 @@ extern "C" { // load image by filename, open file, or memory buffer // -typedef struct -{ - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read - void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative - int (*eof) (void *user); // returns nonzero if we are at end of file/data +typedef struct { + int (*read)(void *user, char *data, + int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip)(void *user, int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof)(void *user); // returns nonzero if we are at end of file/data } stbi_io_callbacks; //////////////////////////////////// @@ -353,16 +351,18 @@ typedef struct // 8-bits-per-channel interface // -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, + int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, + int *channels_in_file, int desired_channels); #ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, + int *comp, int req_comp); #endif - #ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); // for stbi_load_from_file, file pointer is left pointing immediately after image #endif @@ -371,11 +371,13 @@ STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in // 16-bits-per-channel interface // -STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, + int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, + int *channels_in_file, int desired_channels); #ifndef STBI_NO_STDIO -STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); #endif @@ -384,56 +386,55 @@ STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_i // float-per-channel interface // #ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, + int desired_channels); +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, + int *channels_in_file, int desired_channels); - #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); - #endif +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif #endif #ifndef STBI_NO_HDR - STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); - STBIDEF void stbi_hdr_to_ldr_scale(float scale); +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); +STBIDEF void stbi_hdr_to_ldr_scale(float scale); #endif // STBI_NO_HDR #ifndef STBI_NO_LINEAR - STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); - STBIDEF void stbi_ldr_to_hdr_scale(float scale); +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); +STBIDEF void stbi_ldr_to_hdr_scale(float scale); #endif // STBI_NO_LINEAR // stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); #ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename); -STBIDEF int stbi_is_hdr_from_file(FILE *f); +STBIDEF int stbi_is_hdr(char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); #endif // STBI_NO_STDIO - // get a VERY brief reason for failure // NOT THREADSAFE -STBIDEF const char *stbi_failure_reason (void); +STBIDEF const char *stbi_failure_reason(void); // free the loaded image -- this is just free() -STBIDEF void stbi_image_free (void *retval_from_stbi_load); +STBIDEF void stbi_image_free(void *retval_from_stbi_load); // get image dimensions & components without fully decoding -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); #ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit (char const *filename); -STBIDEF int stbi_is_16_bit_from_file(FILE *f); +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit(char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); #endif - - // for image formats that explicitly notate that they have premultiplied alpha, // we just return the colors as stored in the file. set this flag to force // unpremultiplication. results are undefined if the unpremultiply overflow. @@ -449,13 +450,13 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); // ZLIB client - used by PNG, available for other purposes STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, + int parse_header); STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); #ifdef __cplusplus } @@ -468,44 +469,42 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #ifdef STB_IMAGE_IMPLEMENTATION -#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ - || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ - || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ - || defined(STBI_ONLY_ZLIB) - #ifndef STBI_ONLY_JPEG - #define STBI_NO_JPEG - #endif - #ifndef STBI_ONLY_PNG - #define STBI_NO_PNG - #endif - #ifndef STBI_ONLY_BMP - #define STBI_NO_BMP - #endif - #ifndef STBI_ONLY_PSD - #define STBI_NO_PSD - #endif - #ifndef STBI_ONLY_TGA - #define STBI_NO_TGA - #endif - #ifndef STBI_ONLY_GIF - #define STBI_NO_GIF - #endif - #ifndef STBI_ONLY_HDR - #define STBI_NO_HDR - #endif - #ifndef STBI_ONLY_PIC - #define STBI_NO_PIC - #endif - #ifndef STBI_ONLY_PNM - #define STBI_NO_PNM - #endif +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) || defined(STBI_ONLY_TGA) || \ + defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || \ + defined(STBI_ONLY_PNM) || defined(STBI_ONLY_ZLIB) +#ifndef STBI_ONLY_JPEG +#define STBI_NO_JPEG +#endif +#ifndef STBI_ONLY_PNG +#define STBI_NO_PNG +#endif +#ifndef STBI_ONLY_BMP +#define STBI_NO_BMP +#endif +#ifndef STBI_ONLY_PSD +#define STBI_NO_PSD +#endif +#ifndef STBI_ONLY_TGA +#define STBI_NO_TGA +#endif +#ifndef STBI_ONLY_GIF +#define STBI_NO_GIF +#endif +#ifndef STBI_ONLY_HDR +#define STBI_NO_HDR +#endif +#ifndef STBI_ONLY_PIC +#define STBI_NO_PIC +#endif +#ifndef STBI_ONLY_PNM +#define STBI_NO_PNM +#endif #endif #if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) #define STBI_NO_ZLIB #endif - #include #include // ptrdiff_t on osx #include @@ -513,7 +512,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #include #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include // ldexp, pow +#include // ldexp, pow #endif #ifndef STBI_NO_STDIO @@ -525,38 +524,36 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define STBI_ASSERT(x) assert(x) #endif - #ifndef _MSC_VER - #ifdef __cplusplus - #define stbi_inline inline - #else - #define stbi_inline - #endif +#ifdef __cplusplus +#define stbi_inline inline #else - #define stbi_inline __forceinline +#define stbi_inline +#endif +#else +#define stbi_inline __forceinline #endif - #ifdef _MSC_VER typedef unsigned short stbi__uint16; -typedef signed short stbi__int16; +typedef signed short stbi__int16; typedef unsigned int stbi__uint32; -typedef signed int stbi__int32; +typedef signed int stbi__int32; #else #include typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; +typedef int16_t stbi__int16; typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; +typedef int32_t stbi__int32; #endif // should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; +typedef unsigned char validate_uint32[sizeof(stbi__uint32) == 4 ? 1 : -1]; #ifdef _MSC_VER -#define STBI_NOTUSED(v) (void)(v) +#define STBI_NOTUSED(v) (void)(v) #else -#define STBI_NOTUSED(v) (void)sizeof(v) +#define STBI_NOTUSED(v) (void)sizeof(v) #endif #ifdef _MSC_VER @@ -564,9 +561,9 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #endif #ifdef STBI_HAS_LROTL - #define stbi_lrot(x,y) _lrotl(x,y) +#define stbi_lrot(x, y) _lrotl(x, y) #else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#define stbi_lrot(x, y) (((x) << (y)) | ((x) >> (32 - (y)))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) @@ -578,13 +575,13 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #endif #ifndef STBI_MALLOC -#define STBI_MALLOC(sz) malloc(sz) -#define STBI_REALLOC(p,newsz) realloc(p,newsz) -#define STBI_FREE(p) free(p) +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p, newsz) realloc(p, newsz) +#define STBI_FREE(p) free(p) #endif #ifndef STBI_REALLOC_SIZED -#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#define STBI_REALLOC_SIZED(p, oldsz, newsz) STBI_REALLOC(p, newsz) #endif // x86/x64 detection @@ -626,43 +623,39 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #ifdef _MSC_VER -#if _MSC_VER >= 1400 // not VC6 -#include // __cpuid -static int stbi__cpuid3(void) -{ - int info[4]; - __cpuid(info,1); - return info[3]; +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) { + int info[4]; + __cpuid(info, 1); + return info[3]; } #else -static int stbi__cpuid3(void) -{ - int res; - __asm { +static int stbi__cpuid3(void) { + int res; + __asm { mov eax,1 cpuid mov res,edx - } - return res; + } + return res; } #endif #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name -static int stbi__sse2_available(void) -{ - int info3 = stbi__cpuid3(); - return ((info3 >> 26) & 1) != 0; +static int stbi__sse2_available(void) { + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; } #else // assume GCC-style if not VC++ #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) -static int stbi__sse2_available(void) -{ - // If we're even attempting to compile this on GCC/Clang, that means - // -msse2 is on, which means the compiler is allowed to use SSE2 - // instructions at will, and so are we. - return 1; +static int stbi__sse2_available(void) { + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; } #endif #endif @@ -688,176 +681,146 @@ static int stbi__sse2_available(void) // stbi__context structure is our basic context used by all images, so it // contains all the IO context, plus some basic image information -typedef struct -{ - stbi__uint32 img_x, img_y; - int img_n, img_out_n; +typedef struct { + stbi__uint32 img_x, img_y; + int img_n, img_out_n; - stbi_io_callbacks io; - void *io_user_data; + stbi_io_callbacks io; + void *io_user_data; - int read_from_callbacks; - int buflen; - stbi_uc buffer_start[128]; + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original, *img_buffer_original_end; + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; } stbi__context; - static void stbi__refill_buffer(stbi__context *s); // initialize a memory-decode context -static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; - s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) { + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *)buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *)buffer + len; } // initialize a callback-based context -static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) -{ - s->io = *c; - s->io_user_data = user; - s->buflen = sizeof(s->buffer_start); - s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; - stbi__refill_buffer(s); - s->img_buffer_original_end = s->img_buffer_end; +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) { + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; } #ifndef STBI_NO_STDIO -static int stbi__stdio_read(void *user, char *data, int size) -{ - return (int) fread(data,1,size,(FILE*) user); -} +static int stbi__stdio_read(void *user, char *data, int size) { return (int)fread(data, 1, size, (FILE *)user); } -static void stbi__stdio_skip(void *user, int n) -{ - fseek((FILE*) user, n, SEEK_CUR); -} +static void stbi__stdio_skip(void *user, int n) { fseek((FILE *)user, n, SEEK_CUR); } -static int stbi__stdio_eof(void *user) -{ - return feof((FILE*) user); -} +static int stbi__stdio_eof(void *user) { return feof((FILE *)user); } -static stbi_io_callbacks stbi__stdio_callbacks = -{ - stbi__stdio_read, - stbi__stdio_skip, - stbi__stdio_eof, +static stbi_io_callbacks stbi__stdio_callbacks = { + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, }; -static void stbi__start_file(stbi__context *s, FILE *f) -{ - stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); -} +static void stbi__start_file(stbi__context *s, FILE *f) { stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *)f); } -//static void stop_file(stbi__context *s) { } +// static void stop_file(stbi__context *s) { } #endif // !STBI_NO_STDIO -static void stbi__rewind(stbi__context *s) -{ - // conceptually rewind SHOULD rewind to the beginning of the stream, - // but we just rewind to the beginning of the initial buffer, because - // we only use it after doing 'test', which only ever looks at at most 92 bytes - s->img_buffer = s->img_buffer_original; - s->img_buffer_end = s->img_buffer_original_end; +static void stbi__rewind(stbi__context *s) { + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; } -enum -{ - STBI_ORDER_RGB, - STBI_ORDER_BGR -}; +enum { STBI_ORDER_RGB, STBI_ORDER_BGR }; -typedef struct -{ - int bits_per_channel; - int num_channels; - int channel_order; +typedef struct { + int bits_per_channel; + int num_channels; + int channel_order; } stbi__result_info; #ifndef STBI_NO_JPEG -static int stbi__jpeg_test(stbi__context *s); -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNG -static int stbi__png_test(stbi__context *s); -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__png_is16(stbi__context *s); +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); #endif #ifndef STBI_NO_BMP -static int stbi__bmp_test(stbi__context *s); -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_TGA -static int stbi__tga_test(stbi__context *s); -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s); -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__psd_is16(stbi__context *s); +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); #endif #ifndef STBI_NO_HDR -static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PIC -static int stbi__pic_test(stbi__context *s); -static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_GIF -static int stbi__gif_test(stbi__context *s); -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s); -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); #endif // this is not threadsafe static const char *stbi__g_failure_reason; -STBIDEF const char *stbi_failure_reason(void) -{ - return stbi__g_failure_reason; -} +STBIDEF const char *stbi_failure_reason(void) { return stbi__g_failure_reason; } -static int stbi__err(const char *str) -{ - stbi__g_failure_reason = str; - return 0; +static int stbi__err(const char *str) { + stbi__g_failure_reason = str; + return 0; } -static void *stbi__malloc(size_t size) -{ - return STBI_MALLOC(size); -} +static void *stbi__malloc(size_t size) { return STBI_MALLOC(size); } // stb_image uses ints pervasively, including for offset calculations. // therefore the largest decoded image size we can support with the @@ -871,66 +834,63 @@ static void *stbi__malloc(size_t size) // return 1 if the sum is valid, 0 on overflow. // negative terms are considered invalid. -static int stbi__addsizes_valid(int a, int b) -{ - if (b < 0) return 0; - // now 0 <= b <= INT_MAX, hence also - // 0 <= INT_MAX - b <= INTMAX. - // And "a + b <= INT_MAX" (which might overflow) is the - // same as a <= INT_MAX - b (no overflow) - return a <= INT_MAX - b; +static int stbi__addsizes_valid(int a, int b) { + if (b < 0) + return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; } // returns 1 if the product is valid, 0 on overflow. // negative factors are considered invalid. -static int stbi__mul2sizes_valid(int a, int b) -{ - if (a < 0 || b < 0) return 0; - if (b == 0) return 1; // mul-by-0 is always safe - // portable way to check for no overflows in a*b - return a <= INT_MAX/b; +static int stbi__mul2sizes_valid(int a, int b) { + if (a < 0 || b < 0) + return 0; + if (b == 0) + return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX / b; } // returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow -static int stbi__mad2sizes_valid(int a, int b, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +static int stbi__mad2sizes_valid(int a, int b, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a * b, add); } // returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow -static int stbi__mad3sizes_valid(int a, int b, int c, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__addsizes_valid(a*b*c, add); +static int stbi__mad3sizes_valid(int a, int b, int c, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a * b, c) && stbi__addsizes_valid(a * b * c, add); } // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a * b, c) && stbi__mul2sizes_valid(a * b * c, d) && + stbi__addsizes_valid(a * b * c * d, add); } #endif // mallocs with size overflow checking -static void *stbi__malloc_mad2(int a, int b, int add) -{ - if (!stbi__mad2sizes_valid(a, b, add)) return NULL; - return stbi__malloc(a*b + add); +static void *stbi__malloc_mad2(int a, int b, int add) { + if (!stbi__mad2sizes_valid(a, b, add)) + return NULL; + return stbi__malloc(a * b + add); } -static void *stbi__malloc_mad3(int a, int b, int c, int add) -{ - if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; - return stbi__malloc(a*b*c + add); +static void *stbi__malloc_mad3(int a, int b, int c, int add) { + if (!stbi__mad3sizes_valid(a, b, c, add)) + return NULL; + return stbi__malloc(a * b * c + add); } #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) -{ - if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; - return stbi__malloc(a*b*c*d + add); +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) { + if (!stbi__mad4sizes_valid(a, b, c, d, add)) + return NULL; + return stbi__malloc(a * b * c * d + add); } #endif @@ -939,365 +899,356 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) // stbi__errpuc - error returning pointer to unsigned char #ifdef STBI_NO_FAILURE_STRINGS - #define stbi__err(x,y) 0 +#define stbi__err(x, y) 0 #elif defined(STBI_FAILURE_USERMSG) - #define stbi__err(x,y) stbi__err(y) +#define stbi__err(x, y) stbi__err(y) #else - #define stbi__err(x,y) stbi__err(x) +#define stbi__err(x, y) stbi__err(x) #endif -#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) -#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpf(x, y) ((float *)(size_t)(stbi__err(x, y) ? NULL : NULL)) +#define stbi__errpuc(x, y) ((unsigned char *)(size_t)(stbi__err(x, y) ? NULL : NULL)) -STBIDEF void stbi_image_free(void *retval_from_stbi_load) -{ - STBI_FREE(retval_from_stbi_load); -} +STBIDEF void stbi_image_free(void *retval_from_stbi_load) { STBI_FREE(retval_from_stbi_load); } #ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); #endif #ifndef STBI_NO_HDR -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); #endif static int stbi__vertically_flip_on_load = 0; -STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) -{ - stbi__vertically_flip_on_load = flag_true_if_should_flip; +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) { + stbi__vertically_flip_on_load = flag_true_if_should_flip; } -static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields - ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed - ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order - ri->num_channels = 0; - - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); - #endif - #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); - return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif - - #ifndef STBI_NO_TGA - // test tga last because it's a crappy test! - if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp, ri); - #endif - - return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); -} - -static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi_uc *reduced; +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, + int bpc) { + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; - reduced = (stbi_uc *) stbi__malloc(img_len); - if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); +#ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) + return stbi__jpeg_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_PNG + if (stbi__png_test(s)) + return stbi__png_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) + return stbi__bmp_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_GIF + if (stbi__gif_test(s)) + return stbi__gif_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_PSD + if (stbi__psd_test(s)) + return stbi__psd_load(s, x, y, comp, req_comp, ri, bpc); +#endif +#ifndef STBI_NO_PIC + if (stbi__pic_test(s)) + return stbi__pic_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) + return stbi__pnm_load(s, x, y, comp, req_comp, ri); +#endif + +#ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x, y, comp, req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } +#endif - for (i = 0; i < img_len; ++i) - reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling +#ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s, x, y, comp, req_comp, ri); +#endif - STBI_FREE(orig); - return reduced; + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); } -static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi__uint16 *enlarged; +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) { + int i; + int img_len = w * h * channels; + stbi_uc *reduced; - enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); - if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + reduced = (stbi_uc *)stbi__malloc(img_len); + if (reduced == NULL) + return stbi__errpuc("outofmem", "Out of memory"); - for (i = 0; i < img_len; ++i) - enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + for (i = 0; i < img_len; ++i) + reduced[i] = + (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling - STBI_FREE(orig); - return enlarged; + STBI_FREE(orig); + return reduced; } -static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) -{ - int row; - size_t bytes_per_row = (size_t)w * bytes_per_pixel; - stbi_uc temp[2048]; - stbi_uc *bytes = (stbi_uc *)image; - - for (row = 0; row < (h>>1); row++) { - stbi_uc *row0 = bytes + row*bytes_per_row; - stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; - // swap row0 with row1 - size_t bytes_left = bytes_per_row; - while (bytes_left) { - size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); - memcpy(temp, row0, bytes_copy); - memcpy(row0, row1, bytes_copy); - memcpy(row1, temp, bytes_copy); - row0 += bytes_copy; - row1 += bytes_copy; - bytes_left -= bytes_copy; - } - } -} - -static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) -{ - int slice; - int slice_size = w * h * bytes_per_pixel; +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) { + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *)stbi__malloc(img_len * 2); + if (enlarged == NULL) + return (stbi__uint16 *)stbi__errpuc("outofmem", "Out of memory"); - stbi_uc *bytes = (stbi_uc *)image; - for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; - } + for (i = 0; i < img_len; ++i) + enlarged[i] = + (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; } -static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) { + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h >> 1); row++) { + stbi_uc *row0 = bytes + row * bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1) * bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) { + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) { + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); - if (result == NULL) - return NULL; + if (result == NULL) + return NULL; - if (ri.bits_per_channel != 8) { - STBI_ASSERT(ri.bits_per_channel == 16); - result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 8; - } + if (ri.bits_per_channel != 8) { + STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *)result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } - // @TODO: move stbi__convert_format to here + // @TODO: move stbi__convert_format to here - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); - } + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } - return (unsigned char *) result; + return (unsigned char *)result; } -static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) { + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); - if (result == NULL) - return NULL; + if (result == NULL) + return NULL; - if (ri.bits_per_channel != 16) { - STBI_ASSERT(ri.bits_per_channel == 8); - result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 16; - } + if (ri.bits_per_channel != 16) { + STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *)result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } - // @TODO: move stbi__convert_format16 to here - // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); - } + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } - return (stbi__uint16 *) result; + return (stbi__uint16 *)result; } #if !defined(STBI_NO_HDR) || !defined(STBI_NO_LINEAR) -static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) -{ - if (stbi__vertically_flip_on_load && result != NULL) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); - } +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) { + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } } #endif #ifndef STBI_NO_STDIO -static FILE *stbi__fopen(char const *filename, char const *mode) -{ - FILE *f; +static FILE *stbi__fopen(char const *filename, char const *mode) { + FILE *f; #if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; + if (0 != fopen_s(&f, filename, mode)) + f = 0; #else - f = fopen(filename, mode); + f = fopen(filename, mode); #endif - return f; + return f; } +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) { + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) + return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f, x, y, comp, req_comp); + fclose(f); + return result; +} -STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - unsigned char *result; - if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { + unsigned char *result; + stbi__context s; + stbi__start_file(&s, f); + result = stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, -(int)(s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; } -STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} - -STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__uint16 *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} - -STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - stbi__uint16 *result; - if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file_16(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) { + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s, f); + result = stbi__load_and_postprocess_16bit(&s, x, y, comp, req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, -(int)(s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; } +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) { + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) + return (stbi_us *)stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f, x, y, comp, req_comp); + fclose(f); + return result; +} -#endif //!STBI_NO_STDIO +#endif //! STBI_NO_STDIO -STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, + int desired_channels) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__load_and_postprocess_16bit(&s, x, y, channels_in_file, desired_channels); } -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, + int *channels_in_file, int desired_channels) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s, x, y, channels_in_file, desired_channels); } -STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); } -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, + int req_comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); } #ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); - - result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); - if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); - } +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, + int *comp, int req_comp) { + unsigned char *result; + stbi__context s; + stbi__start_mem(&s, buffer, len); - return result; + result = (unsigned char *)stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices(result, *x, *y, *z, *comp); + } + + return result; } #endif #ifndef STBI_NO_LINEAR -static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - stbi__result_info ri; - float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); - if (hdr_data) - stbi__float_postprocess(hdr_data,x,y,comp,req_comp); - return hdr_data; - } - #endif - data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); - if (data) - return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); -} - -STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__loadf_main(&s,x,y,comp,req_comp); +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) { + unsigned char *data; +#ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s, x, y, comp, req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data, x, y, comp, req_comp); + return hdr_data; + } +#endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); } -STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__loadf_main(&s, x, y, comp, req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, + int req_comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__loadf_main(&s, x, y, comp, req_comp); } #ifndef STBI_NO_STDIO -STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - float *result; - FILE *f = stbi__fopen(filename, "rb"); - if (!f) return stbi__errpf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) { + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) + return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f, x, y, comp, req_comp); + fclose(f); + return result; } -STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_file(&s,f); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { + stbi__context s; + stbi__start_file(&s, f); + return stbi__loadf_main(&s, x, y, comp, req_comp); } #endif // !STBI_NO_STDIO @@ -1307,198 +1258,180 @@ STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_ // defined, for API simplicity; if STBI_NO_LINEAR is defined, it always // reports false! -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(buffer); - STBI_NOTUSED(len); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) { +#ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__hdr_test(&s); +#else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; +#endif } #ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; +STBIDEF int stbi_is_hdr(char const *filename) { + FILE *f = stbi__fopen(filename, "rb"); + int result = 0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; } -STBIDEF int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - long pos = ftell(f); - int res; - stbi__context s; - stbi__start_file(&s,f); - res = stbi__hdr_test(&s); - fseek(f, pos, SEEK_SET); - return res; - #else - STBI_NOTUSED(f); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_file(FILE *f) { +#ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s, f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; +#else + STBI_NOTUSED(f); + return 0; +#endif } #endif // !STBI_NO_STDIO -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(clbk); - STBI_NOTUSED(user); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) { +#ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__hdr_test(&s); +#else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; +#endif } #ifndef STBI_NO_LINEAR -static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; +static float stbi__l2h_gamma = 2.2f, stbi__l2h_scale = 1.0f; -STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } -STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } #endif -static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; - -STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } -STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } +static float stbi__h2l_gamma_i = 1.0f / 2.2f, stbi__h2l_scale_i = 1.0f; +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1 / gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1 / scale; } ////////////////////////////////////////////////////////////////////////////// // // Common code used by all image loaders // -enum -{ - STBI__SCAN_load=0, - STBI__SCAN_type, - STBI__SCAN_header -}; - -static void stbi__refill_buffer(stbi__context *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - if (n == 0) { - // at end of file, treat same as if from memory, but need to handle case - // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } else { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } -} - -stbi_inline static stbi_uc stbi__get8(stbi__context *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - if (s->read_from_callbacks) { - stbi__refill_buffer(s); - return *s->img_buffer++; - } - return 0; -} - -stbi_inline static int stbi__at_eof(stbi__context *s) -{ - if (s->io.read) { - if (!(s->io.eof)(s->io_user_data)) return 0; - // if feof() is true, check if buffer = end - // special case: we've only got the special 0 character at the end - if (s->read_from_callbacks == 0) return 1; - } - - return s->img_buffer >= s->img_buffer_end; -} - -static void stbi__skip(stbi__context *s, int n) -{ - if (n < 0) { - s->img_buffer = s->img_buffer_end; - return; - } - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } - s->img_buffer += n; -} - -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - int res, count; - - memcpy(buffer, s->img_buffer, blen); - - count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); - res = (count == (n-blen)); - s->img_buffer = s->img_buffer_end; - return res; - } - } - - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else - return 0; -} - -static int stbi__get16be(stbi__context *s) -{ - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); -} - -static stbi__uint32 stbi__get32be(stbi__context *s) -{ - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); +enum { STBI__SCAN_load = 0, STBI__SCAN_type, STBI__SCAN_header }; + +static void stbi__refill_buffer(stbi__context *s) { + int n = (s->io.read)(s->io_user_data, (char *)s->buffer_start, s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + 1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) { + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +stbi_inline static int stbi__at_eof(stbi__context *s) { + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) + return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) + return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} + +static void stbi__skip(stbi__context *s, int n) { + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int)(s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} + +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) { + if (s->io.read) { + int blen = (int)(s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char *)buffer + blen, n - blen); + res = (count == (n - blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer + n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int stbi__get16be(stbi__context *s) { + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} + +static stbi__uint32 stbi__get32be(stbi__context *s) { + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); } #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing #else -static int stbi__get16le(stbi__context *s) -{ - int z = stbi__get8(s); - return z + (stbi__get8(s) << 8); +static int stbi__get16le(stbi__context *s) { + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); } #endif #ifndef STBI_NO_BMP -static stbi__uint32 stbi__get32le(stbi__context *s) -{ - stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); +static stbi__uint32 stbi__get32le(stbi__context *s) { + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); } #endif -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - +#define STBI__BYTECAST(x) ((stbi_uc)((x)&255)) // truncate int to byte without warnings ////////////////////////////////////////////////////////////////////////////// // @@ -1511,152 +1444,197 @@ static stbi__uint32 stbi__get32le(stbi__context *s) // assume data buffer is malloced, so malloc a new one and free that one // only failure mode is malloc failing -static stbi_uc stbi__compute_y(int r, int g, int b) -{ - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); - if (good == NULL) { - STBI_FREE(data); - return stbi__errpuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; - - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; - default: STBI_ASSERT(0); - } - #undef STBI__CASE - } - - STBI_FREE(data); - return good; -} - -static stbi__uint16 stbi__compute_y_16(int r, int g, int b) -{ - return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - stbi__uint16 *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); - if (good == NULL) { - STBI_FREE(data); - return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - stbi__uint16 *src = data + j * x * img_n ; - stbi__uint16 *dest = good + j * x * req_comp; - - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; - default: STBI_ASSERT(0); - } - #undef STBI__CASE - } - - STBI_FREE(data); - return good; +static stbi_uc stbi__compute_y(int r, int g, int b) { return (stbi_uc)(((r * 77) + (g * 150) + (29 * b)) >> 8); } + +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, + unsigned int y) { + int i, j; + unsigned char *good; + + if (req_comp == img_n) + return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *)stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j = 0; j < (int)y; ++j) { + unsigned char *src = data + j * x * img_n; + unsigned char *dest = good + j * x * req_comp; + +#define STBI__COMBO(a, b) ((a)*8 + (b)) +#define STBI__CASE(a, b) \ + case STBI__COMBO(a, b): \ + for (i = x - 1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1, 2) { dest[0] = src[0], dest[1] = 255; } + break; + STBI__CASE(1, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(1, 4) { dest[0] = dest[1] = dest[2] = src[0], dest[3] = 255; } + break; + STBI__CASE(2, 1) { dest[0] = src[0]; } + break; + STBI__CASE(2, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(2, 4) { dest[0] = dest[1] = dest[2] = src[0], dest[3] = src[1]; } + break; + STBI__CASE(3, 4) { dest[0] = src[0], dest[1] = src[1], dest[2] = src[2], dest[3] = 255; } + break; + STBI__CASE(3, 1) { dest[0] = stbi__compute_y(src[0], src[1], src[2]); } + break; + STBI__CASE(3, 2) { dest[0] = stbi__compute_y(src[0], src[1], src[2]), dest[1] = 255; } + break; + STBI__CASE(4, 1) { dest[0] = stbi__compute_y(src[0], src[1], src[2]); } + break; + STBI__CASE(4, 2) { dest[0] = stbi__compute_y(src[0], src[1], src[2]), dest[1] = src[3]; } + break; + STBI__CASE(4, 3) { dest[0] = src[0], dest[1] = src[1], dest[2] = src[2]; } + break; + default: + STBI_ASSERT(0); + } +#undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) { + return (stbi__uint16)(((r * 77) + (g * 150) + (29 * b)) >> 8); +} + +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, + unsigned int y) { + int i, j; + stbi__uint16 *good; + + if (req_comp == img_n) + return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *)stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *)stbi__errpuc("outofmem", "Out of memory"); + } + + for (j = 0; j < (int)y; ++j) { + stbi__uint16 *src = data + j * x * img_n; + stbi__uint16 *dest = good + j * x * req_comp; + +#define STBI__COMBO(a, b) ((a)*8 + (b)) +#define STBI__CASE(a, b) \ + case STBI__COMBO(a, b): \ + for (i = x - 1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1, 2) { dest[0] = src[0], dest[1] = 0xffff; } + break; + STBI__CASE(1, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(1, 4) { dest[0] = dest[1] = dest[2] = src[0], dest[3] = 0xffff; } + break; + STBI__CASE(2, 1) { dest[0] = src[0]; } + break; + STBI__CASE(2, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(2, 4) { dest[0] = dest[1] = dest[2] = src[0], dest[3] = src[1]; } + break; + STBI__CASE(3, 4) { dest[0] = src[0], dest[1] = src[1], dest[2] = src[2], dest[3] = 0xffff; } + break; + STBI__CASE(3, 1) { dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); } + break; + STBI__CASE(3, 2) { dest[0] = stbi__compute_y_16(src[0], src[1], src[2]), dest[1] = 0xffff; } + break; + STBI__CASE(4, 1) { dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); } + break; + STBI__CASE(4, 2) { dest[0] = stbi__compute_y_16(src[0], src[1], src[2]), dest[1] = src[3]; } + break; + STBI__CASE(4, 3) { dest[0] = src[0], dest[1] = src[1], dest[2] = src[2]; } + break; + default: + STBI_ASSERT(0); + } +#undef STBI__CASE + } + + STBI_FREE(data); + return good; } #ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output; - if (!data) return NULL; - output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); - } - if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; - } - STBI_FREE(data); - return output; +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) { + int i, k, n; + float *output; + if (!data) + return NULL; + output = (float *)stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { + STBI_FREE(data); + return stbi__errpf("outofmem", "Out of memory"); + } + // compute number of non-alpha components + if (comp & 1) + n = comp; + else + n = comp - 1; + for (i = 0; i < x * y; ++i) { + for (k = 0; k < n; ++k) { + output[i * comp + k] = (float)(pow(data[i * comp + k] / 255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + if (k < comp) + output[i * comp + k] = data[i * comp + k] / 255.0f; + } + STBI_FREE(data); + return output; } #endif #ifndef STBI_NO_HDR -#define stbi__float2int(x) ((int) (x)) -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output; - if (!data) return NULL; - output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - } - STBI_FREE(data); - return output; +#define stbi__float2int(x) ((int)(x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) { + int i, k, n; + stbi_uc *output; + if (!data) + return NULL; + output = (stbi_uc *)stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + // compute number of non-alpha components + if (comp & 1) + n = comp; + else + n = comp - 1; + for (i = 0; i < x * y; ++i) { + for (k = 0; k < n; ++k) { + float z = (float)pow(data[i * comp + k] * stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) + z = 0; + if (z > 255) + z = 255; + output[i * comp + k] = (stbi_uc)stbi__float2int(z); + } + if (k < comp) { + float z = data[i * comp + k] * 255 + 0.5f; + if (z < 0) + z = 0; + if (z > 255) + z = 255; + output[i * comp + k] = (stbi_uc)stbi__float2int(z); + } + } + STBI_FREE(data); + return output; } #endif @@ -1684,749 +1662,760 @@ static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) #ifndef STBI_NO_JPEG // huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache - -typedef struct -{ - stbi_uc fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - stbi__uint16 code[256]; - stbi_uc values[256]; - stbi_uc size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct { + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' } stbi__huffman; -typedef struct -{ - stbi__context *s; - stbi__huffman huff_dc[4]; - stbi__huffman huff_ac[4]; - stbi__uint16 dequant[4][64]; - stbi__int16 fast_ac[4][1 << FAST_BITS]; - -// sizes for components, interleaved MCUs - int img_h_max, img_v_max; - int img_mcu_x, img_mcu_y; - int img_mcu_w, img_mcu_h; - -// definition of jpeg image component - struct - { - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; - - int x,y,w2,h2; - stbi_uc *data; - void *raw_data, *raw_coeff; - stbi_uc *linebuf; - short *coeff; // progressive only - int coeff_w, coeff_h; // number of 8x8 coefficient blocks - } img_comp[4]; - - stbi__uint32 code_buffer; // jpeg entropy-coded buffer - int code_bits; // number of valid bits - unsigned char marker; // marker seen while filling entropy buffer - int nomore; // flag if we saw a marker so must stop - - int progressive; - int spec_start; - int spec_end; - int succ_high; - int succ_low; - int eob_run; - int jfif; - int app14_color_transform; // Adobe APP14 tag - int rgb; - - int scan_n, order[4]; - int restart_interval, todo; - -// kernels - void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); - void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); - stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +typedef struct { + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + + // sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + + // definition of jpeg image component + struct { + int id; + int h, v; + int tq; + int hd, ha; + int dc_pred; + + int x, y, w2, h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + + // kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, + int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); } stbi__jpeg; -static int stbi__build_huffman(stbi__huffman *h, int *count) -{ - int i,j,k=0; - unsigned int code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) - h->size[k++] = (stbi_uc) (i+1); - h->size[k] = 0; - - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; - - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (stbi_uc) i; - } - } - } - return 1; +static int stbi__build_huffman(stbi__huffman *h, int *count) { + int i, j, k = 0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i = 0; i < 16; ++i) + for (j = 0; j < count[i]; ++j) + h->size[k++] = (stbi_uc)(i + 1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for (j = 1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16)(code++); + if (code - 1 >= (1u << j)) + return stbi__err("bad code lengths", "Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16 - j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i = 0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS - s); + int m = 1 << (FAST_BITS - s); + for (j = 0; j < m; ++j) { + h->fast[c + j] = (stbi_uc)i; + } + } + } + return 1; } // build a table that decodes both magnitude and value of small ACs in // one go. -static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) -{ - int i; - for (i=0; i < (1 << FAST_BITS); ++i) { - stbi_uc fast = h->fast[i]; - fast_ac[i] = 0; - if (fast < 255) { - int rs = h->values[fast]; - int run = (rs >> 4) & 15; - int magbits = rs & 15; - int len = h->size[fast]; - - if (magbits && len + magbits <= FAST_BITS) { - // magnitude code followed by receive_extend code - int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); - int m = 1 << (magbits - 1); - if (k < m) k += (~0U << magbits) + 1; - // if the result is small enough, we can fit it in fast_ac table - if (k >= -128 && k <= 127) - fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); - } - } - } -} - -static void stbi__grow_buffer_unsafe(stbi__jpeg *j) -{ - do { - unsigned int b = j->nomore ? 0 : stbi__get8(j->s); - if (b == 0xff) { - int c = stbi__get8(j->s); - while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes - if (c != 0) { - j->marker = (unsigned char) c; - j->nomore = 1; - return; - } - } - j->code_buffer |= b << (24 - j->code_bits); - j->code_bits += 8; - } while (j->code_bits <= 24); +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) { + int i; + for (i = 0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) + k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16)((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) { + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) + c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char)c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); } // (1 << n) - 1 -static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; +static const stbi__uint32 stbi__bmask[17] = {0, 1, 3, 7, 15, 31, 63, 127, 255, + 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535}; // decode a jpeg huffman value from the bitstream -stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) -{ - unsigned int temp; - int c,k; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - int s = h->size[k]; - if (s > j->code_bits) - return -1; - j->code_buffer <<= s; - j->code_bits -= s; - return h->values[k]; - } - - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - temp = j->code_buffer >> 16; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - j->code_bits -= 16; - return -1; - } - - if (k > j->code_bits) - return -1; - - // convert the huffman code to the symbol id - c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; - STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); - - // convert the id to a symbol - j->code_bits -= k; - j->code_buffer <<= k; - return h->values[c]; +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) { + unsigned int temp; + int c, k; + + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k = FAST_BITS + 1;; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; } // bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); +stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) { + unsigned int k; + int sgn; + if (j->code_bits < n) + stbi__grow_buffer_unsafe(j); - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB - k = stbi_lrot(j->code_buffer, n); - STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int)(sizeof(stbi__bmask) / sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); } // get some unsigned bits -stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) -{ - unsigned int k; - if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k; -} - -stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) -{ - unsigned int k; - if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); - k = j->code_buffer; - j->code_buffer <<= 1; - --j->code_bits; - return k & 0x80000000; +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { + unsigned int k; + if (j->code_bits < n) + stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { + unsigned int k; + if (j->code_bits < 1) + stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; } // given a value that's at position X in the zigzag stream, // where does it appear in the 8x8 matrix coded as row-major? -static const stbi_uc stbi__jpeg_dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; +static const stbi_uc stbi__jpeg_dezigzag[64 + 15] = {0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, + 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, + 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, + 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63}; // decode one 64-entry block-- -static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) -{ - int diff,dc,k; - int t; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); - - diff = t ? stbi__extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc * dequant[0]); - - // decode AC components, see JPEG spec - k = 1; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * dequant[zig]); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); - } - } - } while (k < 64); - return 1; -} - -static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) -{ - int diff,dc; - int t; - if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - if (j->succ_high == 0) { - // first scan for DC coefficient, must be first - memset(data,0,64*sizeof(data[0])); // 0 all the ac values now - t = stbi__jpeg_huff_decode(j, hdc); - diff = t ? stbi__extend_receive(j, t) : 0; - - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); - } else { - // refinement scan for DC coefficient - if (stbi__jpeg_get_bit(j)) - data[0] += (short) (1 << j->succ_low); - } - return 1; +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, + stbi__int16 *fac, int b, stbi__uint16 *dequant) { + int diff, dc, k; + int t; + + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data, 0, 64 * sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short)(dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c, r, s; + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) + break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)(stbi__extend_receive(j, s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) { + int diff, dc; + int t; + if (j->spec_end != 0) + return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data, 0, 64 * sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short)(dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short)(1 << j->succ_low); + } + return 1; } // @OPTIMIZE: store non-zigzagged during the decode passes, // and only de-zigzag when dequantizing -static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) -{ - int k; - if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->succ_high == 0) { - int shift = j->succ_low; - - if (j->eob_run) { - --j->eob_run; - return 1; - } - - k = j->spec_start; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r); - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - --j->eob_run; - break; - } - k += 16; - } else { - k += r; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); - } - } - } while (k <= j->spec_end); - } else { - // refinement scan for these AC coefficients - - short bit = (short) (1 << j->succ_low); - - if (j->eob_run) { - --j->eob_run; - for (k = j->spec_start; k <= j->spec_end; ++k) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } - } else { - k = j->spec_start; - do { - int r,s; - int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r) - 1; - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - r = 64; // force end of block - } else { - // r=15 s=0 should write 16 0s, so we just do - // a run of 15 0s and then write s (which is 0), - // so we don't have to do anything special here - } - } else { - if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); - // sign bit - if (stbi__jpeg_get_bit(j)) - s = bit; - else - s = -bit; - } - - // advance by r - while (k <= j->spec_end) { - short *p = &data[stbi__jpeg_dezigzag[k++]]; - if (*p != 0) { - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } else { - if (r == 0) { - *p = (short) s; - break; - } - --r; - } - } - } while (k <= j->spec_end); - } - } - return 1; +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) { + int k; + if (j->spec_start == 0) + return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c, r, s; + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)(stbi__extend_receive(j, s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short)(1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit) == 0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r, s; + int rs = stbi__jpeg_huff_decode( + j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) + return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit) == 0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short)s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; } // take a -128..127 value and stbi__clamp it and convert to 0..255 -stbi_inline static stbi_uc stbi__clamp(int x) -{ - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (stbi_uc) x; +stbi_inline static stbi_uc stbi__clamp(int x) { + // trick to use a single test to catch both cases + if ((unsigned int)x > 255) { + if (x < 0) + return 0; + if (x > 255) + return 255; + } + return (stbi_uc)x; } -#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) -#define stbi__fsh(x) ((x) * 4096) +#define stbi__f2f(x) ((int)(((x)*4096 + 0.5))) +#define stbi__fsh(x) ((x)*4096) // derived from jidctint -- DCT_ISLOW -#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * stbi__f2f(0.5411961f); \ - t2 = p1 + p3*stbi__f2f(-1.847759065f); \ - t3 = p1 + p2*stbi__f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = stbi__fsh(p2+p3); \ - t1 = stbi__fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ - t0 = t0*stbi__f2f( 0.298631336f); \ - t1 = t1*stbi__f2f( 2.053119869f); \ - t2 = t2*stbi__f2f( 3.072711026f); \ - t3 = t3*stbi__f2f( 1.501321110f); \ - p1 = p5 + p1*stbi__f2f(-0.899976223f); \ - p2 = p5 + p2*stbi__f2f(-2.562915447f); \ - p3 = p3*stbi__f2f(-1.961570560f); \ - p4 = p4*stbi__f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; - -static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) -{ - int i,val[64],*v=val; - stbi_uc *o; - short *d = data; - - // columns - for (i=0; i < 8; ++i,++d, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0]*4; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } - - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - // so we want to round that, which means adding 0.5 * 1<<17, - // aka 65536. Also, we'll end up with -128 to 127 that we want - // to encode as 0..255 by adding 128, so we'll add that before the shift - x0 += 65536 + (128<<17); - x1 += 65536 + (128<<17); - x2 += 65536 + (128<<17); - x3 += 65536 + (128<<17); - // tried computing the shifts into temps, or'ing the temps to see - // if any were out of range, but that was slower - o[0] = stbi__clamp((x0+t3) >> 17); - o[7] = stbi__clamp((x0-t3) >> 17); - o[1] = stbi__clamp((x1+t2) >> 17); - o[6] = stbi__clamp((x1-t2) >> 17); - o[2] = stbi__clamp((x2+t1) >> 17); - o[5] = stbi__clamp((x2-t1) >> 17); - o[3] = stbi__clamp((x3+t0) >> 17); - o[4] = stbi__clamp((x3-t0) >> 17); - } +#define STBI__IDCT_1D(s0, s1, s2, s3, s4, s5, s6, s7) \ + int t0, t1, t2, t3, p1, p2, p3, p4, p5, x0, x1, x2, x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2 + p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3 * stbi__f2f(-1.847759065f); \ + t3 = p1 + p2 * stbi__f2f(0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2 + p3); \ + t1 = stbi__fsh(p2 - p3); \ + x0 = t0 + t3; \ + x3 = t0 - t3; \ + x1 = t1 + t2; \ + x2 = t1 - t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0 + t2; \ + p4 = t1 + t3; \ + p1 = t0 + t3; \ + p2 = t1 + t2; \ + p5 = (p3 + p4) * stbi__f2f(1.175875602f); \ + t0 = t0 * stbi__f2f(0.298631336f); \ + t1 = t1 * stbi__f2f(2.053119869f); \ + t2 = t2 * stbi__f2f(3.072711026f); \ + t3 = t3 * stbi__f2f(1.501321110f); \ + p1 = p5 + p1 * stbi__f2f(-0.899976223f); \ + p2 = p5 + p2 * stbi__f2f(-2.562915447f); \ + p3 = p3 * stbi__f2f(-1.961570560f); \ + p4 = p4 * stbi__f2f(-0.390180644f); \ + t3 += p1 + p4; \ + t2 += p2 + p3; \ + t1 += p2 + p4; \ + t0 += p1 + p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) { + int i, val[64], *v = val; + stbi_uc *o; + short *d = data; + + // columns + for (i = 0; i < 8; ++i, ++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[8] == 0 && d[16] == 0 && d[24] == 0 && d[32] == 0 && d[40] == 0 && d[48] == 0 && d[56] == 0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] * 4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[0], d[8], d[16], d[24], d[32], d[40], d[48], d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; + x1 += 512; + x2 += 512; + x3 += 512; + v[0] = (x0 + t3) >> 10; + v[56] = (x0 - t3) >> 10; + v[8] = (x1 + t2) >> 10; + v[48] = (x1 - t2) >> 10; + v[16] = (x2 + t1) >> 10; + v[40] = (x2 - t1) >> 10; + v[24] = (x3 + t0) >> 10; + v[32] = (x3 - t0) >> 10; + } + } + + for (i = 0, v = val, o = out; i < 8; ++i, v += 8, o += out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128 << 17); + x1 += 65536 + (128 << 17); + x2 += 65536 + (128 << 17); + x3 += 65536 + (128 << 17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0 + t3) >> 17); + o[7] = stbi__clamp((x0 - t3) >> 17); + o[1] = stbi__clamp((x1 + t2) >> 17); + o[6] = stbi__clamp((x1 - t2) >> 17); + o[2] = stbi__clamp((x2 + t1) >> 17); + o[5] = stbi__clamp((x2 - t1) >> 17); + o[3] = stbi__clamp((x3 + t0) >> 17); + o[4] = stbi__clamp((x3 - t0) >> 17); + } } #ifdef STBI_SSE2 // sse2 integer IDCT. not the fastest possible implementation but it // produces bit-identical results to the generic C version so it's // fully "transparent". -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - // This is constructed to match our regular (generic) integer IDCT exactly. - __m128i row0, row1, row2, row3, row4, row5, row6, row7; - __m128i tmp; - - // dot product constant: even elems=x, odd elems=y - #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) - - // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) - // out(1) = c1[even]*x + c1[odd]*y - #define dct_rot(out0,out1, x,y,c0,c1) \ - __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ - __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ - __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ - __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ - __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ - __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) - - // out = in << 12 (in 16-bit, out 32-bit) - #define dct_widen(out, in) \ - __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ - __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) - - // wide add - #define dct_wadd(out, a, b) \ - __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_add_epi32(a##_h, b##_h) - - // wide sub - #define dct_wsub(out, a, b) \ - __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) - - // butterfly a/b, add bias, then shift by "s" and pack - #define dct_bfly32o(out0, out1, a,b,bias,s) \ - { \ - __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ - __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ - dct_wadd(sum, abiased, b); \ - dct_wsub(dif, abiased, b); \ - out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ - out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ - } - - // 8-bit interleave step (for transposes) - #define dct_interleave8(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi8(a, b); \ - b = _mm_unpackhi_epi8(tmp, b) - - // 16-bit interleave step (for transposes) - #define dct_interleave16(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi16(a, b); \ - b = _mm_unpackhi_epi16(tmp, b) - - #define dct_pass(bias,shift) \ - { \ - /* even part */ \ - dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ - __m128i sum04 = _mm_add_epi16(row0, row4); \ - __m128i dif04 = _mm_sub_epi16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ - dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ - __m128i sum17 = _mm_add_epi16(row1, row7); \ - __m128i sum35 = _mm_add_epi16(row3, row5); \ - dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ - dct_wadd(x4, y0o, y4o); \ - dct_wadd(x5, y1o, y5o); \ - dct_wadd(x6, y2o, y5o); \ - dct_wadd(x7, y3o, y4o); \ - dct_bfly32o(row0,row7, x0,x7,bias,shift); \ - dct_bfly32o(row1,row6, x1,x6,bias,shift); \ - dct_bfly32o(row2,row5, x2,x5,bias,shift); \ - dct_bfly32o(row3,row4, x3,x4,bias,shift); \ - } - - __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); - __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); - __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); - __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); - __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); - __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); - __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); - __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); - - // rounding biases in column/row passes, see stbi__idct_block for explanation. - __m128i bias_0 = _mm_set1_epi32(512); - __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); - - // load - row0 = _mm_load_si128((const __m128i *) (data + 0*8)); - row1 = _mm_load_si128((const __m128i *) (data + 1*8)); - row2 = _mm_load_si128((const __m128i *) (data + 2*8)); - row3 = _mm_load_si128((const __m128i *) (data + 3*8)); - row4 = _mm_load_si128((const __m128i *) (data + 4*8)); - row5 = _mm_load_si128((const __m128i *) (data + 5*8)); - row6 = _mm_load_si128((const __m128i *) (data + 6*8)); - row7 = _mm_load_si128((const __m128i *) (data + 7*8)); - - // column pass - dct_pass(bias_0, 10); - - { - // 16bit 8x8 transpose pass 1 - dct_interleave16(row0, row4); - dct_interleave16(row1, row5); - dct_interleave16(row2, row6); - dct_interleave16(row3, row7); - - // transpose pass 2 - dct_interleave16(row0, row2); - dct_interleave16(row1, row3); - dct_interleave16(row4, row6); - dct_interleave16(row5, row7); - - // transpose pass 3 - dct_interleave16(row0, row1); - dct_interleave16(row2, row3); - dct_interleave16(row4, row5); - dct_interleave16(row6, row7); - } - - // row pass - dct_pass(bias_1, 17); - - { - // pack - __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 - __m128i p1 = _mm_packus_epi16(row2, row3); - __m128i p2 = _mm_packus_epi16(row4, row5); - __m128i p3 = _mm_packus_epi16(row6, row7); - - // 8bit 8x8 transpose pass 1 - dct_interleave8(p0, p2); // a0e0a1e1... - dct_interleave8(p1, p3); // c0g0c1g1... - - // transpose pass 2 - dct_interleave8(p0, p1); // a0c0e0g0... - dct_interleave8(p2, p3); // b0d0f0h0... - - // transpose pass 3 - dct_interleave8(p0, p2); // a0b0c0d0... - dct_interleave8(p1, p3); // a4b4c4d4... - - // store - _mm_storel_epi64((__m128i *) out, p0); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p2); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p1); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p3); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); - } +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) { + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + +// dot product constant: even elems=x, odd elems=y +#define dct_const(x, y) _mm_setr_epi16((x), (y), (x), (y), (x), (y), (x), (y)) + +// out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) +// out(1) = c1[even]*x + c1[odd]*y +#define dct_rot(out0, out1, x, y, c0, c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x), (y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x), (y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + +// out = in << 12 (in 16-bit, out 32-bit) +#define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + +// wide add +#define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + +// butterfly a/b, add bias, then shift by "s" and pack +#define dct_bfly32o(out0, out1, a, b, bias, s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + +// 8-bit interleave step (for transposes) +#define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + +// 16-bit interleave step (for transposes) +#define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + +#define dct_pass(bias, shift) \ + { \ + /* even part */ \ + dct_rot(t2e, t3e, row2, row6, rot0_0, rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o, y2o, row7, row3, rot2_0, rot2_1); \ + dct_rot(y1o, y3o, row5, row1, rot3_0, rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o, y5o, sum17, sum35, rot1_0, rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0, row7, x0, x7, bias, shift); \ + dct_bfly32o(row1, row6, x1, x6, bias, shift); \ + dct_bfly32o(row2, row5, x2, x5, bias, shift); \ + dct_bfly32o(row3, row4, x3, x4, bias, shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f(0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f(0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f(3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f(2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f(1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128 << 17)); + + // load + row0 = _mm_load_si128((const __m128i *)(data + 0 * 8)); + row1 = _mm_load_si128((const __m128i *)(data + 1 * 8)); + row2 = _mm_load_si128((const __m128i *)(data + 2 * 8)); + row3 = _mm_load_si128((const __m128i *)(data + 3 * 8)); + row4 = _mm_load_si128((const __m128i *)(data + 4 * 8)); + row5 = _mm_load_si128((const __m128i *)(data + 5 * 8)); + row6 = _mm_load_si128((const __m128i *)(data + 6 * 8)); + row7 = _mm_load_si128((const __m128i *)(data + 7 * 8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *)out, p0); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p0, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i *)out, p2); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p2, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i *)out, p1); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p1, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i *)out, p3); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p3, 0x4e)); + } #undef dct_const #undef dct_rot @@ -2445,198 +2434,235 @@ static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) // NEON integer IDCT. should produce bit-identical // results to the generic C version. -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; - - int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); - int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); - int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); - int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); - int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); - int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); - int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); - int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); - int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); - int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); - int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); - int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); - -#define dct_long_mul(out, inq, coeff) \ - int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) - -#define dct_long_mac(out, acc, inq, coeff) \ - int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) - -#define dct_widen(out, inq) \ - int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ - int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) { + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f(0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f(1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f(0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f(2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f(3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f(1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) // wide add -#define dct_wadd(out, a, b) \ - int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vaddq_s32(a##_h, b##_h) +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) // wide sub -#define dct_wsub(out, a, b) \ - int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vsubq_s32(a##_h, b##_h) +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) // butterfly a/b, then shift using "shiftop" by "s" and pack -#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ - { \ - dct_wadd(sum, a, b); \ - dct_wsub(dif, a, b); \ - out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ - out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ - } - -#define dct_pass(shiftop, shift) \ - { \ - /* even part */ \ - int16x8_t sum26 = vaddq_s16(row2, row6); \ - dct_long_mul(p1e, sum26, rot0_0); \ - dct_long_mac(t2e, p1e, row6, rot0_1); \ - dct_long_mac(t3e, p1e, row2, rot0_2); \ - int16x8_t sum04 = vaddq_s16(row0, row4); \ - int16x8_t dif04 = vsubq_s16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - int16x8_t sum15 = vaddq_s16(row1, row5); \ - int16x8_t sum17 = vaddq_s16(row1, row7); \ - int16x8_t sum35 = vaddq_s16(row3, row5); \ - int16x8_t sum37 = vaddq_s16(row3, row7); \ - int16x8_t sumodd = vaddq_s16(sum17, sum35); \ - dct_long_mul(p5o, sumodd, rot1_0); \ - dct_long_mac(p1o, p5o, sum17, rot1_1); \ - dct_long_mac(p2o, p5o, sum35, rot1_2); \ - dct_long_mul(p3o, sum37, rot2_0); \ - dct_long_mul(p4o, sum15, rot2_1); \ - dct_wadd(sump13o, p1o, p3o); \ - dct_wadd(sump24o, p2o, p4o); \ - dct_wadd(sump23o, p2o, p3o); \ - dct_wadd(sump14o, p1o, p4o); \ - dct_long_mac(x4, sump13o, row7, rot3_0); \ - dct_long_mac(x5, sump24o, row5, rot3_1); \ - dct_long_mac(x6, sump23o, row3, rot3_2); \ - dct_long_mac(x7, sump14o, row1, rot3_3); \ - dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ - dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ - dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ - dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ - } - - // load - row0 = vld1q_s16(data + 0*8); - row1 = vld1q_s16(data + 1*8); - row2 = vld1q_s16(data + 2*8); - row3 = vld1q_s16(data + 3*8); - row4 = vld1q_s16(data + 4*8); - row5 = vld1q_s16(data + 5*8); - row6 = vld1q_s16(data + 6*8); - row7 = vld1q_s16(data + 7*8); - - // add DC bias - row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); - - // column pass - dct_pass(vrshrn_n_s32, 10); - - // 16bit 8x8 transpose - { +#define dct_bfly32o(out0, out1, a, b, shiftop, s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0, row7, x0, x7, shiftop, shift); \ + dct_bfly32o(row1, row6, x1, x6, shiftop, shift); \ + dct_bfly32o(row2, row5, x2, x5, shiftop, shift); \ + dct_bfly32o(row3, row4, x3, x4, shiftop, shift); \ + } + + // load + row0 = vld1q_s16(data + 0 * 8); + row1 = vld1q_s16(data + 1 * 8); + row2 = vld1q_s16(data + 2 * 8); + row3 = vld1q_s16(data + 3 * 8); + row4 = vld1q_s16(data + 4 * 8); + row5 = vld1q_s16(data + 5 * 8); + row6 = vld1q_s16(data + 6 * 8); + row7 = vld1q_s16(data + 7 * 8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { // these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. // whether compilers actually get this is another story, sadly. -#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } -#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } - - // pass 1 - dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 - dct_trn16(row2, row3); - dct_trn16(row4, row5); - dct_trn16(row6, row7); - - // pass 2 - dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 - dct_trn32(row1, row3); - dct_trn32(row4, row6); - dct_trn32(row5, row7); - - // pass 3 - dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 - dct_trn64(row1, row5); - dct_trn64(row2, row6); - dct_trn64(row3, row7); +#define dct_trn16(x, y) \ + { \ + int16x8x2_t t = vtrnq_s16(x, y); \ + x = t.val[0]; \ + y = t.val[1]; \ + } +#define dct_trn32(x, y) \ + { \ + int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); \ + x = vreinterpretq_s16_s32(t.val[0]); \ + y = vreinterpretq_s16_s32(t.val[1]); \ + } +#define dct_trn64(x, y) \ + { \ + int16x8_t x0 = x; \ + int16x8_t y0 = y; \ + x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); \ + y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); \ + } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); #undef dct_trn16 #undef dct_trn32 #undef dct_trn64 - } - - // row pass - // vrshrn_n_s32 only supports shifts up to 16, we need - // 17. so do a non-rounding shift of 16 first then follow - // up with a rounding shift by 1. - dct_pass(vshrn_n_s32, 16); - - { - // pack and round - uint8x8_t p0 = vqrshrun_n_s16(row0, 1); - uint8x8_t p1 = vqrshrun_n_s16(row1, 1); - uint8x8_t p2 = vqrshrun_n_s16(row2, 1); - uint8x8_t p3 = vqrshrun_n_s16(row3, 1); - uint8x8_t p4 = vqrshrun_n_s16(row4, 1); - uint8x8_t p5 = vqrshrun_n_s16(row5, 1); - uint8x8_t p6 = vqrshrun_n_s16(row6, 1); - uint8x8_t p7 = vqrshrun_n_s16(row7, 1); - - // again, these can translate into one instruction, but often don't. -#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } -#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } - - // sadly can't use interleaved stores here since we only write - // 8 bytes to each scan line! - - // 8x8 8-bit transpose pass 1 - dct_trn8_8(p0, p1); - dct_trn8_8(p2, p3); - dct_trn8_8(p4, p5); - dct_trn8_8(p6, p7); - - // pass 2 - dct_trn8_16(p0, p2); - dct_trn8_16(p1, p3); - dct_trn8_16(p4, p6); - dct_trn8_16(p5, p7); - - // pass 3 - dct_trn8_32(p0, p4); - dct_trn8_32(p1, p5); - dct_trn8_32(p2, p6); - dct_trn8_32(p3, p7); - - // store - vst1_u8(out, p0); out += out_stride; - vst1_u8(out, p1); out += out_stride; - vst1_u8(out, p2); out += out_stride; - vst1_u8(out, p3); out += out_stride; - vst1_u8(out, p4); out += out_stride; - vst1_u8(out, p5); out += out_stride; - vst1_u8(out, p6); out += out_stride; - vst1_u8(out, p7); + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) \ + { \ + uint8x8x2_t t = vtrn_u8(x, y); \ + x = t.val[0]; \ + y = t.val[1]; \ + } +#define dct_trn8_16(x, y) \ + { \ + uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); \ + x = vreinterpret_u8_u16(t.val[0]); \ + y = vreinterpret_u8_u16(t.val[1]); \ + } +#define dct_trn8_32(x, y) \ + { \ + uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); \ + x = vreinterpret_u8_u32(t.val[0]); \ + y = vreinterpret_u8_u32(t.val[1]); \ + } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); + out += out_stride; + vst1_u8(out, p1); + out += out_stride; + vst1_u8(out, p2); + out += out_stride; + vst1_u8(out, p3); + out += out_stride; + vst1_u8(out, p4); + out += out_stride; + vst1_u8(out, p5); + out += out_stride; + vst1_u8(out, p6); + out += out_stride; + vst1_u8(out, p7); #undef dct_trn8_8 #undef dct_trn8_16 #undef dct_trn8_32 - } + } #undef dct_long_mul #undef dct_long_mac @@ -2649,1130 +2675,1221 @@ static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) #endif // STBI_NEON -#define STBI__MARKER_none 0xff +#define STBI__MARKER_none 0xff // if there's a pending marker from the entropy stream, return that // otherwise, fetch from the stream and get a marker. if there's no // marker, return 0xff, which is never a valid marker value -static stbi_uc stbi__get_marker(stbi__jpeg *j) -{ - stbi_uc x; - if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } - x = stbi__get8(j->s); - if (x != 0xff) return STBI__MARKER_none; - while (x == 0xff) - x = stbi__get8(j->s); // consume repeated 0xff fill bytes - return x; +static stbi_uc stbi__get_marker(stbi__jpeg *j) { + stbi_uc x; + if (j->marker != STBI__MARKER_none) { + x = j->marker; + j->marker = STBI__MARKER_none; + return x; + } + x = stbi__get8(j->s); + if (x != 0xff) + return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; } // in each scan, we'll have scan_n components, and the order // of the components is specified by order[] -#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) // after a restart interval, stbi__jpeg_reset the entropy decoder and // the dc prediction -static void stbi__jpeg_reset(stbi__jpeg *j) -{ - j->code_bits = 0; - j->code_buffer = 0; - j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; - j->marker = STBI__MARKER_none; - j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; - j->eob_run = 0; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels -} - -static int stbi__parse_entropy_coded_data(stbi__jpeg *z) -{ - stbi__jpeg_reset(z); - if (!z->progressive) { - if (z->scan_n == 1) { - int i,j; - STBI_SIMD_ALIGN(short, data[64]); - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - STBI_SIMD_ALIGN(short, data[64]); - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } else { - if (z->scan_n == 1) { - int i,j; - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - if (z->spec_start == 0) { - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } else { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) - return 0; - } - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x); - int y2 = (j*z->img_comp[n].v + y); - short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } -} - -static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) -{ - int i; - for (i=0; i < 64; ++i) - data[i] *= dequant[i]; -} - -static void stbi__jpeg_finish(stbi__jpeg *z) -{ - if (z->progressive) { - // dequantize and idct the data - int i,j,n; - for (n=0; n < z->s->img_n; ++n) { - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - } - } - } - } -} - -static int stbi__process_marker(stbi__jpeg *z, int m) -{ - int L; - switch (m) { - case STBI__MARKER_none: // no marker found - return stbi__err("expected marker","Corrupt JPEG"); - - case 0xDD: // DRI - specify restart interval - if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); - z->restart_interval = stbi__get16be(z->s); - return 1; - - case 0xDB: // DQT - define quantization table - L = stbi__get16be(z->s)-2; - while (L > 0) { - int q = stbi__get8(z->s); - int p = q >> 4, sixteen = (p != 0); - int t = q & 15,i; - if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); - if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); - - for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); - L -= (sixteen ? 129 : 65); - } - return L==0; - - case 0xC4: // DHT - define huffman table - L = stbi__get16be(z->s)-2; - while (L > 0) { - stbi_uc *v; - int sizes[16],i,n=0; - int q = stbi__get8(z->s); - int tc = q >> 4; - int th = q & 15; - if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = stbi__get8(z->s); - n += sizes[i]; - } - L -= 17; - if (tc == 0) { - if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; - v = z->huff_dc[th].values; - } else { - if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; - v = z->huff_ac[th].values; - } - for (i=0; i < n; ++i) - v[i] = stbi__get8(z->s); - if (tc != 0) - stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); - L -= n; - } - return L==0; - } - - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - L = stbi__get16be(z->s); - if (L < 2) { - if (m == 0xFE) - return stbi__err("bad COM len","Corrupt JPEG"); - else - return stbi__err("bad APP len","Corrupt JPEG"); - } - L -= 2; - - if (m == 0xE0 && L >= 5) { // JFIF APP0 segment - static const unsigned char tag[5] = {'J','F','I','F','\0'}; - int ok = 1; - int i; - for (i=0; i < 5; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 5; - if (ok) - z->jfif = 1; - } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment - static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; - int ok = 1; - int i; - for (i=0; i < 6; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 6; - if (ok) { - stbi__get8(z->s); // version - stbi__get16be(z->s); // flags0 - stbi__get16be(z->s); // flags1 - z->app14_color_transform = stbi__get8(z->s); // color transform - L -= 6; - } - } - - stbi__skip(z->s, L); - return 1; - } - - return stbi__err("unknown marker","Corrupt JPEG"); +static void stbi__jpeg_reset(stbi__jpeg *j) { + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) { + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i, j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for (j = 0; j < h; ++j) { + for (i = 0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc + z->img_comp[n].hd, z->huff_ac + ha, + z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) + return 0; + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * j * 8 + i * 8, z->img_comp[n].w2, + data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i, j, k, x, y; + STBI_SIMD_ALIGN(short, data[64]); + for (j = 0; j < z->img_mcu_y; ++j) { + for (i = 0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k = 0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y = 0; y < z->img_comp[n].v; ++y) { + for (x = 0; x < z->img_comp[n].h; ++x) { + int x2 = (i * z->img_comp[n].h + x) * 8; + int y2 = (j * z->img_comp[n].v + y) * 8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc + z->img_comp[n].hd, z->huff_ac + ha, + z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) + return 0; + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * y2 + x2, + z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i, j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for (j = 0; j < h; ++j) { + for (i = 0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i, j, k, x, y; + for (j = 0; j < z->img_mcu_y; ++j) { + for (i = 0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k = 0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y = 0; y < z->img_comp[n].v; ++y) { + for (x = 0; x < z->img_comp[n].h; ++x) { + int x2 = (i * z->img_comp[n].h + x); + int y2 = (j * z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) { + int i; + for (i = 0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) { + if (z->progressive) { + // dequantize and idct the data + int i, j, n; + for (n = 0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for (j = 0; j < h; ++j) { + for (i = 0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * j * 8 + i * 8, z->img_comp[n].w2, + data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) { + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker", "Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) + return stbi__err("bad DRI len", "Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s) - 2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15, i; + if (p != 0 && p != 1) + return stbi__err("bad DQT type", "Corrupt JPEG"); + if (t > 3) + return stbi__err("bad DQT table", "Corrupt JPEG"); + + for (i = 0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = + (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L == 0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s) - 2; + while (L > 0) { + stbi_uc *v; + int sizes[16], i, n = 0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) + return stbi__err("bad DHT header", "Corrupt JPEG"); + for (i = 0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc + th, sizes)) + return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac + th, sizes)) + return 0; + v = z->huff_ac[th].values; + } + for (i = 0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L == 0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len", "Corrupt JPEG"); + else + return stbi__err("bad APP len", "Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J', 'F', 'I', 'F', '\0'}; + int ok = 1; + int i; + for (i = 0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A', 'd', 'o', 'b', 'e', '\0'}; + int ok = 1; + int i; + for (i = 0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker", "Corrupt JPEG"); } // after we see SOS -static int stbi__process_scan_header(stbi__jpeg *z) -{ - int i; - int Ls = stbi__get16be(z->s); - z->scan_n = stbi__get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); - for (i=0; i < z->scan_n; ++i) { - int id = stbi__get8(z->s), which; - int q = stbi__get8(z->s); - for (which = 0; which < z->s->img_n; ++which) - if (z->img_comp[which].id == id) - break; - if (which == z->s->img_n) return 0; // no match - z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); - z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); - z->order[i] = which; - } - - { - int aa; - z->spec_start = stbi__get8(z->s); - z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 - aa = stbi__get8(z->s); - z->succ_high = (aa >> 4); - z->succ_low = (aa & 15); - if (z->progressive) { - if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) - return stbi__err("bad SOS", "Corrupt JPEG"); - } else { - if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); - if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); - z->spec_end = 63; - } - } - - return 1; -} - -static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) -{ - int i; - for (i=0; i < ncomp; ++i) { - if (z->img_comp[i].raw_data) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].raw_data = NULL; - z->img_comp[i].data = NULL; - } - if (z->img_comp[i].raw_coeff) { - STBI_FREE(z->img_comp[i].raw_coeff); - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].coeff = 0; - } - if (z->img_comp[i].linebuf) { - STBI_FREE(z->img_comp[i].linebuf); - z->img_comp[i].linebuf = NULL; - } - } - return why; -} - -static int stbi__process_frame_header(stbi__jpeg *z, int scan) -{ - stbi__context *s = z->s; - int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG - p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires - c = stbi__get8(s); - if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); - s->img_n = c; - for (i=0; i < c; ++i) { - z->img_comp[i].data = NULL; - z->img_comp[i].linebuf = NULL; - } - - if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); - - z->rgb = 0; - for (i=0; i < s->img_n; ++i) { - static const unsigned char rgb[3] = { 'R', 'G', 'B' }; - z->img_comp[i].id = stbi__get8(s); - if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) - ++z->rgb; - q = stbi__get8(s); - z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); - z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); - z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); - } - - if (scan != STBI__SCAN_load) return 1; - - if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); - - for (i=0; i < s->img_n; ++i) { - if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; - if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; - } - - // compute interleaved mcu info - z->img_h_max = h_max; - z->img_v_max = v_max; - z->img_mcu_w = h_max * 8; - z->img_mcu_h = v_max * 8; - // these sizes can't be more than 17 bits - z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; - z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; - - for (i=0; i < s->img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; - z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - // - // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) - // so these muls can't overflow with 32-bit ints (which we require) - z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; - z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].coeff = 0; - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].linebuf = NULL; - z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); - if (z->img_comp[i].raw_data == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - // align blocks for idct using mmx/sse - z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - if (z->progressive) { - // w2, h2 are multiples of 8 (see above) - z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; - z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; - z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); - if (z->img_comp[i].raw_coeff == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); - } - } - - return 1; +static int stbi__process_scan_header(stbi__jpeg *z) { + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int)z->s->img_n) + return stbi__err("bad SOS component count", "Corrupt JPEG"); + if (Ls != 6 + 2 * z->scan_n) + return stbi__err("bad SOS len", "Corrupt JPEG"); + for (i = 0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) + return 0; // no match + z->img_comp[which].hd = q >> 4; + if (z->img_comp[which].hd > 3) + return stbi__err("bad DC huff", "Corrupt JPEG"); + z->img_comp[which].ha = q & 15; + if (z->img_comp[which].ha > 3) + return stbi__err("bad AC huff", "Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || + z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) + return stbi__err("bad SOS", "Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) + return stbi__err("bad SOS", "Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) { + int i; + for (i = 0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) { + stbi__context *s = z->s; + int Lf, p, i, q, h_max = 1, v_max = 1, c; + Lf = stbi__get16be(s); + if (Lf < 11) + return stbi__err("bad SOF len", "Corrupt JPEG"); // JPEG + p = stbi__get8(s); + if (p != 8) + return stbi__err("only 8-bit", "JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); + if (s->img_y == 0) + return stbi__err( + "no header height", + "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); + if (s->img_x == 0) + return stbi__err("0 width", "Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) + return stbi__err("bad component count", "Corrupt JPEG"); + s->img_n = c; + for (i = 0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8 + 3 * s->img_n) + return stbi__err("bad SOF len", "Corrupt JPEG"); + + z->rgb = 0; + for (i = 0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = {'R', 'G', 'B'}; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); + if (!z->img_comp[i].h || z->img_comp[i].h > 4) + return stbi__err("bad H", "Corrupt JPEG"); + z->img_comp[i].v = q & 15; + if (!z->img_comp[i].v || z->img_comp[i].v > 4) + return stbi__err("bad V", "Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); + if (z->img_comp[i].tq > 3) + return stbi__err("bad TQ", "Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) + return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) + return stbi__err("too large", "Image too large to decode"); + + for (i = 0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) + h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) + v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w - 1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h - 1) / z->img_mcu_h; + + for (i = 0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max - 1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max - 1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i + 1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc *)(((size_t)z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i + 1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short *)(((size_t)z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; } // use comparisons since in some cases we handle more than one case (e.g. SOF) -#define stbi__DNL(x) ((x) == 0xdc) -#define stbi__SOI(x) ((x) == 0xd8) -#define stbi__EOI(x) ((x) == 0xd9) -#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) -#define stbi__SOS(x) ((x) == 0xda) - -#define stbi__SOF_progressive(x) ((x) == 0xc2) - -static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) -{ - int m; - z->jfif = 0; - z->app14_color_transform = -1; // valid values are 0,1,2 - z->marker = STBI__MARKER_none; // initialize cached marker to empty - m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); - if (scan == STBI__SCAN_type) return 1; - m = stbi__get_marker(z); - while (!stbi__SOF(m)) { - if (!stbi__process_marker(z,m)) return 0; - m = stbi__get_marker(z); - while (m == STBI__MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); - m = stbi__get_marker(z); - } - } - z->progressive = stbi__SOF_progressive(m); - if (!stbi__process_frame_header(z, scan)) return 0; - return 1; +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) { + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) + return stbi__err("no SOI", "Corrupt JPEG"); + if (scan == STBI__SCAN_type) + return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z, m)) + return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) + return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) + return 0; + return 1; } // decode image to YCbCr format -static int stbi__decode_jpeg_image(stbi__jpeg *j) -{ - int m; - for (m = 0; m < 4; m++) { - j->img_comp[m].raw_data = NULL; - j->img_comp[m].raw_coeff = NULL; - } - j->restart_interval = 0; - if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; - m = stbi__get_marker(j); - while (!stbi__EOI(m)) { - if (stbi__SOS(m)) { - if (!stbi__process_scan_header(j)) return 0; - if (!stbi__parse_entropy_coded_data(j)) return 0; - if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } - // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 - } - } else if (stbi__DNL(m)) { - int Ld = stbi__get16be(j->s); - stbi__uint32 NL = stbi__get16be(j->s); - if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); - if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); - } else { - if (!stbi__process_marker(j, m)) return 0; - } - m = stbi__get_marker(j); - } - if (j->progressive) - stbi__jpeg_finish(j); - return 1; +static int stbi__decode_jpeg_image(stbi__jpeg *j) { + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) + return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) + return 0; + if (!stbi__parse_entropy_coded_data(j)) + return 0; + if (j->marker == STBI__MARKER_none) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually + // return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) + return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) + return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) + return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; } // static jfif-centered resampling (across block boundaries) -typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, - int w, int hs); +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, int w, int hs); -#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) +#define stbi__div4(x) ((stbi_uc)((x) >> 2)) -static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - STBI_NOTUSED(out); - STBI_NOTUSED(in_far); - STBI_NOTUSED(w); - STBI_NOTUSED(hs); - return in_near; +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; } -static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - STBI_NOTUSED(hs); - for (i=0; i < w; ++i) - out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); - return out; +static stbi_uc *stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i = 0; i < w; ++i) + out[i] = stbi__div4(3 * in_near[i] + in_far[i] + 2); + return out; } -static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - stbi_uc *input = in_near; +static stbi_uc *stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } - out[0] = input[0]; - out[1] = stbi__div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = stbi__div4(n+input[i-1]); - out[i*2+1] = stbi__div4(n+input[i+1]); - } - out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; + out[0] = input[0]; + out[1] = stbi__div4(input[0] * 3 + input[1] + 2); + for (i = 1; i < w - 1; ++i) { + int n = 3 * input[i] + 2; + out[i * 2 + 0] = stbi__div4(n + input[i - 1]); + out[i * 2 + 1] = stbi__div4(n + input[i + 1]); + } + out[i * 2 + 0] = stbi__div4(input[w - 2] * 3 + input[w - 1] + 2); + out[i * 2 + 1] = input[w - 1]; - STBI_NOTUSED(in_far); - STBI_NOTUSED(hs); + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); - return out; + return out; } -#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) +#define stbi__div16(x) ((stbi_uc)((x) >> 4)) -static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + // need to generate 2x2 samples for every one in input + int i, t0, t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3 * in_near[0] + in_far[0] + 2); + return out; + } - t1 = 3*in_near[0] + in_far[0]; - out[0] = stbi__div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); + t1 = 3 * in_near[0] + in_far[0]; + out[0] = stbi__div4(t1 + 2); + for (i = 1; i < w; ++i) { + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2 - 1] = stbi__div16(3 * t0 + t1 + 8); + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); + } + out[w * 2 - 1] = stbi__div4(t1 + 2); - STBI_NOTUSED(hs); + STBI_NOTUSED(hs); - return out; + return out; } #if defined(STBI_SSE2) || defined(STBI_NEON) -static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i=0,t0,t1; - - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - // process groups of 8 pixels for as long as we can. - // note we can't handle the last pixel in a row in this loop - // because we need to handle the filter boundary conditions. - for (; i < ((w-1) & ~7); i += 8) { +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + // need to generate 2x2 samples for every one in input + int i = 0, t0, t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3 * in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3 * in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w - 1) & ~7); i += 8) { #if defined(STBI_SSE2) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - __m128i zero = _mm_setzero_si128(); - __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); - __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); - __m128i farw = _mm_unpacklo_epi8(farb, zero); - __m128i nearw = _mm_unpacklo_epi8(nearb, zero); - __m128i diff = _mm_sub_epi16(farw, nearw); - __m128i nears = _mm_slli_epi16(nearw, 2); - __m128i curr = _mm_add_epi16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - __m128i prv0 = _mm_slli_si128(curr, 2); - __m128i nxt0 = _mm_srli_si128(curr, 2); - __m128i prev = _mm_insert_epi16(prv0, t1, 0); - __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - __m128i bias = _mm_set1_epi16(8); - __m128i curs = _mm_slli_epi16(curr, 2); - __m128i prvd = _mm_sub_epi16(prev, curr); - __m128i nxtd = _mm_sub_epi16(next, curr); - __m128i curb = _mm_add_epi16(curs, bias); - __m128i even = _mm_add_epi16(prvd, curb); - __m128i odd = _mm_add_epi16(nxtd, curb); - - // interleave even and odd pixels, then undo scaling. - __m128i int0 = _mm_unpacklo_epi16(even, odd); - __m128i int1 = _mm_unpackhi_epi16(even, odd); - __m128i de0 = _mm_srli_epi16(int0, 4); - __m128i de1 = _mm_srli_epi16(int1, 4); - - // pack and write output - __m128i outv = _mm_packus_epi16(de0, de1); - _mm_storeu_si128((__m128i *) (out + i*2), outv); + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *)(in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *)(in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3 * in_near[i + 8] + in_far[i + 8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *)(out + i * 2), outv); #elif defined(STBI_NEON) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - uint8x8_t farb = vld1_u8(in_far + i); - uint8x8_t nearb = vld1_u8(in_near + i); - int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); - int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); - int16x8_t curr = vaddq_s16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - int16x8_t prv0 = vextq_s16(curr, curr, 7); - int16x8_t nxt0 = vextq_s16(curr, curr, 1); - int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); - int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - int16x8_t curs = vshlq_n_s16(curr, 2); - int16x8_t prvd = vsubq_s16(prev, curr); - int16x8_t nxtd = vsubq_s16(next, curr); - int16x8_t even = vaddq_s16(curs, prvd); - int16x8_t odd = vaddq_s16(curs, nxtd); - - // undo scaling and round, then store with even/odd phases interleaved - uint8x8x2_t o; - o.val[0] = vqrshrun_n_s16(even, 4); - o.val[1] = vqrshrun_n_s16(odd, 4); - vst2_u8(out + i*2, o); + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3 * in_near[i + 8] + in_far[i + 8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i * 2, o); #endif - // "previous" value for next iter - t1 = 3*in_near[i+7] + in_far[i+7]; - } + // "previous" value for next iter + t1 = 3 * in_near[i + 7] + in_far[i + 7]; + } - t0 = t1; - t1 = 3*in_near[i] + in_far[i]; - out[i*2] = stbi__div16(3*t1 + t0 + 8); + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); - for (++i; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2 - 1] = stbi__div16(3 * t0 + t1 + 8); + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); + } + out[w * 2 - 1] = stbi__div4(t1 + 2); - STBI_NOTUSED(hs); + STBI_NOTUSED(hs); - return out; + return out; } #endif -static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - STBI_NOTUSED(in_far); - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + // resample with nearest-neighbor + int i, j; + STBI_NOTUSED(in_far); + for (i = 0; i < w; ++i) + for (j = 0; j < hs; ++j) + out[i * hs + j] = in_near[i]; + return out; } // this is a reduced-precision calculation of YCbCr-to-RGB introduced // to make sure the code produces the same results in both SIMD and scalar -#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } +#define stbi__float2fixed(x) (((int)((x)*4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, + int step) { + int i; + for (i = 0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1 << 19); // rounding + int r, g, b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr * stbi__float2fixed(1.40200f); + g = y_fixed + (cr * -stbi__float2fixed(0.71414f)) + ((cb * -stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb * stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned)r > 255) { + if (r < 0) + r = 0; + else + r = 255; + } + if ((unsigned)g > 255) { + if (g < 0) + g = 0; + else + g = 255; + } + if ((unsigned)b > 255) { + if (b < 0) + b = 0; + else + b = 255; + } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } } #if defined(STBI_SSE2) || defined(STBI_NEON) -static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) -{ - int i = 0; +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, + int step) { + int i = 0; #ifdef STBI_SSE2 - // step == 3 is pretty ugly on the final interleave, and i'm not convinced - // it's useful in practice (you wouldn't use it for textures, for example). - // so just accelerate step == 4 case. - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - __m128i signflip = _mm_set1_epi8(-0x80); - __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); - __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); - __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); - __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); - __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); - __m128i xw = _mm_set1_epi16(255); // alpha channel - - for (; i+7 < count; i += 8) { - // load - __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); - __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); - __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); - __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 - __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 - - // unpack to short (and left-shift cr, cb by 8) - __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); - __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); - __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); - - // color transform - __m128i yws = _mm_srli_epi16(yw, 4); - __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); - __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); - __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); - __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); - __m128i rws = _mm_add_epi16(cr0, yws); - __m128i gwt = _mm_add_epi16(cb0, yws); - __m128i bws = _mm_add_epi16(yws, cb1); - __m128i gws = _mm_add_epi16(gwt, cr1); - - // descale - __m128i rw = _mm_srai_epi16(rws, 4); - __m128i bw = _mm_srai_epi16(bws, 4); - __m128i gw = _mm_srai_epi16(gws, 4); - - // back to byte, set up for transpose - __m128i brb = _mm_packus_epi16(rw, bw); - __m128i gxb = _mm_packus_epi16(gw, xw); - - // transpose to interleave channels - __m128i t0 = _mm_unpacklo_epi8(brb, gxb); - __m128i t1 = _mm_unpackhi_epi8(brb, gxb); - __m128i o0 = _mm_unpacklo_epi16(t0, t1); - __m128i o1 = _mm_unpackhi_epi16(t0, t1); - - // store - _mm_storeu_si128((__m128i *) (out + 0), o0); - _mm_storeu_si128((__m128i *) (out + 16), o1); - out += 32; - } - } + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16((short)(1.40200f * 4096.0f + 0.5f)); + __m128i cr_const1 = _mm_set1_epi16(-(short)(0.71414f * 4096.0f + 0.5f)); + __m128i cb_const0 = _mm_set1_epi16(-(short)(0.34414f * 4096.0f + 0.5f)); + __m128i cb_const1 = _mm_set1_epi16((short)(1.77200f * 4096.0f + 0.5f)); + __m128i y_bias = _mm_set1_epi8((char)(unsigned char)128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i + 7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *)(y + i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *)(pcr + i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *)(pcb + i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *)(out + 0), o0); + _mm_storeu_si128((__m128i *)(out + 16), o1); + out += 32; + } + } #endif #ifdef STBI_NEON - // in this version, step=3 support would be easy to add. but is there demand? - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - uint8x8_t signflip = vdup_n_u8(0x80); - int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); - int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); - int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); - int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); - - for (; i+7 < count; i += 8) { - // load - uint8x8_t y_bytes = vld1_u8(y + i); - uint8x8_t cr_bytes = vld1_u8(pcr + i); - uint8x8_t cb_bytes = vld1_u8(pcb + i); - int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); - int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); - - // expand to s16 - int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); - int16x8_t crw = vshll_n_s8(cr_biased, 7); - int16x8_t cbw = vshll_n_s8(cb_biased, 7); - - // color transform - int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); - int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); - int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); - int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); - int16x8_t rws = vaddq_s16(yws, cr0); - int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); - int16x8_t bws = vaddq_s16(yws, cb1); - - // undo scaling, round, convert to byte - uint8x8x4_t o; - o.val[0] = vqrshrun_n_s16(rws, 4); - o.val[1] = vqrshrun_n_s16(gws, 4); - o.val[2] = vqrshrun_n_s16(bws, 4); - o.val[3] = vdup_n_u8(255); - - // store, interleaving r/g/b/a - vst4_u8(out, o); - out += 8*4; - } - } + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16((short)(1.40200f * 4096.0f + 0.5f)); + int16x8_t cr_const1 = vdupq_n_s16(-(short)(0.71414f * 4096.0f + 0.5f)); + int16x8_t cb_const0 = vdupq_n_s16(-(short)(0.34414f * 4096.0f + 0.5f)); + int16x8_t cb_const1 = vdupq_n_s16((short)(1.77200f * 4096.0f + 0.5f)); + + for (; i + 7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8 * 4; + } + } #endif - for (; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1 << 19); // rounding + int r, g, b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr * stbi__float2fixed(1.40200f); + g = y_fixed + cr * -stbi__float2fixed(0.71414f) + ((cb * -stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb * stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned)r > 255) { + if (r < 0) + r = 0; + else + r = 255; + } + if ((unsigned)g > 255) { + if (g < 0) + g = 0; + else + g = 255; + } + if ((unsigned)b > 255) { + if (b < 0) + b = 0; + else + b = 255; + } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } } #endif // set up the kernels -static void stbi__setup_jpeg(stbi__jpeg *j) -{ - j->idct_block_kernel = stbi__idct_block; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; +static void stbi__setup_jpeg(stbi__jpeg *j) { + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; #ifdef STBI_SSE2 - if (stbi__sse2_available()) { - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; - } + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } #endif #ifdef STBI_NEON - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; #endif } // clean up the temporary component buffers -static void stbi__cleanup_jpeg(stbi__jpeg *j) -{ - stbi__free_jpeg_components(j, j->s->img_n, 0); -} - -typedef struct -{ - resample_row_func resample; - stbi_uc *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on +static void stbi__cleanup_jpeg(stbi__jpeg *j) { stbi__free_jpeg_components(j, j->s->img_n, 0); } + +typedef struct { + resample_row_func resample; + stbi_uc *line0, *line1; + int hs, vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on } stbi__resample; // fast 0..255 * 0..255 => 0..255 rounded multiplication -static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) -{ - unsigned int t = x*y + 128; - return (stbi_uc) ((t + (t >>8)) >> 8); -} - -static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n, is_rgb; - z->s->img_n = 0; // make stbi__cleanup_jpeg safe - - // validate req_comp - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - - // load a jpeg image from whichever source, but leave in YCbCr format - if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } - - // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; - - is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); - - if (z->s->img_n == 3 && n < 3 && !is_rgb) - decode_n = 1; - else - decode_n = z->s->img_n; - - // resample and color-convert - { - int k; - unsigned int i,j; - stbi_uc *output; - stbi_uc *coutput[4]; - - stbi__resample res_comp[4]; - - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); - if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - r->hs = z->img_h_max / z->img_comp[k].h; - r->vs = z->img_v_max / z->img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (z->s->img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = z->img_comp[k].data; - - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; - else r->resample = stbi__resample_row_generic; - } - - // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); - if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - // now go ahead and resample - for (j=0; j < z->s->img_y; ++j) { - stbi_uc *out = output + n * z->s->img_x * j; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(z->img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < z->img_comp[k].y) - r->line1 += z->img_comp[k].w2; - } - } - if (n >= 3) { - stbi_uc *y = coutput[0]; - if (z->s->img_n == 3) { - if (is_rgb) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = y[i]; - out[1] = coutput[1][i]; - out[2] = coutput[2][i]; - out[3] = 255; - out += n; - } - } else { - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else if (z->s->img_n == 4) { - if (z->app14_color_transform == 0) { // CMYK - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(coutput[0][i], m); - out[1] = stbi__blinn_8x8(coutput[1][i], m); - out[2] = stbi__blinn_8x8(coutput[2][i], m); - out[3] = 255; - out += n; - } - } else if (z->app14_color_transform == 2) { // YCCK - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(255 - out[0], m); - out[1] = stbi__blinn_8x8(255 - out[1], m); - out[2] = stbi__blinn_8x8(255 - out[2], m); - out += n; - } - } else { // YCbCr + alpha? Ignore the fourth channel for now - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else - for (i=0; i < z->s->img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - if (is_rgb) { - if (n == 1) - for (i=0; i < z->s->img_x; ++i) - *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - else { - for (i=0; i < z->s->img_x; ++i, out += 2) { - out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - out[1] = 255; - } - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); - stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); - stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); - out[0] = stbi__compute_y(r, g, b); - out[1] = 255; - out += n; - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); - out[1] = 255; - out += n; - } - } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; - } - } - } - stbi__cleanup_jpeg(z); - *out_x = z->s->img_x; - *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output - return output; - } -} - -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - unsigned char* result; - stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); - STBI_NOTUSED(ri); - j->s = s; - stbi__setup_jpeg(j); - result = load_jpeg_image(j, x,y,comp,req_comp); - STBI_FREE(j); - return result; -} - -static int stbi__jpeg_test(stbi__context *s) -{ - int r; - stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); - j->s = s; - stbi__setup_jpeg(j); - r = stbi__decode_jpeg_header(j, STBI__SCAN_type); - stbi__rewind(s); - STBI_FREE(j); - return r; -} - -static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) -{ - if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { - stbi__rewind( j->s ); - return 0; - } - if (x) *x = j->s->img_x; - if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; - return 1; -} - -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) -{ - int result; - stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); - j->s = s; - result = stbi__jpeg_info_raw(j, x, y, comp); - STBI_FREE(j); - return result; +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) { + unsigned int t = x * y + 128; + return (stbi_uc)((t + (t >> 8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) { + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) + return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { + stbi__cleanup_jpeg(z); + return NULL; + } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i, j; + stbi_uc *output; + stbi_uc *coutput[4]; + + stbi__resample res_comp[4]; + + for (k = 0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *)stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { + stbi__cleanup_jpeg(z); + return stbi__errpuc("outofmem", "Out of memory"); + } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs - 1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) + r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) + r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) + r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) + r->resample = z->resample_row_hv_2_kernel; + else + r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *)stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { + stbi__cleanup_jpeg(z); + return stbi__errpuc("outofmem", "Out of memory"); + } + + // now go ahead and resample + for (j = 0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k = 0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i = 0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i = 0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i = 0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i = 0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i = 0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i = 0; i < z->s->img_x; ++i) + out[i] = y[i]; + else + for (i = 0; i < z->s->img_x; ++i) + *out++ = y[i], *out++ = 255; + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) + *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + unsigned char *result; + stbi__jpeg *j = (stbi__jpeg *)stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x, y, comp, req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) { + int r; + stbi__jpeg *j = (stbi__jpeg *)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) { + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind(j->s); + return 0; + } + if (x) + *x = j->s->img_x; + if (y) + *y = j->s->img_y; + if (comp) + *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { + int result; + stbi__jpeg *j = (stbi__jpeg *)(stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; } #endif @@ -3786,83 +3903,80 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_ZLIB // fast-way is faster to check than jpeg huffman, but slow way is slower -#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables -#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) -typedef struct -{ - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; - int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; +typedef struct { + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; } stbi__zhuffman; -stbi_inline static int stbi__bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; -} - -stbi_inline static int stbi__bit_reverse(int v, int bits) -{ - STBI_ASSERT(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return stbi__bitreverse16(v) >> (16-bits); -} - -static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; - - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - if (sizes[i] > (1 << i)) - return stbi__err("bad sizes", "Corrupt PNG"); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; - if (s <= STBI__ZFAST_BITS) { - int j = stbi__bit_reverse(next_code[s],s); - while (j < (1 << STBI__ZFAST_BITS)) { - z->fast[j] = fastv; - j += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; +stbi_inline static int stbi__bitreverse16(int n) { + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) { + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16 - bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) { + int i, k = 0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i = 0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i = 1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i = 1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16)code; + z->firstsymbol[i] = (stbi__uint16)k; + code = (code + sizes[i]); + if (sizes[i]) + if (code - 1 >= (1 << i)) + return stbi__err("bad codelengths", "Corrupt PNG"); + z->maxcode[i] = code << (16 - i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i = 0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16)((s << 9) | i); + z->size[c] = (stbi_uc)s; + z->value[c] = (stbi__uint16)i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s], s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; } // zlib-from-memory implementation for PNG reading @@ -3871,259 +3985,277 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int // we require PNG read all the IDATs and combine them into a single // memory buffer -typedef struct -{ - stbi_uc *zbuffer, *zbuffer_end; - int num_bits; - stbi__uint32 code_buffer; +typedef struct { + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; - stbi__zhuffman z_length, z_distance; + stbi__zhuffman z_length, z_distance; } stbi__zbuf; -stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) -{ - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; -} - -static void stbi__fill_bits(stbi__zbuf *z) -{ - do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); -} - -stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; -} - -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s,k; - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = stbi__bit_reverse(a->code_buffer, 16); - for (s=STBI__ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s == 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; -} - -stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b) { - s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; - } - return stbi__zhuffman_decode_slowpath(a, z); -} - -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes -{ - char *q; - int cur, limit, old_limit; - z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = old_limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) - limit *= 2; - q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); - STBI_NOTUSED(old_limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; -} - -static const int stbi__zlength_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; - -static const int stbi__zlength_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - -static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - -static const int stbi__zdist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static int stbi__parse_huffman_block(stbi__zbuf *a) -{ - char *zout = a->zout; - for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes - if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; - zout = a->zout; - } - *zout++ = (char) z; - } else { - stbi_uc *p; - int len,dist; - if (z == 256) { - a->zout = zout; - return 1; - } - z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { - if (!stbi__zexpand(a, zout, len)) return 0; - zout = a->zout; - } - p = (stbi_uc *) (zout - dist); - if (dist == 1) { // run of one byte; common in images. - stbi_uc v = *p; - if (len) { do *zout++ = v; while (--len); } - } else { - if (len) { do *zout++ = *p++; while (--len); } - } - } - } -} - -static int stbi__compute_huffman_codes(stbi__zbuf *a) -{ - static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137];//padding for maximum single op - stbi_uc codelength_sizes[19]; - int i,n; - - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; - int ntot = hlit + hdist; - - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; - } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; - - n = 0; - while (n < ntot) { - int c = stbi__zhuffman_decode(a, &z_codelength); - if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); - if (c < 16) - lencodes[n++] = (stbi_uc) c; - else { - stbi_uc fill = 0; - if (c == 16) { - c = stbi__zreceive(a,2)+3; - if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); - fill = lencodes[n-1]; - } else if (c == 17) - c = stbi__zreceive(a,3)+3; - else { - STBI_ASSERT(c == 18); - c = stbi__zreceive(a,7)+11; - } - if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); - memset(lencodes+n, fill, c); - n += c; - } - } - if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; -} - -static int stbi__parse_uncompressed_block(stbi__zbuf *a) -{ - stbi_uc header[4]; - int len,nlen,k; - if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check - a->code_buffer >>= 8; - a->num_bits -= 8; - } - STBI_ASSERT(a->num_bits == 0); - // now fill header the normal way - while (k < 4) - header[k++] = stbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; -} - -static int stbi__parse_zlib_header(stbi__zbuf *a) -{ - int cmf = stbi__zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; -} - -static const stbi_uc stbi__zdefault_length[288] = -{ - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 -}; -static const stbi_uc stbi__zdefault_distance[32] = -{ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 -}; +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) { + if (z->zbuffer >= z->zbuffer_end) + return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) { + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int)stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) { + unsigned int k; + if (z->num_bits < n) + stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) { + int b, s, k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s = STBI__ZFAST_BITS + 1;; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) + return -1; // invalid code! + // code size is s, so: + b = (k >> (16 - s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) { + int b, s; + if (a->num_bits < 16) + stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) + return stbi__err("output buffer limit", "Corrupt PNG"); + cur = (int)(z->zout - z->zout_start); + limit = old_limit = (int)(z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *)STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) + return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + +static const int stbi__zlength_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0}; + +static const int stbi__zdist_base[32] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; + +static const int stbi__zdist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) { + char *zout = a->zout; + for (;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) + return stbi__err("bad huffman code", "Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) + return 0; + zout = a->zout; + } + *zout++ = (char)z; + } else { + stbi_uc *p; + int len, dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) + len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) + return stbi__err("bad huffman code", "Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) + dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) + return stbi__err("bad dist", "Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) + return 0; + zout = a->zout; + } + p = (stbi_uc *)(zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { + do + *zout++ = v; + while (--len); + } + } else { + if (len) { + do + *zout++ = *p++; + while (--len); + } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) { + static const stbi_uc length_dezigzag[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286 + 32 + 137]; // padding for maximum single op + stbi_uc codelength_sizes[19]; + int i, n; + + int hlit = stbi__zreceive(a, 5) + 257; + int hdist = stbi__zreceive(a, 5) + 1; + int hclen = stbi__zreceive(a, 4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i = 0; i < hclen; ++i) { + int s = stbi__zreceive(a, 3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc)s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) + return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) + return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc)c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a, 2) + 3; + if (n == 0) + return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n - 1]; + } else if (c == 17) + c = stbi__zreceive(a, 3) + 3; + else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a, 7) + 11; + } + if (ntot - n < c) + return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes + n, fill, c); + n += c; + } + } + if (n != ntot) + return stbi__err("bad codelengths", "Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) + return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes + hlit, hdist)) + return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) { + stbi_uc header[4]; + int len, nlen, k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc)(a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) + return stbi__err("zlib corrupt", "Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) + return stbi__err("read past buffer", "Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) + return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) { + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf * 256 + flg) % 31 != 0) + return stbi__err("bad zlib header", "Corrupt PNG"); // zlib spec + if (flg & 32) + return stbi__err("no preset dict", "Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) + return stbi__err("bad compression", "Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[288] = { + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8}; +static const stbi_uc stbi__zdefault_distance[32] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; /* Init algorithm: { @@ -4137,117 +4269,122 @@ Init algorithm: } */ -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); - if (type == 0) { - if (!stbi__parse_uncompressed_block(a)) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; - } else { - if (!stbi__compute_huffman_codes(a)) return 0; - } - if (!stbi__parse_huffman_block(a)) return 0; - } - } while (!final); - return 1; -} - -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; - - return stbi__parse_zlib(a, parse_header); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); - else - return -1; -} - -STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(16384); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer+len; - if (stbi__do_zlib(&a, p, 16384, 1, 0)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) { + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) + return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a, 1); + type = stbi__zreceive(a, 2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) + return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length, stbi__zdefault_length, 288)) + return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) + return 0; + } else { + if (!stbi__compute_huffman_codes(a)) + return 0; + } + if (!stbi__parse_huffman_block(a)) + return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) { + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) { + stbi__zbuf a; + char *p = (char *)stbi__malloc(initial_size); + if (p == NULL) + return NULL; + a.zbuffer = (stbi_uc *)buffer; + a.zbuffer_end = (stbi_uc *)buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) + *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) { + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, + int parse_header) { + stbi__zbuf a; + char *p = (char *)stbi__malloc(initial_size); + if (p == NULL) + return NULL; + a.zbuffer = (stbi_uc *)buffer; + a.zbuffer_end = (stbi_uc *)buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) + *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) { + stbi__zbuf a; + a.zbuffer = (stbi_uc *)ibuffer; + a.zbuffer_end = (stbi_uc *)ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int)(a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) { + stbi__zbuf a; + char *p = (char *)stbi__malloc(16384); + if (p == NULL) + return NULL; + a.zbuffer = (stbi_uc *)buffer; + a.zbuffer_end = (stbi_uc *)buffer + len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) + *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) { + stbi__zbuf a; + a.zbuffer = (stbi_uc *)ibuffer; + a.zbuffer_end = (stbi_uc *)ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int)(a.zout - a.zout_start); + else + return -1; } #endif @@ -4262,1057 +4399,1203 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char // - uses stb_zlib, a PD zlib implementation with fast huffman decoding #ifndef STBI_NO_PNG -typedef struct -{ - stbi__uint32 length; - stbi__uint32 type; +typedef struct { + stbi__uint32 length; + stbi__uint32 type; } stbi__pngchunk; -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) -{ - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); - return c; +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) { + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; } -static int stbi__check_png_header(stbi__context *s) -{ - static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); - return 1; +static int stbi__check_png_header(stbi__context *s) { + static const stbi_uc png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + int i; + for (i = 0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) + return stbi__err("bad png sig", "Not a PNG"); + return 1; } -typedef struct -{ - stbi__context *s; - stbi_uc *idata, *expanded, *out; - int depth; +typedef struct { + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; } stbi__png; - enum { - STBI__F_none=0, - STBI__F_sub=1, - STBI__F_up=2, - STBI__F_avg=3, - STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first + STBI__F_none = 0, + STBI__F_sub = 1, + STBI__F_up = 2, + STBI__F_avg = 3, + STBI__F_paeth = 4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first }; -static stbi_uc first_row_filter[5] = -{ - STBI__F_none, - STBI__F_sub, - STBI__F_none, - STBI__F_avg_first, - STBI__F_paeth_first -}; +static stbi_uc first_row_filter[5] = {STBI__F_none, STBI__F_sub, STBI__F_none, STBI__F_avg_first, STBI__F_paeth_first}; -static int stbi__paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; +static int stbi__paeth(int a, int b, int c) { + int p = a + b - c; + int pa = abs(p - a); + int pb = abs(p - b); + int pc = abs(p - c); + if (pa <= pb && pa <= pc) + return a; + if (pb <= pc) + return b; + return c; } -static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +static const stbi_uc stbi__depth_scale_table[9] = {0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01}; // create the png data from post-deflated data -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) -{ - int bytes = (depth == 16? 2 : 1); - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n*bytes; - stbi__uint32 img_len, img_width_bytes; - int k; - int img_n = s->img_n; // copy it into a local for later - - int output_bytes = out_n*bytes; - int filter_bytes = img_n*bytes; - int width = x; - - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into - if (!a->out) return stbi__err("outofmem", "Out of memory"); - - if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); - img_width_bytes = (((img_n * x * depth) + 7) >> 3); - img_len = (img_width_bytes + 1) * y; - - // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, - // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), - // so just check for raw_len < img_len always. - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); - - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior; - int filter = *raw++; - - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; - } - prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above - - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; - - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } - } - - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else if (depth == 16) { - if (img_n != out_n) { - cur[filter_bytes] = 255; // first pixel top byte - cur[filter_bytes+1] = 255; // first pixel bottom byte - } - raw += filter_bytes; - cur += output_bytes; - prior += output_bytes; - } else { - raw += 1; - cur += 1; - prior += 1; - } - - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*filter_bytes; - #define STBI__CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; - } - #undef STBI__CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define STBI__CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ - for (k=0; k < filter_bytes; ++k) - switch (filter) { - STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; - } - #undef STBI__CASE - - // the loop above sets the high byte of the pixels' alpha, but for - // 16 bit png files we also need the low byte set. we'll do that here. - if (depth == 16) { - cur = a->out + stride*j; // start at the beginning of the row again - for (i=0; i < x; ++i,cur+=output_bytes) { - cur[filter_bytes+1] = 255; - } - } - } - } - - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range - - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones - - if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); - } - if (k > 0) *cur++ = scale * ((*in >> 4) ); - } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); - } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); - } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); - } - if (img_n != out_n) { - int q; - // insert alpha = 255 - cur = a->out + stride*j; - if (img_n == 1) { - for (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; - } - } else { - STBI_ASSERT(img_n == 3); - for (q=x-1; q >= 0; --q) { - cur[q*4+3] = 255; - cur[q*4+2] = cur[q*3+2]; - cur[q*4+1] = cur[q*3+1]; - cur[q*4+0] = cur[q*3+0]; - } - } - } - } - } else if (depth == 16) { - // force the image data from big-endian to platform-native. - // this is done in a separate pass due to the decoding relying - // on the data being untouched, but could probably be done - // per-line during decode if care is taken. - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; - - for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { - *cur16 = (cur[0] << 8) | cur[1]; - } - } - - return 1; -} - -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) -{ - int bytes = (depth == 16 ? 2 : 1); - int out_bytes = out_n * bytes; - stbi_uc *final; - int p; - if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - - // de-interlacing - final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - STBI_FREE(final); - return 0; - } - for (j=0; j < y; ++j) { - for (i=0; i < x; ++i) { - int out_y = j*yspc[p]+yorig[p]; - int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, - a->out + (j*x+i)*out_bytes, out_bytes); - } - } - STBI_FREE(a->out); - image_data += img_len; - image_data_len -= img_len; - } - } - a->out = final; - - return 1; -} - -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint16 *p = (stbi__uint16*) z->out; - - // compute color-based transparency, assuming we've - // already got 65535 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i = 0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 65535); - p += 2; - } - } else { - for (i = 0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) -{ - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; - - p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); - - // between here and free(out) below, exitting would leak - temp_out = p; - - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - STBI_FREE(a->out); - a->out = temp_out; - - STBI_NOTUSED(len); - - return 1; +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, + stbi__uint32 y, int depth, int color) { + int bytes = (depth == 16 ? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i, j, stride = x * out_n * bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n * bytes; + int filter_bytes = img_n * bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n + 1); + a->out = (stbi_uc *)stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) + return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) + return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) + return stbi__err("not enough pixels", "Corrupt PNG"); + + for (j = 0; j < y; ++j) { + stbi_uc *cur = a->out + stride * j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter", "Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += + x * out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) + filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k = 0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none: + cur[k] = raw[k]; + break; + case STBI__F_sub: + cur[k] = raw[k]; + break; + case STBI__F_up: + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + cur[k] = STBI__BYTECAST(raw[k] + (prior[k] >> 1)); + break; + case STBI__F_paeth: + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0, prior[k], 0)); + break; + case STBI__F_avg_first: + cur[k] = raw[k]; + break; + case STBI__F_paeth_first: + cur[k] = raw[k]; + break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes + 1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1) * filter_bytes; +#define STBI__CASE(f) \ + case f: \ + for (k = 0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: + memcpy(cur, raw, nk); + break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k - filter_bytes]); } + break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } + break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k - filter_bytes]) >> 1)); } + break; + STBI__CASE(STBI__F_paeth) { + cur[k] = + STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - filter_bytes], prior[k], prior[k - filter_bytes])); + } + break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k - filter_bytes] >> 1)); } + break; + STBI__CASE(STBI__F_paeth_first) { + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - filter_bytes], 0, 0)); + } + break; + } +#undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n + 1 == out_n); +#define STBI__CASE(f) \ + case f: \ + for (i = x - 1; i >= 1; \ + --i, cur[filter_bytes] = 255, raw += filter_bytes, cur += output_bytes, prior += output_bytes) \ + for (k = 0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } + break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k - output_bytes]); } + break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } + break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k - output_bytes]) >> 1)); } + break; + STBI__CASE(STBI__F_paeth) { + cur[k] = + STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - output_bytes], prior[k], prior[k - output_bytes])); + } + break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k - output_bytes] >> 1)); } + break; + STBI__CASE(STBI__F_paeth_first) { + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - output_bytes], 0, 0)); + } + break; + } +#undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride * j; // start at the beginning of the row again + for (i = 0; i < x; ++i, cur += output_bytes) { + cur[filter_bytes + 1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j = 0; j < y; ++j) { + stbi_uc *cur = a->out + stride * j; + stbi_uc *in = a->out + stride * j + x * out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for + // 1/2/4-bit png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data + // that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k = x * img_n; k >= 2; k -= 2, ++in) { + *cur++ = scale * ((*in >> 4)); + *cur++ = scale * ((*in) & 0x0f); + } + if (k > 0) + *cur++ = scale * ((*in >> 4)); + } else if (depth == 2) { + for (k = x * img_n; k >= 4; k -= 4, ++in) { + *cur++ = scale * ((*in >> 6)); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in) & 0x03); + } + if (k > 0) + *cur++ = scale * ((*in >> 6)); + if (k > 1) + *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) + *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k = x * img_n; k >= 8; k -= 8, ++in) { + *cur++ = scale * ((*in >> 7)); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in) & 0x01); + } + if (k > 0) + *cur++ = scale * ((*in >> 7)); + if (k > 1) + *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) + *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) + *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) + *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) + *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) + *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride * j; + if (img_n == 1) { + for (q = x - 1; q >= 0; --q) { + cur[q * 2 + 1] = 255; + cur[q * 2 + 0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q = x - 1; q >= 0; --q) { + cur[q * 4 + 3] = 255; + cur[q * 4 + 2] = cur[q * 3 + 2]; + cur[q * 4 + 1] = cur[q * 3 + 1]; + cur[q * 4 + 0] = cur[q * 3 + 0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16 *)cur; + + for (i = 0; i < x * y * out_n; ++i, cur16++, cur += 2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, + int color, int interlaced) { + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *)stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + for (p = 0; p < 7; ++p) { + int xorig[] = {0, 4, 0, 2, 0, 1, 0}; + int yorig[] = {0, 0, 4, 0, 2, 0, 1}; + int xspc[] = {8, 8, 4, 4, 2, 2, 1}; + int yspc[] = {8, 8, 8, 4, 4, 2, 2}; + int i, j, x, y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p] - 1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p] - 1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j = 0; j < y; ++j) { + for (i = 0; i < x; ++i) { + int out_y = j * yspc[p] + yorig[p]; + int out_x = i * xspc[p] + xorig[p]; + memcpy(final + out_y * a->s->img_x * out_bytes + out_x * out_bytes, + a->out + (j * x + i) * out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) { + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) { + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16 *)z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) { + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *)stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) + return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i = 0; i < pixel_count; ++i) { + int n = orig[i] * 4; + p[0] = palette[n]; + p[1] = palette[n + 1]; + p[2] = palette[n + 2]; + p += 3; + } + } else { + for (i = 0; i < pixel_count; ++i) { + int n = orig[i] * 4; + p[0] = palette[n]; + p[1] = palette[n + 1]; + p[2] = palette[n + 2]; + p[3] = palette[n + 3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; } static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; - -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; -} - -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag = flag_true_if_should_convert; -} - -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - if (s->img_out_n == 3) { // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - // convert bgr to rgb and unpremultiply - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - stbi_uc half = a / 2; - p[0] = (p[2] * 255 + half) / a; - p[1] = (p[1] * 255 + half) / a; - p[2] = ( t * 255 + half) / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } -} - -#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) - -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]; - stbi__uint16 tc16[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, is_iphone=0; - stbi__context *s = z->s; - - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; - - if (!stbi__check_png_header(s)) return 0; - - if (scan == STBI__SCAN_type) return 1; - - for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); - switch (c.type) { - case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); - break; - case STBI__PNG_TYPE('I','H','D','R'): { - int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS - } - break; - } - - case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); - palette[i*4+3] = 255; - } - break; - } - - case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); - } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); - has_trans = 1; - if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is - } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger - } - } - break; - } - - case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } - if ((int)(ioff + c.length) < (int)ioff) return 0; - if (ioff + c.length > idata_limit) { - stbi__uint32 idata_limit_old = idata_limit; - stbi_uc *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - STBI_NOTUSED(idata_limit_old); - p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); - z->idata = p; - } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } - - case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); - // initial guess for decoded data size to avoid unnecessary reallocs - bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component - raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); - if (z->expanded == NULL) return 0; // zlib should set error - STBI_FREE(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; - if (has_trans) { - if (z->depth == 16) { - if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; - } else { - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; - } - } - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); - if (pal_img_n) { - // pal_img_n == 3 or 4 - s->img_n = pal_img_n; // record the actual colors we had - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } else if (has_trans) { - // non-paletted image with tRNS -> source image has (constant) alpha - ++s->img_n; - } - STBI_FREE(z->expanded); z->expanded = NULL; - return 1; - } - - default: - // if critical, fail - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - // not threadsafe - static char invalid_chunk[] = "XXXX PNG chunk not known"; - invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); - invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); - invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); - invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); - #endif - return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); - } - stbi__skip(s, c.length); - break; - } - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - } -} - -static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) -{ - void *result=NULL; - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth < 8) - ri->bits_per_channel = 8; - else - ri->bits_per_channel = p->depth; - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - if (ri->bits_per_channel == 8) - result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - else - result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; - } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_n; - } - STBI_FREE(p->out); p->out = NULL; - STBI_FREE(p->expanded); p->expanded = NULL; - STBI_FREE(p->idata); p->idata = NULL; - - return result; -} - -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi__png p; - p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp, ri); -} - -static int stbi__png_test(stbi__context *s) -{ - int r; - r = stbi__check_png_header(s); - stbi__rewind(s); - return r; -} - -static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) -{ - if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { - stbi__rewind( p->s ); - return 0; - } - if (x) *x = p->s->img_x; - if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; - return 1; -} - -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__png p; - p.s = s; - return stbi__png_info_raw(&p, x, y, comp); -} - -static int stbi__png_is16(stbi__context *s) -{ - stbi__png p; - p.s = s; - if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) - return 0; - if (p.depth != 16) { - stbi__rewind(p.s); - return 0; - } - return 1; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) { + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i = 0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i = 0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = (t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i = 0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a, b, c, d) \ + (((unsigned)(a) << 24) + ((unsigned)(b) << 16) + ((unsigned)(c) << 8) + (unsigned)(d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) { + stbi_uc palette[1024], pal_img_n = 0; + stbi_uc has_trans = 0, tc[3]; + stbi__uint16 tc16[3]; + stbi__uint32 ioff = 0, idata_limit = 0, i, pal_len = 0; + int first = 1, k, interlace = 0, color = 0, is_iphone = 0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) + return 0; + + if (scan == STBI__SCAN_type) + return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C', 'g', 'B', 'I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I', 'H', 'D', 'R'): { + int comp, filter; + if (!first) + return stbi__err("multiple IHDR", "Corrupt PNG"); + first = 0; + if (c.length != 13) + return stbi__err("bad IHDR len", "Corrupt PNG"); + s->img_x = stbi__get32be(s); + if (s->img_x > (1 << 24)) + return stbi__err("too large", "Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); + if (s->img_y > (1 << 24)) + return stbi__err("too large", "Very large image (corrupt?)"); + z->depth = stbi__get8(s); + if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) + return stbi__err("1/2/4/8/16-bit only", "PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); + if (color > 6) + return stbi__err("bad ctype", "Corrupt PNG"); + if (color == 3 && z->depth == 16) + return stbi__err("bad ctype", "Corrupt PNG"); + if (color == 3) + pal_img_n = 3; + else if (color & 1) + return stbi__err("bad ctype", "Corrupt PNG"); + comp = stbi__get8(s); + if (comp) + return stbi__err("bad comp method", "Corrupt PNG"); + filter = stbi__get8(s); + if (filter) + return stbi__err("bad filter method", "Corrupt PNG"); + interlace = stbi__get8(s); + if (interlace > 1) + return stbi__err("bad interlace method", "Corrupt PNG"); + if (!s->img_x || !s->img_y) + return stbi__err("0-pixel image", "Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) + return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) + return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) + return stbi__err("too large", "Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P', 'L', 'T', 'E'): { + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256 * 3) + return stbi__err("invalid PLTE", "Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) + return stbi__err("invalid PLTE", "Corrupt PNG"); + for (i = 0; i < pal_len; ++i) { + palette[i * 4 + 0] = stbi__get8(s); + palette[i * 4 + 1] = stbi__get8(s); + palette[i * 4 + 2] = stbi__get8(s); + palette[i * 4 + 3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t', 'R', 'N', 'S'): { + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) + return stbi__err("tRNS after IDAT", "Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { + s->img_n = 4; + return 1; + } + if (pal_len == 0) + return stbi__err("tRNS before PLTE", "Corrupt PNG"); + if (c.length > pal_len) + return stbi__err("bad tRNS len", "Corrupt PNG"); + pal_img_n = 4; + for (i = 0; i < c.length; ++i) + palette[i * 4 + 3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) + return stbi__err("tRNS with alpha", "Corrupt PNG"); + if (c.length != (stbi__uint32)s->img_n * 2) + return stbi__err("bad tRNS len", "Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) + tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) + tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * + stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I', 'D', 'A', 'T'): { + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) + return stbi__err("no PLTE", "Corrupt PNG"); + if (scan == STBI__SCAN_header) { + s->img_n = pal_img_n; + return 1; + } + if ((int)(ioff + c.length) < (int)ioff) + return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) + idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *)STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); + if (p == NULL) + return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata + ioff, c.length)) + return stbi__err("outofdata", "Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I', 'E', 'N', 'D'): { + stbi__uint32 raw_len, bpl; + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) + return 1; + if (z->idata == NULL) + return stbi__err("no IDAT", "Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *)stbi_zlib_decode_malloc_guesssize_headerflag((char *)z->idata, ioff, raw_len, + (int *)&raw_len, !is_iphone); + if (z->expanded == NULL) + return 0; // zlib should set error + STBI_FREE(z->idata); + z->idata = NULL; + if ((req_comp == s->img_n + 1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n + 1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) + return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) + return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) + return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) + s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); + z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { +#ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); +#endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) { + void *result = NULL; + if (req_comp < 0 || req_comp > 4) + return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = + stbi__convert_format((unsigned char *)result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = + stbi__convert_format16((stbi__uint16 *)result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) + return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) + *n = p->s->img_n; + } + STBI_FREE(p->out); + p->out = NULL; + STBI_FREE(p->expanded); + p->expanded = NULL; + STBI_FREE(p->idata); + p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + stbi__png p; + p.s = s; + return stbi__do_png(&p, x, y, comp, req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) { + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) { + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind(p->s); + return 0; + } + if (x) + *x = p->s->img_x; + if (y) + *y = p->s->img_y; + if (comp) + *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) { + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) { + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; } #endif // Microsoft/Windows BMP image #ifndef STBI_NO_BMP -static int stbi__bmp_test_raw(stbi__context *s) -{ - int r; - int sz; - if (stbi__get8(s) != 'B') return 0; - if (stbi__get8(s) != 'M') return 0; - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - stbi__get32le(s); // discard data offset - sz = stbi__get32le(s); - r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); - return r; -} - -static int stbi__bmp_test(stbi__context *s) -{ - int r = stbi__bmp_test_raw(s); - stbi__rewind(s); - return r; +static int stbi__bmp_test_raw(stbi__context *s) { + int r; + int sz; + if (stbi__get8(s) != 'B') + return 0; + if (stbi__get8(s) != 'M') + return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) { + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; } - // returns 0..31 for the highest set bit -static int stbi__high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) n += 16, z >>= 16; - if (z >= 0x00100) n += 8, z >>= 8; - if (z >= 0x00010) n += 4, z >>= 4; - if (z >= 0x00004) n += 2, z >>= 2; - if (z >= 0x00002) n += 1, z >>= 1; - return n; -} - -static int stbi__bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; +static int stbi__high_bit(unsigned int z) { + int n = 0; + if (z == 0) + return -1; + if (z >= 0x10000) + n += 16, z >>= 16; + if (z >= 0x00100) + n += 8, z >>= 8; + if (z >= 0x00010) + n += 4, z >>= 4; + if (z >= 0x00004) + n += 2, z >>= 2; + if (z >= 0x00002) + n += 1, z >>= 1; + return n; +} + +static int stbi__bitcount(unsigned int a) { + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; } // extract an arbitrarily-aligned N-bit value (N=bits) // from v, and then make it 8-bits long and fractionally // extend it to full full range. -static int stbi__shiftsigned(int v, int shift, int bits) -{ - static unsigned int mul_table[9] = { - 0, - 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, - 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, - }; - static unsigned int shift_table[9] = { - 0, 0,0,1,0,2,4,6,0, - }; - if (shift < 0) - v <<= -shift; - else - v >>= shift; - STBI_ASSERT(v >= 0 && v < 256); - v >>= (8-bits); - STBI_ASSERT(bits >= 0 && bits <= 8); - return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; -} - -typedef struct -{ - int bpp, offset, hsz; - unsigned int mr,mg,mb,ma, all_a; +static int stbi__shiftsigned(int v, int shift, int bits) { + static unsigned int mul_table[9] = { + 0, + 0xff /*0b11111111*/, + 0x55 /*0b01010101*/, + 0x49 /*0b01001001*/, + 0x11 /*0b00010001*/, + 0x21 /*0b00100001*/, + 0x41 /*0b01000001*/, + 0x81 /*0b10000001*/, + 0x01 /*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0, 0, 1, 0, 2, 4, 6, 0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v >= 0 && v < 256); + v >>= (8 - bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int)((unsigned)v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct { + int bpp, offset, hsz; + unsigned int mr, mg, mb, ma, all_a; } stbi__bmp_data; -static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) -{ - int hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - info->offset = stbi__get32le(s); - info->hsz = hsz = stbi__get32le(s); - info->mr = info->mg = info->mb = info->ma = 0; - - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); - if (hsz == 12) { - s->img_x = stbi__get16le(s); - s->img_y = stbi__get16le(s); - } else { - s->img_x = stbi__get32le(s); - s->img_y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); - info->bpp = stbi__get16le(s); - if (hsz != 12) { - int compress = stbi__get32le(s); - if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); - stbi__get32le(s); // discard sizeof - stbi__get32le(s); // discard hres - stbi__get32le(s); // discard vres - stbi__get32le(s); // discard colorsused - stbi__get32le(s); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - } - if (info->bpp == 16 || info->bpp == 32) { - if (compress == 0) { - if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } - } else if (compress == 3) { - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - // not documented, but generated by photoshop and handled by mspaint - if (info->mr == info->mg && info->mg == info->mb) { - // ?!?!? - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else { - int i; - if (hsz != 108 && hsz != 124) - return stbi__errpuc("bad BMP", "bad BMP"); - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - info->ma = stbi__get32le(s); - stbi__get32le(s); // discard color space - for (i=0; i < 12; ++i) - stbi__get32le(s); // discard color space parameters - if (hsz == 124) { - stbi__get32le(s); // discard rendering intent - stbi__get32le(s); // discard offset of profile data - stbi__get32le(s); // discard size of profile data - stbi__get32le(s); // discard reserved - } - } - } - return (void *) 1; -} - - -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - unsigned int mr=0,mg=0,mb=0,ma=0, all_a; - stbi_uc pal[256][4]; - int psize=0,i,j,width; - int flip_vertically, pad, target; - stbi__bmp_data info; - STBI_NOTUSED(ri); - - info.all_a = 255; - if (stbi__bmp_parse_header(s, &info) == NULL) - return NULL; // error code already set - - flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); - - mr = info.mr; - mg = info.mg; - mb = info.mb; - ma = info.ma; - all_a = info.all_a; - - if (info.hsz == 12) { - if (info.bpp < 24) - psize = (info.offset - 14 - 24) / 3; - } else { - if (info.bpp < 16) - psize = (info.offset - 14 - info.hsz) >> 2; - } - - s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = s->img_n; // if they want monochrome, we'll post-convert - - // sanity-check size - if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "Corrupt BMP"); - - out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (info.bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } - for (i=0; i < psize; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - if (info.hsz != 12) stbi__get8(s); - pal[i][3] = 255; - } - stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); - if (info.bpp == 1) width = (s->img_x + 7) >> 3; - else if (info.bpp == 4) width = (s->img_x + 1) >> 1; - else if (info.bpp == 8) width = s->img_x; - else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } - pad = (-width)&3; - if (info.bpp == 1) { - for (j=0; j < (int) s->img_y; ++j) { - int bit_offset = 7, v = stbi__get8(s); - for (i=0; i < (int) s->img_x; ++i) { - int color = (v>>bit_offset)&0x1; - out[z++] = pal[color][0]; - out[z++] = pal[color][1]; - out[z++] = pal[color][2]; - if((--bit_offset) < 0) { - bit_offset = 7; - v = stbi__get8(s); - } - } - stbi__skip(s, pad); - } - } else { - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (info.bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (info.bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - stbi__skip(s, pad); - } - } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - stbi__skip(s, info.offset - 14 - info.hsz); - if (info.bpp == 24) width = 3 * s->img_x; - else if (info.bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (info.bpp == 24) { - easy = 1; - } else if (info.bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - // right shift amt to put high bit in position #7 - rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); - gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); - bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); - ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); - } - for (j=0; j < (int) s->img_y; ++j) { - if (easy) { - for (i=0; i < (int) s->img_x; ++i) { - unsigned char a; - out[z+2] = stbi__get8(s); - out[z+1] = stbi__get8(s); - out[z+0] = stbi__get8(s); - z += 3; - a = (easy == 2 ? stbi__get8(s) : 255); - all_a |= a; - if (target == 4) out[z++] = a; - } - } else { - int bpp = info.bpp; - for (i=0; i < (int) s->img_x; ++i) { - stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); - unsigned int a; - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); - a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); - all_a |= a; - if (target == 4) out[z++] = STBI__BYTECAST(a); - } - } - stbi__skip(s, pad); - } - } - - // if alpha channel is all 0s, replace with all 255s - if (target == 4 && all_a == 0) - for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) - out[i] = 255; - - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) s->img_y>>1; ++j) { - stbi_uc *p1 = out + j *s->img_x*target; - stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; - for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i], p1[i] = p2[i], p2[i] = t; - } - } - } - - if (req_comp && req_comp != target) { - out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - return out; +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) { + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') + return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) + return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) + return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) + return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i = 0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *)1; +} + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + stbi_uc *out; + unsigned int mr = 0, mg = 0, mb = 0, ma = 0, all_a; + stbi_uc pal[256][4]; + int psize = 0, i, j, width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int)s->img_y) > 0; + s->img_y = abs((int)s->img_y); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - 14 - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - 14 - info.hsz) >> 2; + } + + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *)stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) + return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z = 0; + if (psize == 0 || psize > 256) { + STBI_FREE(out); + return stbi__errpuc("invalid", "Corrupt BMP"); + } + for (i = 0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) + stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) + width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) + width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) + width = s->img_x; + else { + STBI_FREE(out); + return stbi__errpuc("bad bpp", "Corrupt BMP"); + } + pad = (-width) & 3; + if (info.bpp == 1) { + for (j = 0; j < (int)s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i = 0; i < (int)s->img_x; ++i) { + int color = (v >> bit_offset) & 0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if ((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j = 0; j < (int)s->img_y; ++j) { + for (i = 0; i < (int)s->img_x; i += 2) { + int v = stbi__get8(s), v2 = 0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) + out[z++] = 255; + if (i + 1 == (int)s->img_x) + break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) + out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift = 0, gshift = 0, bshift = 0, ashift = 0, rcount = 0, gcount = 0, bcount = 0, acount = 0; + int z = 0; + int easy = 0; + stbi__skip(s, info.offset - 14 - info.hsz); + if (info.bpp == 24) + width = 3 * s->img_x; + else if (info.bpp == 16) + width = 2 * s->img_x; + else /* bpp = 32 and pad = 0 */ + width = 0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { + STBI_FREE(out); + return stbi__errpuc("bad masks", "Corrupt BMP"); + } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr) - 7; + rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg) - 7; + gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb) - 7; + bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma) - 7; + acount = stbi__bitcount(ma); + } + for (j = 0; j < (int)s->img_y; ++j) { + if (easy) { + for (i = 0; i < (int)s->img_x; ++i) { + unsigned char a; + out[z + 2] = stbi__get8(s); + out[z + 1] = stbi__get8(s); + out[z + 0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) + out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i = 0; i < (int)s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32)stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) + out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i = 4 * s->img_x * s->img_y - 1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j = 0; j < (int)s->img_y >> 1; ++j) { + stbi_uc *p1 = out + j * s->img_x * target; + stbi_uc *p2 = out + (s->img_y - 1 - j) * s->img_x * target; + for (i = 0; i < (int)s->img_x * target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) + return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) + *comp = s->img_n; + return out; } #endif @@ -5320,330 +5603,332 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req // by Jonathan Dummer #ifndef STBI_NO_TGA // returns STBI_rgb or whatever, 0 on error -static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) -{ - // only RGB or RGBA (incl. 16bit) or grey allowed - if (is_rgb16) *is_rgb16 = 0; - switch(bits_per_pixel) { - case 8: return STBI_grey; - case 16: if(is_grey) return STBI_grey_alpha; - // fallthrough - case 15: if(is_rgb16) *is_rgb16 = 1; - return STBI_rgb; - case 24: // fallthrough - case 32: return bits_per_pixel/8; - default: return 0; - } -} - -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) -{ - int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; - int sz, tga_colormap_type; - stbi__get8(s); // discard Offset - tga_colormap_type = stbi__get8(s); // colormap type - if( tga_colormap_type > 1 ) { - stbi__rewind(s); - return 0; // only RGB or indexed allowed - } - tga_image_type = stbi__get8(s); // image type - if ( tga_colormap_type == 1 ) { // colormapped (paletted) image - if (tga_image_type != 1 && tga_image_type != 9) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip image x and y origin - tga_colormap_bpp = sz; - } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE - if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { - stbi__rewind(s); - return 0; // only RGB or grey allowed, +/- RLE - } - stbi__skip(s,9); // skip colormap specification and image x/y origin - tga_colormap_bpp = 0; - } - tga_w = stbi__get16le(s); - if( tga_w < 1 ) { - stbi__rewind(s); - return 0; // test width - } - tga_h = stbi__get16le(s); - if( tga_h < 1 ) { - stbi__rewind(s); - return 0; // test height - } - tga_bits_per_pixel = stbi__get8(s); // bits per pixel - stbi__get8(s); // ignore alpha bits - if (tga_colormap_bpp != 0) { - if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { - // when using a colormap, tga_bits_per_pixel is the size of the indexes - // I don't think anything but 8 or 16bit indexes makes sense - stbi__rewind(s); - return 0; - } - tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); - } else { - tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); - } - if(!tga_comp) { - stbi__rewind(s); - return 0; - } - if (x) *x = tga_w; - if (y) *y = tga_h; - if (comp) *comp = tga_comp; - return 1; // seems to have passed everything -} - -static int stbi__tga_test(stbi__context *s) -{ - int res = 0; - int sz, tga_color_type; - stbi__get8(s); // discard Offset - tga_color_type = stbi__get8(s); // color type - if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed - sz = stbi__get8(s); // image type - if ( tga_color_type == 1 ) { // colormapped (paletted) image - if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; - stbi__skip(s,4); // skip image x and y origin - } else { // "normal" image w/o colormap - if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE - stbi__skip(s,9); // skip colormap specification and image x/y origin - } - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height - sz = stbi__get8(s); // bits per pixel - if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; - - res = 1; // if we got this far, everything's good and we can return 1 instead of 0 +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int *is_rgb16) { + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) + *is_rgb16 = 0; + switch (bits_per_pixel) { + case 8: + return STBI_grey; + case 16: + if (is_grey) + return STBI_grey_alpha; + // fallthrough + case 15: + if (is_rgb16) + *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: + return bits_per_pixel / 8; + default: + return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) { + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if (tga_colormap_type > 1) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if (tga_colormap_type == 1) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ((tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11)) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s, 9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if (tga_w < 1) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if (tga_h < 1) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if (!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) + *x = tga_w; + if (y) + *y = tga_h; + if (comp) + *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) { + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if (tga_color_type > 1) + goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if (tga_color_type == 1) { // colormapped (paletted) image + if (sz != 1 && sz != 9) + goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s, 4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) + goto errorEnd; + stbi__skip(s, 4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ((sz != 2) && (sz != 3) && (sz != 10) && (sz != 11)) + goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s, 9); // skip colormap specification and image x/y origin + } + if (stbi__get16le(s) < 1) + goto errorEnd; // test width + if (stbi__get16le(s) < 1) + goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ((tga_color_type == 1) && (sz != 8) && (sz != 16)) + goto errorEnd; // for colormapped images, bpp is size of an index + if ((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) + goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 errorEnd: - stbi__rewind(s); - return res; + stbi__rewind(s); + return res; } // read 16bit value and convert to 24bit RGB -static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) -{ - stbi__uint16 px = (stbi__uint16)stbi__get16le(s); - stbi__uint16 fiveBitMask = 31; - // we have 3 channels with 5bits each - int r = (px >> 10) & fiveBitMask; - int g = (px >> 5) & fiveBitMask; - int b = px & fiveBitMask; - // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later - out[0] = (stbi_uc)((r * 255)/31); - out[1] = (stbi_uc)((g * 255)/31); - out[2] = (stbi_uc)((b * 255)/31); - - // some people claim that the most significant bit might be used for alpha - // (possibly if an alpha-bit is set in the "image descriptor byte") - // but that only made 16bit test images completely translucent.. - // so let's treat all 15 and 16bit TGAs as RGB with no alpha. -} - -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - // read in the TGA header stuff - int tga_offset = stbi__get8(s); - int tga_indexed = stbi__get8(s); - int tga_image_type = stbi__get8(s); - int tga_is_RLE = 0; - int tga_palette_start = stbi__get16le(s); - int tga_palette_len = stbi__get16le(s); - int tga_palette_bits = stbi__get8(s); - int tga_x_origin = stbi__get16le(s); - int tga_y_origin = stbi__get16le(s); - int tga_width = stbi__get16le(s); - int tga_height = stbi__get16le(s); - int tga_bits_per_pixel = stbi__get8(s); - int tga_comp, tga_rgb16=0; - int tga_inverted = stbi__get8(s); - // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4] = {0}; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - STBI_NOTUSED(ri); - - // do a tiny bit of precessing - if ( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - tga_inverted = 1 - ((tga_inverted >> 5) & 1); - - // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); - else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); - - if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency - return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); - - // tga info - *x = tga_width; - *y = tga_height; - if (comp) *comp = tga_comp; - - if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) - return stbi__errpuc("too large", "Corrupt TGA"); - - tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); - if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); - - // skip to the data's starting position (offset usually = 0) - stbi__skip(s, tga_offset ); - - if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { - for (i=0; i < tga_height; ++i) { - int row = tga_inverted ? tga_height -i - 1 : i; - stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; - stbi__getn(s, tga_row, tga_width * tga_comp); - } - } else { - // do I need to load a palette? - if ( tga_indexed) - { - // any data to skip? (offset usually = 0) - stbi__skip(s, tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); - if (!tga_palette) { - STBI_FREE(tga_data); - return stbi__errpuc("outofmem", "Out of memory"); - } - if (tga_rgb16) { - stbi_uc *pal_entry = tga_palette; - STBI_ASSERT(tga_comp == STBI_rgb); - for (i=0; i < tga_palette_len; ++i) { - stbi__tga_read_rgb16(s, pal_entry); - pal_entry += tga_comp; - } - } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { - STBI_FREE(tga_data); - STBI_FREE(tga_palette); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } - } - // load the data - for (i=0; i < tga_width * tga_height; ++i) - { - // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? - if ( tga_is_RLE ) - { - if ( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = stbi__get8(s); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if ( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if ( read_next_pixel ) - { - // load however much data we did have - if ( tga_indexed ) - { - // read in index, then perform the lookup - int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); - if ( pal_idx >= tga_palette_len ) { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_comp; - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else if(tga_rgb16) { - STBI_ASSERT(tga_comp == STBI_rgb); - stbi__tga_read_rgb16(s, raw_data); - } else { - // read in the data raw - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = stbi__get8(s); - } - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel - - // copy data - for (j = 0; j < tga_comp; ++j) - tga_data[i*tga_comp+j] = raw_data[j]; - - // in case we're in RLE mode, keep counting down - --RLE_count; - } - // do I need to invert the image? - if ( tga_inverted ) - { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * tga_comp; - int index2 = (tga_height - 1 - j) * tga_width * tga_comp; - for (i = tga_width * tga_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } - } - // clear my palette, if I had one - if ( tga_palette != NULL ) - { - STBI_FREE( tga_palette ); - } - } - - // swap RGB - if the source data was RGB16, it already is in the right order - if (tga_comp >= 3 && !tga_rgb16) - { - unsigned char* tga_pixel = tga_data; - for (i=0; i < tga_width * tga_height; ++i) - { - unsigned char temp = tga_pixel[0]; - tga_pixel[0] = tga_pixel[2]; - tga_pixel[2] = temp; - tga_pixel += tga_comp; - } - } - - // convert to target component count - if (req_comp && req_comp != tga_comp) - tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); - - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - // OK, done - return tga_data; +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc *out) { + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255) / 31); + out[1] = (stbi_uc)((g * 255) / 31); + out[2] = (stbi_uc)((b * 255) / 31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16 = 0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + + // do a tiny bit of precessing + if (tga_image_type >= 8) { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if (tga_indexed) + tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if (!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) + *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char *)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) + return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset); + + if (!tga_indexed && !tga_is_RLE && !tga_rgb16) { + for (i = 0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height - i - 1 : i; + stbi_uc *tga_row = tga_data + row * tga_width * tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if (tga_indexed) { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start); + // load the palette + tga_palette = (unsigned char *)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i = 0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i = 0; i < tga_width * tga_height; ++i) { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if (tga_is_RLE) { + if (RLE_count == 0) { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if (!RLE_repeating) { + read_next_pixel = 1; + } + } else { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if (read_next_pixel) { + // load however much data we did have + if (tga_indexed) { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if (pal_idx >= tga_palette_len) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx + j]; + } + } else if (tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i * tga_comp + j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if (tga_inverted) { + for (j = 0; j * 2 < tga_height; ++j) { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if (tga_palette != NULL) { + STBI_FREE(tga_palette); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) { + unsigned char *tga_pixel = tga_data; + for (i = 0; i < tga_width * tga_height; ++i) { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; } #endif @@ -5651,247 +5936,249 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB #ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s) -{ - int r = (stbi__get32be(s) == 0x38425053); - stbi__rewind(s); - return r; -} - -static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) -{ - int count, nleft, len; - - count = 0; - while ((nleft = pixelCount - count) > 0) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - if (len > nleft) return 0; // corrupt data - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len = 257 - len; - if (len > nleft) return 0; // corrupt data - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } - - return 1; -} - -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - int pixelCount; - int channelCount, compression; - int channel, i; - int bitdepth; - int w,h; - stbi_uc *out; - STBI_NOTUSED(ri); - - // Check identifier - if (stbi__get32be(s) != 0x38425053) // "8BPS" - return stbi__errpuc("not PSD", "Corrupt PSD image"); - - // Check file type version. - if (stbi__get16be(s) != 1) - return stbi__errpuc("wrong version", "Unsupported version of PSD image"); - - // Skip 6 reserved bytes. - stbi__skip(s, 6 ); - - // Read the number of channels (R, G, B, A, etc). - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) - return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); - - // Read the rows and columns of the image. - h = stbi__get32be(s); - w = stbi__get32be(s); - - // Make sure the depth is 8 bits. - bitdepth = stbi__get16be(s); - if (bitdepth != 8 && bitdepth != 16) - return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); - - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (stbi__get16be(s) != 3) - return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); - - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - stbi__skip(s,stbi__get32be(s) ); - - // Skip the image resources. (resolution, pen tool paths, etc) - stbi__skip(s, stbi__get32be(s) ); - - // Skip the reserved data. - stbi__skip(s, stbi__get32be(s) ); - - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = stbi__get16be(s); - if (compression > 1) - return stbi__errpuc("bad compression", "PSD has an unknown compression format"); - - // Check size - if (!stbi__mad3sizes_valid(4, w, h, 0)) - return stbi__errpuc("too large", "Corrupt PSD"); - - // Create the destination image. - - if (!compression && bitdepth == 16 && bpc == 16) { - out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); - ri->bits_per_channel = 16; - } else - out = (stbi_uc *) stbi__malloc(4 * w*h); - - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - pixelCount = w*h; - - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); - - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop - - // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, - // which we're going to just skip. - stbi__skip(s, h * channelCount * 2 ); - - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; - - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++, p += 4) - *p = (channel == 3 ? 255 : 0); - } else { - // Read the RLE data. - if (!stbi__psd_decode_rle(s, p, pixelCount)) { - STBI_FREE(out); - return stbi__errpuc("corrupt", "bad RLE data"); - } - } - } - - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. - - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - if (channel >= channelCount) { - // Fill this channel with default data. - if (bitdepth == 16 && bpc == 16) { - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - stbi__uint16 val = channel == 3 ? 65535 : 0; - for (i = 0; i < pixelCount; i++, q += 4) - *q = val; - } else { - stbi_uc *p = out+channel; - stbi_uc val = channel == 3 ? 255 : 0; - for (i = 0; i < pixelCount; i++, p += 4) - *p = val; - } - } else { - if (ri->bits_per_channel == 16) { // output bpc - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - for (i = 0; i < pixelCount; i++, q += 4) - *q = (stbi__uint16) stbi__get16be(s); - } else { - stbi_uc *p = out+channel; - if (bitdepth == 16) { // input bpc - for (i = 0; i < pixelCount; i++, p += 4) - *p = (stbi_uc) (stbi__get16be(s) >> 8); - } else { - for (i = 0; i < pixelCount; i++, p += 4) - *p = stbi__get8(s); - } - } - } - } - } - - // remove weird white matte from PSD - if (channelCount >= 4) { - if (ri->bits_per_channel == 16) { - for (i=0; i < w*h; ++i) { - stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; - if (pixel[3] != 0 && pixel[3] != 65535) { - float a = pixel[3] / 65535.0f; - float ra = 1.0f / a; - float inv_a = 65535.0f * (1 - ra); - pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); - pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); - pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); - } - } - } else { - for (i=0; i < w*h; ++i) { - unsigned char *pixel = out + 4*i; - if (pixel[3] != 0 && pixel[3] != 255) { - float a = pixel[3] / 255.0f; - float ra = 1.0f / a; - float inv_a = 255.0f * (1 - ra); - pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); - pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); - pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); - } - } - } - } - - // convert to desired output format - if (req_comp && req_comp != 4) { - if (ri->bits_per_channel == 16) - out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); - else - out = stbi__convert_format(out, 4, req_comp, w, h); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - if (comp) *comp = 4; - *y = h; - *x = w; - - return out; +static int stbi__psd_test(stbi__context *s) { + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) { + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) + return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) + return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w, h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s, stbi__get32be(s)); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s)); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s)); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *)stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *)stbi__malloc(4 * w * h); + + if (!out) + return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w * h; + + // Initialize the data to zero. + // memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out + channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *)out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out + channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *)out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16)stbi__get16be(s); + } else { + stbi_uc *p = out + channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc)(stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i = 0; i < w * h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *)out + 4 * i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16)(pixel[0] * ra + inv_a); + pixel[1] = (stbi__uint16)(pixel[1] * ra + inv_a); + pixel[2] = (stbi__uint16)(pixel[2] * ra + inv_a); + } + } + } else { + for (i = 0; i < w * h; ++i) { + unsigned char *pixel = out + 4 * i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char)(pixel[0] * ra + inv_a); + pixel[1] = (unsigned char)(pixel[1] * ra + inv_a); + pixel[2] = (unsigned char)(pixel[2] * ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *)stbi__convert_format16((stbi__uint16 *)out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) + return out; // stbi__convert_format frees input on failure + } + + if (comp) + *comp = 4; + *y = h; + *x = w; + + return out; } #endif @@ -5903,211 +6190,213 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req // See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ #ifndef STBI_NO_PIC -static int stbi__pic_is4(stbi__context *s,const char *str) -{ - int i; - for (i=0; i<4; ++i) - if (stbi__get8(s) != (stbi_uc)str[i]) - return 0; +static int stbi__pic_is4(stbi__context *s, const char *str) { + int i; + for (i = 0; i < 4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; - return 1; + return 1; } -static int stbi__pic_test_core(stbi__context *s) -{ - int i; +static int stbi__pic_test_core(stbi__context *s) { + int i; - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) - return 0; + if (!stbi__pic_is4(s, "\x53\x80\xF6\x34")) + return 0; - for(i=0;i<84;++i) - stbi__get8(s); + for (i = 0; i < 84; ++i) + stbi__get8(s); - if (!stbi__pic_is4(s,"PICT")) - return 0; + if (!stbi__pic_is4(s, "PICT")) + return 0; - return 1; + return 1; } -typedef struct -{ - stbi_uc size,type,channel; +typedef struct { + stbi_uc size, type, channel; } stbi__pic_packet; -static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) -{ - int mask=0x80, i; +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) { + int mask = 0x80, i; - for (i=0; i<4; ++i, mask>>=1) { - if (channel & mask) { - if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); - dest[i]=stbi__get8(s); - } - } + for (i = 0; i < 4; ++i, mask >>= 1) { + if (channel & mask) { + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "PIC file too short"); + dest[i] = stbi__get8(s); + } + } - return dest; + return dest; } -static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) -{ - int mask=0x80,i; +static void stbi__copyval(int channel, stbi_uc *dest, const stbi_uc *src) { + int mask = 0x80, i; - for (i=0;i<4; ++i, mask>>=1) - if (channel&mask) - dest[i]=src[i]; + for (i = 0; i < 4; ++i, mask >>= 1) + if (channel & mask) + dest[i] = src[i]; } -static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) -{ - int act_comp=0,num_packets=0,y,chained; - stbi__pic_packet packets[10]; - - // this will (should...) cater for even some bizarre stuff like having data - // for the same channel in multiple packets. - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return stbi__errpuc("bad format","too many packets"); - - packet = &packets[num_packets++]; +static stbi_uc *stbi__pic_load_core(stbi__context *s, int width, int height, int *comp, stbi_uc *result) { + int act_comp = 0, num_packets = 0, y, chained; + stbi__pic_packet packets[10]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets == sizeof(packets) / sizeof(packets[0])) + return stbi__errpuc("bad format", "too many packets"); - act_comp |= packet->channel; + packet = &packets[num_packets++]; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); - if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); - } while (chained); + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); - *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + act_comp |= packet->channel; - for(y=0; ysize != 8) + return stbi__errpuc("bad format", "packet isn't 8bpp"); + } while (chained); - for(packet_idx=0; packet_idx < num_packets; ++packet_idx) { - stbi__pic_packet *packet = &packets[packet_idx]; - stbi_uc *dest = result+y*width*4; + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? - switch (packet->type) { - default: - return stbi__errpuc("bad format","packet has bad compression type"); + for (y = 0; y < height; ++y) { + int packet_idx; - case 0: {//uncompressed - int x; + for (packet_idx = 0; packet_idx < num_packets; ++packet_idx) { + stbi__pic_packet *packet = &packets[packet_idx]; + stbi_uc *dest = result + y * width * 4; - for(x=0;xchannel,dest)) - return 0; - break; - } + switch (packet->type) { + default: + return stbi__errpuc("bad format", "packet has bad compression type"); - case 1://Pure RLE - { - int left=width, i; + case 0: { // uncompressed + int x; - while (left>0) { - stbi_uc count,value[4]; + for (x = 0; x < width; ++x, dest += 4) + if (!stbi__readval(s, packet->channel, dest)) + return 0; + break; + } + + case 1: // Pure RLE + { + int left = width, i; - count=stbi__get8(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + while (left > 0) { + stbi_uc count, value[4]; - if (count > left) - count = (stbi_uc) left; + count = stbi__get8(s); + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "file too short (pure read count)"); - if (!stbi__readval(s,packet->channel,value)) return 0; + if (count > left) + count = (stbi_uc)left; - for(i=0; ichannel,dest,value); - left -= count; - } - } - break; + if (!stbi__readval(s, packet->channel, value)) + return 0; - case 2: {//Mixed RLE - int left=width; - while (left>0) { - int count = stbi__get8(s), i; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + for (i = 0; i < count; ++i, dest += 4) + stbi__copyval(packet->channel, dest, value); + left -= count; + } + } break; - if (count >= 128) { // Repeated - stbi_uc value[4]; + case 2: { // Mixed RLE + int left = width; + while (left > 0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count == 128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file", "scanline overrun"); - if (count==128) - count = stbi__get16be(s); - else - count -= 127; - if (count > left) - return stbi__errpuc("bad file","scanline overrun"); + if (!stbi__readval(s, packet->channel, value)) + return 0; - if (!stbi__readval(s,packet->channel,value)) - return 0; - - for(i=0;ichannel,dest,value); - } else { // Raw - ++count; - if (count>left) return stbi__errpuc("bad file","scanline overrun"); - - for(i=0;ichannel,dest)) - return 0; - } - left-=count; - } - break; - } - } - } - } - - return result; -} - -static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) -{ - stbi_uc *result; - int i, x,y, internal_comp; - STBI_NOTUSED(ri); - - if (!comp) comp = &internal_comp; - - for (i=0; i<92; ++i) - stbi__get8(s); - - x = stbi__get16be(s); - y = stbi__get16be(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); - - stbi__get32be(s); //skip `ratio' - stbi__get16be(s); //skip `fields' - stbi__get16be(s); //skip `pad' - - // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); - memset(result, 0xff, x*y*4); - - if (!stbi__pic_load_core(s,x,y,comp, result)) { - STBI_FREE(result); - result=0; - } - *px = x; - *py = y; - if (req_comp == 0) req_comp = *comp; - result=stbi__convert_format(result,4,req_comp,x,y); - - return result; -} - -static int stbi__pic_test(stbi__context *s) -{ - int r = stbi__pic_test_core(s); - stbi__rewind(s); - return r; + for (i = 0; i < count; ++i, dest += 4) + stbi__copyval(packet->channel, dest, value); + } else { // Raw + ++count; + if (count > left) + return stbi__errpuc("bad file", "scanline overrun"); + + for (i = 0; i < count; ++i, dest += 4) + if (!stbi__readval(s, packet->channel, dest)) + return 0; + } + left -= count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s, int *px, int *py, int *comp, int req_comp, stbi__result_info *ri) { + stbi_uc *result; + int i, x, y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) + comp = &internal_comp; + + for (i = 0; i < 92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) + return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); // skip `ratio' + stbi__get16be(s); // skip `fields' + stbi__get16be(s); // skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *)stbi__malloc_mad3(x, y, 4, 0); + memset(result, 0xff, x * y * 4); + + if (!stbi__pic_load_core(s, x, y, comp, result)) { + STBI_FREE(result); + result = 0; + } + *px = x; + *py = y; + if (req_comp == 0) + req_comp = *comp; + result = stbi__convert_format(result, 4, req_comp, x, y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) { + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; } #endif @@ -6115,868 +6404,901 @@ static int stbi__pic_test(stbi__context *s) // GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb #ifndef STBI_NO_GIF -typedef struct -{ - stbi__int16 prefix; - stbi_uc first; - stbi_uc suffix; +typedef struct { + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; } stbi__gif_lzw; -typedef struct -{ - int w,h; - stbi_uc *out; // output buffer (always 4 components) - stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; - int flags, bgindex, ratio, transparent, eflags; - stbi_uc pal[256][4]; - stbi_uc lpal[256][4]; - stbi__gif_lzw codes[8192]; - stbi_uc *color_table; - int parse, step; - int lflags; - int start_x, start_y; - int max_x, max_y; - int cur_x, cur_y; - int line_size; - int delay; +typedef struct { + int w, h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; } stbi__gif; -static int stbi__gif_test_raw(stbi__context *s) -{ - int sz; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; - sz = stbi__get8(s); - if (sz != '9' && sz != '7') return 0; - if (stbi__get8(s) != 'a') return 0; - return 1; -} - -static int stbi__gif_test(stbi__context *s) -{ - int r = stbi__gif_test_raw(s); - stbi__rewind(s); - return r; -} - -static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) -{ - int i; - for (i=0; i < num_entries; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - pal[i][3] = transp == i ? 0 : 255; - } -} - -static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) -{ - stbi_uc version; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') - return stbi__err("not GIF", "Corrupt GIF"); - - version = stbi__get8(s); - if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); - if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); - - stbi__g_failure_reason = ""; - g->w = stbi__get16le(s); - g->h = stbi__get16le(s); - g->flags = stbi__get8(s); - g->bgindex = stbi__get8(s); - g->ratio = stbi__get8(s); - g->transparent = -1; - - if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments - - if (is_info) return 1; - - if (g->flags & 0x80) - stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); - - return 1; -} - -static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - if (!stbi__gif_header(s, g, comp, 1)) { - STBI_FREE(g); - stbi__rewind( s ); - return 0; - } - if (x) *x = g->w; - if (y) *y = g->h; - STBI_FREE(g); - return 1; -} - -static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) -{ - stbi_uc *p, *c; - int idx; - - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi__out_gif_code(g, g->codes[code].prefix); - - if (g->cur_y >= g->max_y) return; - - idx = g->cur_x + g->cur_y; - p = &g->out[idx]; - g->history[idx / 4] = 1; - - c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } - g->cur_x += 4; - - if (g->cur_x >= g->max_x) { - g->cur_x = g->start_x; - g->cur_y += g->step; - - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; - } - } -} - -static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) -{ - stbi_uc lzw_cs; - stbi__int32 len, init_code; - stbi__uint32 first; - stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; - stbi__gif_lzw *p; - - lzw_cs = stbi__get8(s); - if (lzw_cs > 12) return NULL; - clear = 1 << lzw_cs; - first = 1; - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - bits = 0; - valid_bits = 0; - for (init_code = 0; init_code < clear; init_code++) { - g->codes[init_code].prefix = -1; - g->codes[init_code].first = (stbi_uc) init_code; - g->codes[init_code].suffix = (stbi_uc) init_code; - } - - // support no starting clear code - avail = clear+2; - oldcode = -1; - - len = 0; - for(;;) { - if (valid_bits < codesize) { - if (len == 0) { - len = stbi__get8(s); // start new block - if (len == 0) - return g->out; - } - --len; - bits |= (stbi__int32) stbi__get8(s) << valid_bits; - valid_bits += 8; - } else { - stbi__int32 code = bits & codemask; - bits >>= codesize; - valid_bits -= codesize; - // @OPTIMIZE: is there some way we can accelerate the non-clear path? - if (code == clear) { // clear code - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - avail = clear + 2; - oldcode = -1; - first = 0; - } else if (code == clear + 1) { // end of stream code - stbi__skip(s, len); - while ((len = stbi__get8(s)) > 0) - stbi__skip(s,len); - return g->out; - } else if (code <= avail) { - if (first) { - return stbi__errpuc("no clear code", "Corrupt GIF"); - } - - if (oldcode >= 0) { - p = &g->codes[avail++]; - if (avail > 8192) { - return stbi__errpuc("too many codes", "Corrupt GIF"); - } - - p->prefix = (stbi__int16) oldcode; - p->first = g->codes[oldcode].first; - p->suffix = (code == avail) ? p->first : g->codes[code].first; - } else if (code == avail) - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - - stbi__out_gif_code(g, (stbi__uint16) code); - - if ((avail & codemask) == 0 && avail <= 0x0FFF) { - codesize++; - codemask = (1 << codesize) - 1; - } - - oldcode = code; - } else { - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - } - } - } +static int stbi__gif_test_raw(stbi__context *s) { + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') + return 0; + if (stbi__get8(s) != 'a') + return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) { + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) { + int i; + for (i = 0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) { + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') + return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') + return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) + *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) + return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s, g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { + stbi__gif *g = (stbi__gif *)stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind(s); + return 0; + } + if (x) + *x = g->w; + if (y) + *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) + return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) { + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) + return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc)init_code; + g->codes[init_code].suffix = (stbi_uc)init_code; + } + + // support no starting clear code + avail = clear + 2; + oldcode = -1; + + len = 0; + for (;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32)stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s, len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16)oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16)code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } } // this function is designed to support animated gifs, although stb_image doesn't support it // two back is the image from two frames ago, used for a very specific disposal format -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) -{ - int dispose; - int first_frame; - int pi; - int pcount; - - // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; - if (g->out == 0) { - if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header - g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - g->history = (stbi_uc *) stbi__malloc(g->w * g->h); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - - // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; - // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to teh color that was there the previous frame. - memset( g->out, 0x00, 4 * g->w * g->h ); - memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent) - memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame - first_frame = 1; - } else { - // second frame - how do we dispoase of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; - - if ((dispose == 3) && (two_back == 0)) { - dispose = 2; // if I don't have an image to revert back to, default to the old background - } - - if (dispose == 3) { // use previous graphic - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); - } - } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); - } - } - } else { - // This is a non-disposal case eithe way, so just - // leave the pixels as is, and they will become the new background - // 1: do not dispose - // 0: not specified. - } - - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); - } - - // clear my history; - memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame - - for (;;) { - int tag = stbi__get8(s); - switch (tag) { - case 0x2C: /* Image Descriptor */ - { - stbi__int32 x, y, w, h; - stbi_uc *o; - - x = stbi__get16le(s); - y = stbi__get16le(s); - w = stbi__get16le(s); - h = stbi__get16le(s); - if (((x + w) > (g->w)) || ((y + h) > (g->h))) - return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); - - g->line_size = g->w * 4; - g->start_x = x * 4; - g->start_y = y * g->line_size; - g->max_x = g->start_x + w * 4; - g->max_y = g->start_y + h * g->line_size; - g->cur_x = g->start_x; - g->cur_y = g->start_y; - - g->lflags = stbi__get8(s); - - if (g->lflags & 0x40) { - g->step = 8 * g->line_size; // first interlaced spacing - g->parse = 3; - } else { - g->step = g->line_size; - g->parse = 0; - } - - if (g->lflags & 0x80) { - stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi_uc *) g->lpal; - } else if (g->flags & 0x80) { - g->color_table = (stbi_uc *) g->pal; - } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - - o = stbi__process_gif_raster(s, g); - if (o == NULL) return NULL; - - // if this was the first frame, - pcount = g->w * g->h; - if (first_frame && (g->bgindex > 0)) { - // if first frame, any pixel not drawn to gets the background color - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); - } - } - } - - return o; - } - - case 0x21: // Comment Extension. - { - int len; - int ext = stbi__get8(s); - if (ext == 0xF9) { // Graphic Control Extension. - len = stbi__get8(s); - if (len == 4) { - g->eflags = stbi__get8(s); - g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. - - // unset old transparent - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } - if (g->eflags & 0x01) { - g->transparent = stbi__get8(s); - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; - } - } else { - // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; - } - } else { - stbi__skip(s, len); - break; - } - } - while ((len = stbi__get8(s)) != 0) { - stbi__skip(s, len); - } - break; - } - - case 0x3B: // gif stream termination code - return (stbi_uc *) s; // using '1' causes warning on some compilers - - default: - return stbi__errpuc("unknown code", "Corrupt GIF"); - } - } -} - -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - if (stbi__gif_test(s)) { - int layers = 0; - stbi_uc *u = 0; - stbi_uc *out = 0; - stbi_uc *two_back = 0; - stbi__gif g; - int stride; - memset(&g, 0, sizeof(g)); - if (delays) { - *delays = 0; - } - - do { - u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - - if (u) { - *x = g.w; - *y = g.h; - ++layers; - stride = g.w * g.h * 4; - - if (out) { - out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); - if (delays) { - *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); - } - } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); - if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); - } - } - memcpy( out + ((layers - 1) * stride), u, stride ); - if (layers >= 2) { - two_back = out - 2 * stride; - } - - if (delays) { - (*delays)[layers - 1U] = g.delay; - } - } - } while (u != 0); - - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); - - // do the final conversion after loading everything; - if (req_comp && req_comp != 4) - out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - - *z = layers; - return out; - } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); - } -} - -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *u = 0; - stbi__gif g; - memset(&g, 0, sizeof(g)); - - u = stbi__gif_load_next(s, &g, comp, req_comp, 0); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - if (u) { - *x = g.w; - *y = g.h; - - // moved conversion to after successful load so that the same - // can be done for multiple frames. - if (req_comp && req_comp != 4) - u = stbi__convert_format(u, 4, req_comp, g.w, g.h); - } - - // free buffers needed for multiple frame loading; - STBI_FREE(g.history); - STBI_FREE(g.background); - - return u; -} - -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) -{ - return stbi__gif_info_raw(s,x,y,comp); -} +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) { + int dispose; + int first_frame; + int pi; + int pcount; + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp, 0)) + return 0; // stbi__g_failure_reason set by stbi__gif_header + g->out = (stbi_uc *)stbi__malloc(4 * g->w * g->h); + g->background = (stbi_uc *)stbi__malloc(4 * g->w * g->h); + g->history = (stbi_uc *)stbi__malloc(g->w * g->h); + if (g->out == 0) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to teh color that was there the previous frame. + memset(g->out, 0x00, 4 * g->w * g->h); + memset(g->background, 0x00, 4 * g->w * g->h); // state of the background (starts transparent) + memset(g->history, 0x00, g->w * g->h); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispoase of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy(&g->out[pi * 4], &two_back[pi * 4], 4); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy(&g->out[pi * 4], &g->background[pi * 4], 4); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy(g->background, g->out, 4 * g->w * g->h); + } + + // clear my history; + memset(g->history, 0x00, g->w * g->h); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s, g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *)g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *)g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (o == NULL) + return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be + // reset next frame if need be; + memcpy(&g->out[pi * 4], &g->pal[g->bgindex], 4); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *)s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *)s) + u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + out = (stbi_uc *)STBI_REALLOC(out, layers * stride); + if (delays) { + *delays = (int *)STBI_REALLOC(*delays, sizeof(int) * layers); + } + } else { + out = (stbi_uc *)stbi__malloc(layers * stride); + if (delays) { + *delays = (int *)stbi__malloc(layers * sizeof(int)); + } + } + memcpy(out + ((layers - 1) * stride), u, stride); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *)s) + u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) { return stbi__gif_info_raw(s, x, y, comp); } #endif // ************************************************************************************************* // Radiance RGBE HDR loader // originally by Nicolas Schulz #ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s, const char *signature) -{ - int i; - for (i=0; signature[i]; ++i) - if (stbi__get8(s) != signature[i]) - return 0; - stbi__rewind(s); - return 1; -} - -static int stbi__hdr_test(stbi__context* s) -{ - int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); - stbi__rewind(s); - if(!r) { - r = stbi__hdr_test_core(s, "#?RGBE\n"); - stbi__rewind(s); - } - return r; -} - -#define STBI__HDR_BUFLEN 1024 -static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) -{ - int len=0; - char c = '\0'; - - c = (char) stbi__get8(z); - - while (!stbi__at_eof(z) && c != '\n') { - buffer[len++] = c; - if (len == STBI__HDR_BUFLEN-1) { - // flush to end of line - while (!stbi__at_eof(z) && stbi__get8(z) != '\n') - ; - break; - } - c = (char) stbi__get8(z); - } - - buffer[len] = 0; - return buffer; -} - -static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if ( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } -} - -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - const char *headerToken; - STBI_NOTUSED(ri); - - // Check identifier - headerToken = stbi__hdr_gettoken(s,buffer); - if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) - return stbi__errpf("not HDR", "Corrupt HDR image"); - - // Parse header - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); - - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = (int) strtol(token, NULL, 10); - - *x = width; - *y = height; - - if (comp) *comp = 3; - if (req_comp == 0) req_comp = 3; - - if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) - return stbi__errpf("too large", "HDR image is too large"); - - // Read data - hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); - if (!hdr_data) - return stbi__errpf("outofmem", "Out of memory"); - - // Load image data - // image data is stored as some number of sca - if ( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - stbi__getn(s, rgbe, 4); - stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } - } - } else { - // Read RLE-encoded data - scanline = NULL; - - for (j = 0; j < height; ++j) { - c1 = stbi__get8(s); - c2 = stbi__get8(s); - len = stbi__get8(s); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi_uc rgbe[4]; - rgbe[0] = (stbi_uc) c1; - rgbe[1] = (stbi_uc) c2; - rgbe[2] = (stbi_uc) len; - rgbe[3] = (stbi_uc) stbi__get8(s); - stbi__hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - STBI_FREE(scanline); - goto main_decode_loop; // yes, this makes no sense - } - len <<= 8; - len |= stbi__get8(s); - if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) { - scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); - if (!scanline) { - STBI_FREE(hdr_data); - return stbi__errpf("outofmem", "Out of memory"); - } - } - - for (k = 0; k < 4; ++k) { - int nleft; - i = 0; - while ((nleft = width - i) > 0) { - count = stbi__get8(s); - if (count > 128) { - // Run - value = stbi__get8(s); - count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = stbi__get8(s); - } - } - } - for (i=0; i < width; ++i) - stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); - } - if (scanline) - STBI_FREE(scanline); - } - - return hdr_data; -} - -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int dummy; - - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - - if (stbi__hdr_test(s) == 0) { - stbi__rewind( s ); - return 0; - } - - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) { - stbi__rewind( s ); - return 0; - } - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *y = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *x = (int) strtol(token, NULL, 10); - *comp = 3; - return 1; +static int stbi__hdr_test_core(stbi__context *s, const char *signature) { + int i; + for (i = 0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context *s) { + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if (!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) { + int len = 0; + char c = '\0'; + + c = (char)stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN - 1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char)stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) { + if (input[3] != 0) { + float f1; + // Exponent + f1 = (float)ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) + output[1] = 1; + if (req_comp == 4) + output[3] = 1; + } else { + switch (req_comp) { + case 4: + output[3] = 1; /* fallthrough */ + case 3: + output[0] = output[1] = output[2] = 0; + break; + case 2: + output[1] = 1; /* fallthrough */ + case 1: + output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1, c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s, buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for (;;) { + token = stbi__hdr_gettoken(s, buffer); + if (token[0] == 0) + break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) + valid = 1; + } + + if (!valid) + return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s, buffer); + if (strncmp(token, "-Y ", 3)) + return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int)strtol(token, &token, 10); + while (*token == ' ') + ++token; + if (strncmp(token, "+X ", 3)) + return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int)strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) + *comp = 3; + if (req_comp == 0) + req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *)stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if (width < 8 || width >= 32768) { + // Read flat data + for (j = 0; j < height; ++j) { + for (i = 0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc)c1; + rgbe[1] = (stbi_uc)c2; + rgbe[2] = (stbi_uc)len; + rgbe[3] = (stbi_uc)stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); + } + if (scanline == NULL) { + scanline = (stbi_uc *)stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("corrupt", "bad RLE data in HDR"); + } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("corrupt", "bad RLE data in HDR"); + } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i = 0; i < width; ++i) + stbi__hdr_convert(hdr_data + (j * width + i) * req_comp, scanline + i * 4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) { + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind(s); + return 0; + } + + for (;;) { + token = stbi__hdr_gettoken(s, buffer); + if (token[0] == 0) + break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) + valid = 1; + } + + if (!valid) { + stbi__rewind(s); + return 0; + } + token = stbi__hdr_gettoken(s, buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind(s); + return 0; + } + token += 3; + *y = (int)strtol(token, &token, 10); + while (*token == ' ') + ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind(s); + return 0; + } + token += 3; + *x = (int)strtol(token, NULL, 10); + *comp = 3; + return 1; } #endif // STBI_NO_HDR #ifndef STBI_NO_BMP -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) -{ - void *p; - stbi__bmp_data info; - - info.all_a = 255; - p = stbi__bmp_parse_header(s, &info); - stbi__rewind( s ); - if (p == NULL) - return 0; - if (x) *x = s->img_x; - if (y) *y = s->img_y; - if (comp) *comp = info.ma ? 4 : 3; - return 1; +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) { + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind(s); + if (p == NULL) + return 0; + if (x) + *x = s->img_x; + if (y) + *y = s->img_y; + if (comp) + *comp = info.ma ? 4 : 3; + return 1; } #endif #ifndef STBI_NO_PSD -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) -{ - int channelCount, dummy, depth; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - *y = stbi__get32be(s); - *x = stbi__get32be(s); - depth = stbi__get16be(s); - if (depth != 8 && depth != 16) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 3) { - stbi__rewind( s ); - return 0; - } - *comp = 4; - return 1; -} - -static int stbi__psd_is16(stbi__context *s) -{ - int channelCount, depth; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - (void) stbi__get32be(s); - (void) stbi__get32be(s); - depth = stbi__get16be(s); - if (depth != 16) { - stbi__rewind( s ); - return 0; - } - return 1; +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) { + int channelCount, dummy, depth; + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind(s); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind(s); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind(s); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind(s); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) { + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind(s); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind(s); + return 0; + } + (void)stbi__get32be(s); + (void)stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind(s); + return 0; + } + return 1; } #endif #ifndef STBI_NO_PIC -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) -{ - int act_comp=0,num_packets=0,chained,dummy; - stbi__pic_packet packets[10]; - - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { - stbi__rewind(s); - return 0; - } - - stbi__skip(s, 88); - - *x = stbi__get16be(s); - *y = stbi__get16be(s); - if (stbi__at_eof(s)) { - stbi__rewind( s); - return 0; - } - if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { - stbi__rewind( s ); - return 0; - } - - stbi__skip(s, 8); - - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return 0; - - packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - act_comp |= packet->channel; - - if (stbi__at_eof(s)) { - stbi__rewind( s ); - return 0; - } - if (packet->size != 8) { - stbi__rewind( s ); - return 0; - } - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); - - return 1; +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) { + int act_comp = 0, num_packets = 0, chained, dummy; + stbi__pic_packet packets[10]; + + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; + + if (!stbi__pic_is4(s, "\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind(s); + return 0; + } + if ((*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets == sizeof(packets) / sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind(s); + return 0; + } + if (packet->size != 8) { + stbi__rewind(s); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; } #endif @@ -6994,431 +7316,426 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s) -{ - char p, t; - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - return 1; +static int stbi__pnm_test(stbi__context *s) { + char p, t; + p = (char)stbi__get8(s); + t = (char)stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + return 1; } -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - STBI_NOTUSED(ri); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + stbi_uc *out; + STBI_NOTUSED(ri); - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) - return 0; + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; + *x = s->img_x; + *y = s->img_y; + if (comp) + *comp = s->img_n; - if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "PNM too large"); + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + out = (stbi_uc *)stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + if (!out) + return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); - if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - return out; + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) + return out; // stbi__convert_format frees input on failure + } + return out; } -static int stbi__pnm_isspace(char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +static int stbi__pnm_isspace(char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; } -static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) -{ - for (;;) { - while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) - *c = (char) stbi__get8(s); +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) { + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char)stbi__get8(s); - if (stbi__at_eof(s) || *c != '#') - break; + if (stbi__at_eof(s) || *c != '#') + break; - while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) - *c = (char) stbi__get8(s); - } + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r') + *c = (char)stbi__get8(s); + } } -static int stbi__pnm_isdigit(char c) -{ - return c >= '0' && c <= '9'; -} +static int stbi__pnm_isdigit(char c) { return c >= '0' && c <= '9'; } -static int stbi__pnm_getinteger(stbi__context *s, char *c) -{ - int value = 0; +static int stbi__pnm_getinteger(stbi__context *s, char *c) { + int value = 0; - while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { - value = value*10 + (*c - '0'); - *c = (char) stbi__get8(s); - } + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value * 10 + (*c - '0'); + *c = (char)stbi__get8(s); + } - return value; + return value; } -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) -{ - int maxv, dummy; - char c, p, t; +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) { + int maxv, dummy; + char c, p, t; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; - stbi__rewind(s); + stbi__rewind(s); - // Get identifier - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind(s); - return 0; - } + // Get identifier + p = (char)stbi__get8(s); + t = (char)stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } - *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - c = (char) stbi__get8(s); - stbi__pnm_skip_whitespace(s, &c); + c = (char)stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); - *x = stbi__pnm_getinteger(s, &c); // read width - stbi__pnm_skip_whitespace(s, &c); + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); - *y = stbi__pnm_getinteger(s, &c); // read height - stbi__pnm_skip_whitespace(s, &c); + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); - maxv = stbi__pnm_getinteger(s, &c); // read max value + maxv = stbi__pnm_getinteger(s, &c); // read max value - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); - else - return 1; + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; } #endif -static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_info(s, x, y, comp)) return 1; - #endif +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) { +#ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PNG - if (stbi__png_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_GIF - if (stbi__gif_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_BMP - if (stbi__bmp_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PSD - if (stbi__psd_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PIC - if (stbi__pic_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PNM - if (stbi__pnm_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_HDR - if (stbi__hdr_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) + return 1; +#endif - // test tga last because it's a crappy test! - #ifndef STBI_NO_TGA - if (stbi__tga_info(s, x, y, comp)) - return 1; - #endif - return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +// test tga last because it's a crappy test! +#ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; +#endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); } -static int stbi__is_16_main(stbi__context *s) -{ - #ifndef STBI_NO_PNG - if (stbi__png_is16(s)) return 1; - #endif +static int stbi__is_16_main(stbi__context *s) { +#ifndef STBI_NO_PNG + if (stbi__png_is16(s)) + return 1; +#endif - #ifndef STBI_NO_PSD - if (stbi__psd_is16(s)) return 1; - #endif +#ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) + return 1; +#endif - return 0; + return 0; } #ifndef STBI_NO_STDIO -STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_info_from_file(f, x, y, comp); - fclose(f); - return result; -} - -STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); - return r; -} - -STBIDEF int stbi_is_16_bit(char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_is_16_bit_from_file(f); - fclose(f); - return result; -} - -STBIDEF int stbi_is_16_bit_from_file(FILE *f) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__is_16_main(&s); - fseek(f,pos,SEEK_SET); - return r; +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) { + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) + return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) { + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s, x, y, comp); + fseek(f, pos, SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) { + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) + return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) { + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f, pos, SEEK_SET); + return r; } #endif // !STBI_NO_STDIO -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__info_main(&s,x,y,comp); +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__info_main(&s, x, y, comp); } -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__info_main(&s,x,y,comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)c, user); + return stbi__info_main(&s, x, y, comp); } -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__is_16_main(&s); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__is_16_main(&s); } -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__is_16_main(&s); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)c, user); + return stbi__is_16_main(&s); } #endif // STB_IMAGE_IMPLEMENTATION /* revision history: - 2.19 (2018-02-11) fix warning - 2.18 (2018-01-30) fix warnings - 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug - 1-bit BMP - *_is_16_bit api - avoid warnings - 2.16 (2017-07-23) all functions have 16-bit variants; - STBI_NO_STDIO works again; - compilation fixes; - fix rounding in unpremultiply; - optimize vertical flip; - disable raw_len validation; - documentation fixes - 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; - warning fixes; disable run-time SSE detection on gcc; - uniform handling of optional "return" values; - thread-safe initialization of zlib tables - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) allocate large structures on the stack - remove white matting for transparent PSD - fix reported channel count for PNG & BMP - re-enable SSE2 in non-gcc 64-bit - support RGB-formatted JPEG - read 16-bit PNGs (only as 8-bit) - 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED - 2.09 (2016-01-16) allow comments in PNM files - 16-bit-per-pixel TGA (not bit-per-component) - info() for TGA could break due to .hdr handling - info() for BMP to shares code instead of sloppy parse - can use STBI_REALLOC_SIZED if allocator doesn't support realloc - code cleanup - 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA - 2.07 (2015-09-13) fix compiler warnings - partial animated GIF support - limited 16-bpc PSD support - #ifdef unused functions - bug with < 92 byte PIC,PNM,HDR,TGA - 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value - 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning - 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit - 2.03 (2015-04-12) extra corruption checking (mmozeiko) - stbi_set_flip_vertically_on_load (nguillemot) - fix NEON support; fix mingw support - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) - progressive JPEG (stb) - PGM/PPM support (Ken Miller) - STBI_MALLOC,STBI_REALLOC,STBI_FREE - GIF bugfix -- seemingly never worked - STBI_NO_*, STBI_ONLY_* - 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) - optimize PNG (ryg) - fix bug in interlaced PNG with user-specified channel count (stb) - 1.46 (2014-08-26) - fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG - 1.45 (2014-08-16) - fix MSVC-ARM internal compiler error by wrapping malloc - 1.44 (2014-08-07) - various warning fixes from Ronny Chevalier - 1.43 (2014-07-15) - fix MSVC-only compiler problem in code changed in 1.42 - 1.42 (2014-07-09) - don't define _CRT_SECURE_NO_WARNINGS (affects user code) - fixes to stbi__cleanup_jpeg path - added STBI_ASSERT to avoid requiring assert.h - 1.41 (2014-06-25) - fix search&replace from 1.36 that messed up comments/error messages - 1.40 (2014-06-22) - fix gcc struct-initialization warning - 1.39 (2014-06-15) - fix to TGA optimization when req_comp != number of components in TGA; - fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) - add support for BMP version 5 (more ignored fields) - 1.38 (2014-06-06) - suppress MSVC warnings on integer casts truncating values - fix accidental rename of 'skip' field of I/O - 1.37 (2014-06-04) - remove duplicate typedef - 1.36 (2014-06-03) - convert to header file single-file library - if de-iphone isn't set, load iphone images color-swapped instead of returning NULL - 1.35 (2014-05-27) - various warnings - fix broken STBI_SIMD path - fix bug where stbi_load_from_file no longer left file pointer in correct place - fix broken non-easy path for 32-bit BMP (possibly never used) - TGA optimization by Arseny Kapoulkine - 1.34 (unknown) - use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case - 1.33 (2011-07-14) - make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements - 1.32 (2011-07-13) - support for "info" function for all supported filetypes (SpartanJ) - 1.31 (2011-06-20) - a few more leak fixes, bug in PNG handling (SpartanJ) - 1.30 (2011-06-11) - added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) - removed deprecated format-specific test/load functions - removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway - error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) - fix inefficiency in decoding 32-bit BMP (David Woo) - 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville - 1.28 (2010-08-01) - fix bug in GIF palette transparency (SpartanJ) - 1.27 (2010-08-01) - cast-to-stbi_uc to fix warnings - 1.26 (2010-07-24) - fix bug in file buffering for PNG reported by SpartanJ - 1.25 (2010-07-17) - refix trans_data warning (Won Chun) - 1.24 (2010-07-12) - perf improvements reading from files on platforms with lock-heavy fgetc() - minor perf improvements for jpeg - deprecated type-specific functions so we'll get feedback if they're needed - attempt to fix trans_data warning (Won Chun) - 1.23 fixed bug in iPhone support - 1.22 (2010-07-10) - removed image *writing* support - stbi_info support from Jetro Lauha - GIF support from Jean-Marc Lienher - iPhone PNG-extensions from James Brown - warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) - 1.21 fix use of 'stbi_uc' in header (reported by jon blow) - 1.20 added support for Softimage PIC, by Tom Seddon - 1.19 bug in interlaced PNG corruption check (found by ryg) - 1.18 (2008-08-02) - fix a threading bug (local mutable static) - 1.17 support interlaced PNG - 1.16 major bugfix - stbi__convert_format converted one too many pixels - 1.15 initialize some fields for thread safety - 1.14 fix threadsafe conversion bug - header-file-only version (#define STBI_HEADER_FILE_ONLY before including) - 1.13 threadsafe - 1.12 const qualifiers in the API - 1.11 Support installable IDCT, colorspace conversion routines - 1.10 Fixes for 64-bit (don't use "unsigned long") - optimized upsampling by Fabian "ryg" Giesen - 1.09 Fix format-conversion for PSD code (bad global variables!) - 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz - 1.07 attempt to fix C++ warning/errors again - 1.06 attempt to fix C++ warning/errors again - 1.05 fix TGA loading to return correct *comp and use good luminance calc - 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free - 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR - 1.02 support for (subset of) HDR files, float interface for preferred access to them - 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all - 1.00 interface to zlib that skips zlib header - 0.99 correct handling of alpha in palette - 0.98 TGA loader by lonesock; dynamically add loaders (untested) - 0.97 jpeg errors on too large a file; also catch another malloc failure - 0.96 fix detection of invalid v value - particleman@mollyrocket forum - 0.95 during header scan, seek to markers in case of padding - 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same - 0.93 handle jpegtran output; verbose errors - 0.92 read 4,8,16,24,32-bit BMP files of several formats - 0.91 output 24-bit Windows 3.0 BMP files - 0.90 fix a few more warnings; bump version number to approach 1.0 - 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd - 0.60 fix compiling as c++ - 0.59 fix warnings: merge Dave Moore's -Wall fixes - 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian - 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available - 0.56 fix bug: zlib uncompressed mode len vs. nlen - 0.55 fix bug: restart_interval not initialized to 0 - 0.54 allow NULL for 'int *comp' - 0.53 fix bug in png 3->4; speedup png decoding - 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments - 0.51 obey req_comp requests, 1-component jpegs return as 1-component, - on 'test' only check type, not whether we support this variant - 0.50 (2006-11-19) - first released version + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks + anyway error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) fix inefficiency in + decoding 32-bit BMP (David Woo) 1.29 (2010-08-16) various warning fixes from Aurelien Pocheville 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version */ - /* ------------------------------------------------------------------------------ This software is available under 2 licenses -- choose whichever you prefer. diff --git a/src/stb_image_write.h b/src/stb_image_write.h index 082eb69..c61ec30 100644 --- a/src/stb_image_write.h +++ b/src/stb_image_write.h @@ -55,11 +55,11 @@ USAGE: There are also five equivalent functions that use an arbitrary write function. You are expected to open/close your file-equivalent before and after calling these: - int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); - int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); - int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); - int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); - int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int +stride_in_bytes); int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void +*data); int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); int +stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); int +stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); where the callback is: void stbi_write_func(void *context, void *data, int size); @@ -105,7 +105,7 @@ USAGE: TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed data, set the global variable 'stbi_write_tga_with_rle' to 0. - + JPEG does ignore alpha channels in input data; quality is between 1 and 100. Higher quality looks better but results in a bigger image. JPEG baseline (no JPEG progressive). @@ -113,7 +113,7 @@ USAGE: CREDITS: - Sean Barrett - PNG/BMP/TGA + Sean Barrett - PNG/BMP/TGA Baldur Karlsson - HDR Jean-Sebastien Guay - TGA monochrome Tim Kelsey - misc enhancements @@ -155,55 +155,57 @@ LICENSE // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' #ifndef STBIWDEF #ifdef STB_IMAGE_WRITE_STATIC -#define STBIWDEF static +#define STBIWDEF static #else #ifdef __cplusplus -#define STBIWDEF extern "C" +#define STBIWDEF extern "C" #else -#define STBIWDEF extern +#define STBIWDEF extern #endif #endif #endif -#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations extern int stbi_write_tga_with_rle; extern int stbi_write_png_compression_level; extern int stbi_write_force_png_filter; #endif #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); -STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); -STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); #ifdef STBI_WINDOWS_UTF8 -STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t *input); #endif #endif typedef void stbi_write_func(void *context, void *data, int size); -STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); -STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, + int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); -STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, + int quality); STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); -#endif//INCLUDE_STB_IMAGE_WRITE_H +#endif // INCLUDE_STB_IMAGE_WRITE_H #ifdef STB_IMAGE_WRITE_IMPLEMENTATION #ifdef _WIN32 - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif - #ifndef _CRT_NONSTDC_NO_DEPRECATE - #define _CRT_NONSTDC_NO_DEPRECATE - #endif +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#endif #endif #ifndef STBI_WRITE_NO_STDIO @@ -225,63 +227,53 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); #ifndef STBIW_MALLOC #define STBIW_MALLOC(sz) malloc(sz) -#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_REALLOC(p, newsz) realloc(p, newsz) #define STBIW_FREE(p) free(p) #endif #ifndef STBIW_REALLOC_SIZED -#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#define STBIW_REALLOC_SIZED(p, oldsz, newsz) STBIW_REALLOC(p, newsz) #endif - #ifndef STBIW_MEMMOVE -#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#define STBIW_MEMMOVE(a, b, sz) memmove(a, b, sz) #endif - #ifndef STBIW_ASSERT #include #define STBIW_ASSERT(x) assert(x) #endif -#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) +#define STBIW_UCHAR(x) (unsigned char)((x)&0xff) #ifdef STB_IMAGE_WRITE_STATIC -static int stbi__flip_vertically_on_write=0; +static int stbi__flip_vertically_on_write = 0; static int stbi_write_png_compression_level = 8; -static int stbi_write_tga_with_rle = 1; -static int stbi_write_force_png_filter = -1; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; #else int stbi_write_png_compression_level = 8; -int stbi__flip_vertically_on_write=0; -int stbi_write_tga_with_rle = 1; -int stbi_write_force_png_filter = -1; +int stbi__flip_vertically_on_write = 0; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; #endif -STBIWDEF void stbi_flip_vertically_on_write(int flag) -{ - stbi__flip_vertically_on_write = flag; -} +STBIWDEF void stbi_flip_vertically_on_write(int flag) { stbi__flip_vertically_on_write = flag; } -typedef struct -{ - stbi_write_func *func; - void *context; +typedef struct { + stbi_write_func *func; + void *context; } stbi__write_context; // initialize a callback-based context -static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) -{ - s->func = c; - s->context = context; +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) { + s->func = c; + s->context = context; } #ifndef STBI_WRITE_NO_STDIO -static void stbi__stdio_write(void *context, void *data, int size) -{ - fwrite(data,1,size,(FILE*) context); -} +static void stbi__stdio_write(void *context, void *data, int size) { fwrite(data, 1, size, (FILE *)context); } #if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) #ifdef __cplusplus @@ -289,306 +281,305 @@ static void stbi__stdio_write(void *context, void *data, int size) #else #define STBIW_EXTERN extern #endif -STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); -STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); - -STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) -{ - return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, + const char *str, int cbmb, wchar_t *widestr, + int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, + const wchar_t *widestr, int cchwide, char *str, + int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t *input) { + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int)bufferlen, NULL, NULL); } #endif -static FILE *stbiw__fopen(char const *filename, char const *mode) -{ - FILE *f; +static FILE *stbiw__fopen(char const *filename, char const *mode) { + FILE *f; #if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) - wchar_t wMode[64]; - wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) - return 0; - - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) - return 0; + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; #if _MSC_VER >= 1400 - if (0 != _wfopen_s(&f, wFilename, wMode)) - f = 0; + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; #else - f = _wfopen(wFilename, wMode); + f = _wfopen(wFilename, wMode); #endif #elif defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; + if (0 != fopen_s(&f, filename, mode)) + f = 0; #else - f = fopen(filename, mode); + f = fopen(filename, mode); #endif - return f; + return f; } -static int stbi__start_write_file(stbi__write_context *s, const char *filename) -{ - FILE *f = stbiw__fopen(filename, "wb"); - stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); - return f != NULL; +static int stbi__start_write_file(stbi__write_context *s, const char *filename) { + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *)f); + return f != NULL; } -static void stbi__end_write_file(stbi__write_context *s) -{ - fclose((FILE *)s->context); -} +static void stbi__end_write_file(stbi__write_context *s) { fclose((FILE *)s->context); } #endif // !STBI_WRITE_NO_STDIO typedef unsigned int stbiw_uint32; -typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; - -static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) -{ - while (*fmt) { - switch (*fmt++) { - case ' ': break; - case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); - s->func(s->context,&x,1); - break; } - case '2': { int x = va_arg(v,int); - unsigned char b[2]; - b[0] = STBIW_UCHAR(x); - b[1] = STBIW_UCHAR(x>>8); - s->func(s->context,b,2); - break; } - case '4': { stbiw_uint32 x = va_arg(v,int); - unsigned char b[4]; - b[0]=STBIW_UCHAR(x); - b[1]=STBIW_UCHAR(x>>8); - b[2]=STBIW_UCHAR(x>>16); - b[3]=STBIW_UCHAR(x>>24); - s->func(s->context,b,4); - break; } - default: +typedef int stb_image_write_test[sizeof(stbiw_uint32) == 4 ? 1 : -1]; + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) { + while (*fmt) { + switch (*fmt++) { + case ' ': + break; + case '1': { + unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context, &x, 1); + break; + } + case '2': { + int x = va_arg(v, int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x >> 8); + s->func(s->context, b, 2); + break; + } + case '4': { + stbiw_uint32 x = va_arg(v, int); + unsigned char b[4]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x >> 8); + b[2] = STBIW_UCHAR(x >> 16); + b[3] = STBIW_UCHAR(x >> 24); + s->func(s->context, b, 4); + break; + } + default: STBIW_ASSERT(0); return; - } - } + } + } } -static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) -{ - va_list v; - va_start(v, fmt); - stbiw__writefv(s, fmt, v); - va_end(v); +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); } -static void stbiw__putc(stbi__write_context *s, unsigned char c) -{ - s->func(s->context, &c, 1); -} +static void stbiw__putc(stbi__write_context *s, unsigned char c) { s->func(s->context, &c, 1); } -static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) -{ - unsigned char arr[3]; - arr[0] = a; arr[1] = b; arr[2] = c; - s->func(s->context, arr, 3); +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) { + unsigned char arr[3]; + arr[0] = a; + arr[1] = b; + arr[2] = c; + s->func(s->context, arr, 3); } -static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) -{ - unsigned char bg[3] = { 255, 0, 255}, px[3]; - int k; +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, + unsigned char *d) { + unsigned char bg[3] = {255, 0, 255}, px[3]; + int k; - if (write_alpha < 0) - s->func(s->context, &d[comp - 1], 1); + if (write_alpha < 0) + s->func(s->context, &d[comp - 1], 1); - switch (comp) { - case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case - case 1: - if (expand_mono) + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp - else - s->func(s->context, d, 1); // monochrome TGA - break; - case 4: - if (!write_alpha) { + else + s->func(s->context, d, 1); // monochrome TGA + break; + case 4: + if (!write_alpha) { // composite against pink background for (k = 0; k < 3; ++k) - px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); break; - } - /* FALLTHROUGH */ - case 3: - stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); - break; - } - if (write_alpha > 0) - s->func(s->context, &d[comp - 1], 1); + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + s->func(s->context, &d[comp - 1], 1); } -static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) -{ - stbiw_uint32 zero = 0; - int i,j, j_end; - - if (y <= 0) - return; - - if (stbi__flip_vertically_on_write) - vdir *= -1; - - if (vdir < 0) { - j_end = -1; j = y-1; - } else { - j_end = y; j = 0; - } - - for (; j != j_end; j += vdir) { - for (i=0; i < x; ++i) { - unsigned char *d = (unsigned char *) data + (j*x+i)*comp; - stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); - } - s->func(s->context, &zero, scanline_pad); - } +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, + int write_alpha, int scanline_pad, int expand_mono) { + stbiw_uint32 zero = 0; + int i, j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) { + j_end = -1; + j = y - 1; + } else { + j_end = y; + j = 0; + } + + for (; j != j_end; j += vdir) { + for (i = 0; i < x; ++i) { + unsigned char *d = (unsigned char *)data + (j * x + i) * comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + s->func(s->context, &zero, scanline_pad); + } } -static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) -{ - if (y < 0 || x < 0) { - return 0; - } else { - va_list v; - va_start(v, fmt); - stbiw__writefv(s, fmt, v); - va_end(v); - stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); - return 1; - } +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, + void *data, int alpha, int pad, const char *fmt, ...) { + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s, rgb_dir, vdir, x, y, comp, data, alpha, pad, expand_mono); + return 1; + } } -static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) -{ - int pad = (-x*3) & 3; - return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, - "11 4 22 4" "4 44 22 444444", - 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header - 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) { + int pad = (-x * 3) & 3; + return stbiw__outfile(s, -1, -1, x, y, comp, 1, (void *)data, 0, pad, + "11 4 22 4" + "4 44 22 444444", + 'B', 'M', 14 + 40 + (x * 3 + pad) * y, 0, 0, 14 + 40, // file header + 40, x, y, 1, 24, 0, 0, 0, 0, 0, 0); // bitmap header } -STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_bmp_core(&s, x, y, comp, data); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_bmp_core(&s, x, y, comp, data); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) { + stbi__write_context s; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; } -#endif //!STBI_WRITE_NO_STDIO - -static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) -{ - int has_alpha = (comp == 2 || comp == 4); - int colorbytes = has_alpha ? comp-1 : comp; - int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 - - if (y < 0 || x < 0) - return 0; - - if (!stbi_write_tga_with_rle) { - return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, - "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); - } else { - int i,j,k; - int jend, jdir; - - stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); - - if (stbi__flip_vertically_on_write) { - j = 0; - jend = y; - jdir = 1; - } else { - j = y-1; - jend = -1; - jdir = -1; - } - for (; j != jend; j += jdir) { - unsigned char *row = (unsigned char *) data + j * x * comp; - int len; - - for (i = 0; i < x; i += len) { - unsigned char *begin = row + i * comp; - int diff = 1; - len = 1; - - if (i < x - 1) { - ++len; - diff = memcmp(begin, row + (i + 1) * comp, comp); - if (diff) { - const unsigned char *prev = begin; - for (k = i + 2; k < x && len < 128; ++k) { - if (memcmp(prev, row + k * comp, comp)) { - prev += comp; - ++len; - } else { - --len; - break; - } - } - } else { - for (k = i + 2; k < x && len < 128; ++k) { - if (!memcmp(begin, row + k * comp, comp)) { - ++len; - } else { - break; - } - } - } - } - - if (diff) { - unsigned char header = STBIW_UCHAR(len - 1); - s->func(s->context, &header, 1); - for (k = 0; k < len; ++k) { - stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); - } - } else { - unsigned char header = STBIW_UCHAR(len - 129); - s->func(s->context, &header, 1); - stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); +#endif //! STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) { + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp - 1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *)data, has_alpha, 0, "111 221 2222 11", 0, 0, format, 0, + 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i, j, k; + int jend, jdir; + + stbiw__writef(s, "111 221 2222 11", 0, 0, format + 8, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, + has_alpha * 8); + + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y - 1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *)data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + s->func(s->context, &header, 1); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + s->func(s->context, &header, 1); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } } - } - } - } - return 1; + } + } + return 1; } -STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_tga_core(&s, x, y, comp, (void *) data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *)data); } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) { + stbi__write_context s; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *)data); + stbi__end_write_file(&s); + return r; + } else + return 0; } #endif @@ -596,177 +587,175 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const // Radiance RGBE HDR writer // by Baldur Karlsson -#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) -static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) -{ - int exponent; - float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) { + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); - if (maxcomp < 1e-32f) { - rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; - } else { - float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float)frexp(maxcomp, &exponent) * 256.0f / maxcomp; - rgbe[0] = (unsigned char)(linear[0] * normalize); - rgbe[1] = (unsigned char)(linear[1] * normalize); - rgbe[2] = (unsigned char)(linear[2] * normalize); - rgbe[3] = (unsigned char)(exponent + 128); - } + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } } -static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) -{ - unsigned char lengthbyte = STBIW_UCHAR(length+128); - STBIW_ASSERT(length+128 <= 255); - s->func(s->context, &lengthbyte, 1); - s->func(s->context, &databyte, 1); +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) { + unsigned char lengthbyte = STBIW_UCHAR(length + 128); + STBIW_ASSERT(length + 128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); } -static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) -{ - unsigned char lengthbyte = STBIW_UCHAR(length); - STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code - s->func(s->context, &lengthbyte, 1); - s->func(s->context, data, length); +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) { + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); } -static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) -{ - unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; - unsigned char rgbe[4]; - float linear[3]; - int x; +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, + float *scanline) { + unsigned char scanlineheader[4] = {2, 2, 0, 0}; + unsigned char rgbe[4]; + float linear[3]; + int x; - scanlineheader[2] = (width&0xff00)>>8; - scanlineheader[3] = (width&0x00ff); + scanlineheader[2] = (width & 0xff00) >> 8; + scanlineheader[3] = (width & 0x00ff); - /* skip RLE for images too small or large */ - if (width < 8 || width >= 32768) { - for (x=0; x < width; x++) { - switch (ncomp) { + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x = 0; x < width; x++) { + switch (ncomp) { case 4: /* fallthrough */ - case 3: linear[2] = scanline[x*ncomp + 2]; - linear[1] = scanline[x*ncomp + 1]; - linear[0] = scanline[x*ncomp + 0]; - break; + case 3: + linear[2] = scanline[x * ncomp + 2]; + linear[1] = scanline[x * ncomp + 1]; + linear[0] = scanline[x * ncomp + 0]; + break; default: - linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; - break; - } - stbiw__linear_to_rgbe(rgbe, linear); - s->func(s->context, rgbe, 4); - } - } else { - int c,r; - /* encode into scratch buffer */ - for (x=0; x < width; x++) { - switch(ncomp) { + linear[0] = linear[1] = linear[2] = scanline[x * ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c, r; + /* encode into scratch buffer */ + for (x = 0; x < width; x++) { + switch (ncomp) { case 4: /* fallthrough */ - case 3: linear[2] = scanline[x*ncomp + 2]; - linear[1] = scanline[x*ncomp + 1]; - linear[0] = scanline[x*ncomp + 0]; - break; + case 3: + linear[2] = scanline[x * ncomp + 2]; + linear[1] = scanline[x * ncomp + 1]; + linear[0] = scanline[x * ncomp + 0]; + break; default: - linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; - break; - } - stbiw__linear_to_rgbe(rgbe, linear); - scratch[x + width*0] = rgbe[0]; - scratch[x + width*1] = rgbe[1]; - scratch[x + width*2] = rgbe[2]; - scratch[x + width*3] = rgbe[3]; - } - - s->func(s->context, scanlineheader, 4); - - /* RLE each component separately */ - for (c=0; c < 4; c++) { - unsigned char *comp = &scratch[width*c]; - - x = 0; - while (x < width) { - // find first run - r = x; - while (r+2 < width) { - if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) - break; - ++r; - } - if (r+2 >= width) - r = width; - // dump up to first run - while (x < r) { - int len = r-x; - if (len > 128) len = 128; - stbiw__write_dump_data(s, len, &comp[x]); - x += len; + linear[0] = linear[1] = linear[2] = scanline[x * ncomp + 0]; + break; } - // if there's a run, output it - if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd - // find next byte after run - while (r < width && comp[r] == comp[x]) - ++r; - // output run up to r - while (x < r) { - int len = r-x; - if (len > 127) len = 127; - stbiw__write_run_data(s, len, comp[x]); - x += len; - } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width * 0] = rgbe[0]; + scratch[x + width * 1] = rgbe[1]; + scratch[x + width * 2] = rgbe[2]; + scratch[x + width * 3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c = 0; c < 4; c++) { + unsigned char *comp = &scratch[width * c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r + 2 < width) { + if (comp[r] == comp[r + 1] && comp[r] == comp[r + 2]) + break; + ++r; + } + if (r + 2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r - x; + if (len > 128) + len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r + 2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r - x; + if (len > 127) + len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } } - } - } - } + } + } } -static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) -{ - if (y <= 0 || x <= 0 || data == NULL) - return 0; - else { - // Each component is stored separately. Allocate scratch space for full output scanline. - unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); - int i, len; - char buffer[128]; - char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; - s->func(s->context, header, sizeof(header)-1); +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) { + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *)STBIW_MALLOC(x * 4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header) - 1); #ifdef __STDC_WANT_SECURE_LIB__ - len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else - len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #endif - s->func(s->context, buffer, len); - - for(i=0; i < y; i++) - stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); - STBIW_FREE(scratch); - return 1; - } + s->func(s->context, buffer, len); + + for (i = 0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, + data + comp * x * (stbi__flip_vertically_on_write ? y - 1 - i : i)); + STBIW_FREE(scratch); + return 1; + } } -STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) { + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *)data); } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) { + stbi__write_context s; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *)data); + stbi__end_write_file(&s); + return r; + } else + return 0; } #endif // STBI_WRITE_NO_STDIO - ////////////////////////////////////////////////////////////////////////////// // // PNG writer @@ -774,417 +763,472 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const #ifndef STBIW_ZLIB_COMPRESS // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() -#define stbiw__sbraw(a) ((int *) (a) - 2) -#define stbiw__sbm(a) stbiw__sbraw(a)[0] -#define stbiw__sbn(a) stbiw__sbraw(a)[1] +#define stbiw__sbraw(a) ((int *)(a)-2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] -#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) -#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) -#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) +#define stbiw__sbneedgrow(a, n) ((a) == 0 || stbiw__sbn(a) + n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a, n) (stbiw__sbneedgrow(a, (n)) ? stbiw__sbgrow(a, n) : 0) +#define stbiw__sbgrow(a, n) stbiw__sbgrowf((void **)&(a), (n), sizeof(*(a))) -#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a, 1), (a)[stbiw__sbn(a)++] = (v)) #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) -#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) - -static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) -{ - int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; - void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); - STBIW_ASSERT(p); - if (p) { - if (!*arr) ((int *) p)[1] = 0; - *arr = (void *) ((int *) p + 2); - stbiw__sbm(*arr) = m; - } - return *arr; +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)), 0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) { + int m = *arr ? 2 * stbiw__sbm(*arr) + increment : increment + 1; + void *p = + STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr) * itemsize + sizeof(int) * 2) : 0, + itemsize * m + sizeof(int) * 2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) + ((int *)p)[1] = 0; + *arr = (void *)((int *)p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; } -static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) -{ - while (*bitcount >= 8) { - stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); - *bitbuffer >>= 8; - *bitcount -= 8; - } - return data; +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) { + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; } -static int stbiw__zlib_bitrev(int code, int codebits) -{ - int res=0; - while (codebits--) { - res = (res << 1) | (code & 1); - code >>= 1; - } - return res; +static int stbiw__zlib_bitrev(int code, int codebits) { + int res = 0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; } -static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) -{ - int i; - for (i=0; i < limit && i < 258; ++i) - if (a[i] != b[i]) break; - return i; +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) { + int i; + for (i = 0; i < limit && i < 258; ++i) + if (a[i] != b[i]) + break; + return i; } -static unsigned int stbiw__zhash(unsigned char *data) -{ - stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - return hash; +static unsigned int stbiw__zhash(unsigned char *data) { + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; } -#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) -#define stbiw__zlib_add(code,codebits) \ - (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) -#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code, codebits) (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b, c) stbiw__zlib_add(stbiw__zlib_bitrev(b, c), c) // default huffman tables -#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) -#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) -#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) -#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) -#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256, 7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280, 8) +#define stbiw__zlib_huff(n) \ + ((n) <= 143 ? stbiw__zlib_huff1(n) \ + : (n) <= 255 ? stbiw__zlib_huff2(n) \ + : (n) <= 279 ? stbiw__zlib_huff3(n) \ + : stbiw__zlib_huff4(n)) #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) -#define stbiw__ZHASH 16384 +#define stbiw__ZHASH 16384 #endif // STBIW_ZLIB_COMPRESS -STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) -{ +STBIWDEF unsigned char *stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { #ifdef STBIW_ZLIB_COMPRESS - // user provided a zlib compress implementation, use that - return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); -#else // use builtin - static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; - static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; - static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; - static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; - unsigned int bitbuf=0; - int i,j, bitcount=0; - unsigned char *out = NULL; - unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); - if (hash_table == NULL) - return NULL; - if (quality < 5) quality = 5; - - stbiw__sbpush(out, 0x78); // DEFLATE 32K window - stbiw__sbpush(out, 0x5e); // FLEVEL = 1 - stbiw__zlib_add(1,1); // BFINAL = 1 - stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman - - for (i=0; i < stbiw__ZHASH; ++i) - hash_table[i] = NULL; - - i=0; - while (i < data_len-3) { - // hash next 3 bytes of data to be compressed - int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; - unsigned char *bestloc = 0; - unsigned char **hlist = hash_table[h]; - int n = stbiw__sbcount(hlist); - for (j=0; j < n; ++j) { - if (hlist[j]-data > i-32768) { // if entry lies within window - int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); - if (d >= best) { best=d; bestloc=hlist[j]; } - } - } - // when hash table entry is too long, delete half the entries - if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { - STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); - stbiw__sbn(hash_table[h]) = quality; - } - stbiw__sbpush(hash_table[h],data+i); - - if (bestloc) { - // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal - h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); - hlist = hash_table[h]; - n = stbiw__sbcount(hlist); - for (j=0; j < n; ++j) { - if (hlist[j]-data > i-32767) { - int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); - if (e > best) { // if next match is better, bail on current match - bestloc = NULL; - break; - } + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, + 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 259}; + static unsigned char lengtheb[] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, + 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static unsigned short distc[] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32768}; + static unsigned char disteb[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + unsigned int bitbuf = 0; + int i, j, bitcount = 0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char ***)STBIW_MALLOC(stbiw__ZHASH * sizeof(char **)); + if (hash_table == NULL) + return NULL; + if (quality < 5) + quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1, 1); // BFINAL = 1 + stbiw__zlib_add(1, 2); // BTYPE = 1 -- fixed huffman + + for (i = 0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i = 0; + while (i < data_len - 3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data + i) & (stbiw__ZHASH - 1), best = 3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j = 0; j < n; ++j) { + if (hlist[j] - data > i - 32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data + i, data_len - i); + if (d >= best) { + best = d; + bestloc = hlist[j]; + } + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2 * quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h] + quality, sizeof(hash_table[h][0]) * quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h], data + i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data + i + 1) & (stbiw__ZHASH - 1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j = 0; j < n; ++j) { + if (hlist[j] - data > i - 32767) { + int e = stbiw__zlib_countm(hlist[j], data + i + 1, data_len - i - 1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int)(data + i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j = 0; best > lengthc[j + 1] - 1; ++j) + ; + stbiw__zlib_huff(j + 257); + if (lengtheb[j]) + stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j = 0; d > distc[j + 1] - 1; ++j) + ; + stbiw__zlib_add(stbiw__zlib_bitrev(j, 5), 5); + if (disteb[j]) + stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (; i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0, 1); + + for (i = 0; i < stbiw__ZHASH; ++i) + (void)stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + { + // compute adler32 on input + unsigned int s1 = 1, s2 = 0; + int blocklen = (int)(data_len % 5552); + j = 0; + while (j < data_len) { + for (i = 0; i < blocklen; ++i) { + s1 += data[j + i]; + s2 += s1; } - } - } - - if (bestloc) { - int d = (int) (data+i - bestloc); // distance back - STBIW_ASSERT(d <= 32767 && best <= 258); - for (j=0; best > lengthc[j+1]-1; ++j); - stbiw__zlib_huff(j+257); - if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); - for (j=0; d > distc[j+1]-1; ++j); - stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); - if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); - i += best; - } else { - stbiw__zlib_huffb(data[i]); - ++i; - } - } - // write out final bytes - for (;i < data_len; ++i) - stbiw__zlib_huffb(data[i]); - stbiw__zlib_huff(256); // end of block - // pad with 0 bits to byte boundary - while (bitcount) - stbiw__zlib_add(0,1); - - for (i=0; i < stbiw__ZHASH; ++i) - (void) stbiw__sbfree(hash_table[i]); - STBIW_FREE(hash_table); - - { - // compute adler32 on input - unsigned int s1=1, s2=0; - int blocklen = (int) (data_len % 5552); - j=0; - while (j < data_len) { - for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } - s1 %= 65521; s2 %= 65521; - j += blocklen; - blocklen = 5552; - } - stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s2)); - stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s1)); - } - *out_len = stbiw__sbn(out); - // make returned pointer freeable - STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); - return (unsigned char *) stbiw__sbraw(out); + s1 %= 65521; + s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *)stbiw__sbraw(out); #endif // STBIW_ZLIB_COMPRESS } -static unsigned int stbiw__crc32(unsigned char *buffer, int len) -{ +static unsigned int stbiw__crc32(unsigned char *buffer, int len) { #ifdef STBIW_CRC32 return STBIW_CRC32(buffer, len); #else - static unsigned int crc_table[256] = - { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - }; - - unsigned int crc = ~0u; - int i; - for (i=0; i < len; ++i) - crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; - return ~crc; + static unsigned int crc_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0eDB8832, + 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, + 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, + 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, + 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, + 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, + 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, + 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, + 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, + 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, + 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, + 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, + 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, + 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, + 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D}; + + unsigned int crc = ~0u; + int i; + for (i = 0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; #endif } -#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) -#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); -#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) +#define stbiw__wpng4(o, a, b, c, d) \ + ((o)[0] = STBIW_UCHAR(a), (o)[1] = STBIW_UCHAR(b), (o)[2] = STBIW_UCHAR(c), (o)[3] = STBIW_UCHAR(d), (o) += 4) +#define stbiw__wp32(data, v) stbiw__wpng4(data, (v) >> 24, (v) >> 16, (v) >> 8, (v)); +#define stbiw__wptag(data, s) stbiw__wpng4(data, s[0], s[1], s[2], s[3]) -static void stbiw__wpcrc(unsigned char **data, int len) -{ - unsigned int crc = stbiw__crc32(*data - len - 4, len+4); - stbiw__wp32(*data, crc); +static void stbiw__wpcrc(unsigned char **data, int len) { + unsigned int crc = stbiw__crc32(*data - len - 4, len + 4); + stbiw__wp32(*data, crc); } -static unsigned char stbiw__paeth(int a, int b, int c) -{ - int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); - if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); - if (pb <= pc) return STBIW_UCHAR(b); - return STBIW_UCHAR(c); +static unsigned char stbiw__paeth(int a, int b, int c) { + int p = a + b - c, pa = abs(p - a), pb = abs(p - b), pc = abs(p - c); + if (pa <= pb && pa <= pc) + return STBIW_UCHAR(a); + if (pb <= pc) + return STBIW_UCHAR(b); + return STBIW_UCHAR(c); } // @OPTIMIZE: provide an option that always forces left-predict or paeth predict -static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) -{ - static int mapping[] = { 0,1,2,3,4 }; - static int firstmap[] = { 0,1,0,5,6 }; - int *mymap = (y != 0) ? mapping : firstmap; - int i; - int type = mymap[filter_type]; - unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); - int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; - - if (type==0) { - memcpy(line_buffer, z, width*n); - return; - } - - // first loop isn't optimized since it's just one pixel - for (i = 0; i < n; ++i) { - switch (type) { - case 1: line_buffer[i] = z[i]; break; - case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; - case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; - case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; - case 5: line_buffer[i] = z[i]; break; - case 6: line_buffer[i] = z[i]; break; - } - } - switch (type) { - case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; - case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; - case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; - case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; - case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; - case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; - } +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, + int filter_type, signed char *line_buffer) { + static int mapping[] = {0, 1, 2, 3, 4}; + static int firstmap[] = {0, 1, 0, 5, 6}; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height - 1 - y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type == 0) { + memcpy(line_buffer, z, width * n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: + line_buffer[i] = z[i]; + break; + case 2: + line_buffer[i] = z[i] - z[i - signed_stride]; + break; + case 3: + line_buffer[i] = z[i] - (z[i - signed_stride] >> 1); + break; + case 4: + line_buffer[i] = (signed char)(z[i] - stbiw__paeth(0, z[i - signed_stride], 0)); + break; + case 5: + line_buffer[i] = z[i]; + break; + case 6: + line_buffer[i] = z[i]; + break; + } + } + switch (type) { + case 1: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - z[i - n]; + break; + case 2: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - z[i - signed_stride]; + break; + case 3: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - ((z[i - n] + z[i - signed_stride]) >> 1); + break; + case 4: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - stbiw__paeth(z[i - n], z[i - signed_stride], z[i - signed_stride - n]); + break; + case 5: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - (z[i - n] >> 1); + break; + case 6: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - stbiw__paeth(z[i - n], 0, 0); + break; + } } -STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) -{ - int force_filter = stbi_write_force_png_filter; - int ctype[5] = { -1, 0, 4, 2, 6 }; - unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; - unsigned char *out,*o, *filt, *zlib; - signed char *line_buffer; - int j,zlen; - - if (stride_bytes == 0) - stride_bytes = x * n; - - if (force_filter >= 5) { - force_filter = -1; - } - - filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; - line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } - for (j=0; j < y; ++j) { - int filter_type; - if (force_filter > -1) { - filter_type = force_filter; - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); - } else { // Estimate the best filter by running through all of them: - int best_filter = 0, best_filter_val = 0x7fffffff, est, i; - for (filter_type = 0; filter_type < 5; filter_type++) { - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); - - // Estimate the entropy of the line using this filter; the less, the better. - est = 0; - for (i = 0; i < x*n; ++i) { - est += abs((signed char) line_buffer[i]); +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, + int *out_len) { + int force_filter = stbi_write_force_png_filter; + int ctype[5] = {-1, 0, 4, 2, 6}; + unsigned char sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + unsigned char *out, *o, *filt, *zlib; + signed char *line_buffer; + int j, zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *)STBIW_MALLOC((x * n + 1) * y); + if (!filt) + return 0; + line_buffer = (signed char *)STBIW_MALLOC(x * n); + if (!line_buffer) { + STBIW_FREE(filt); + return 0; + } + for (j = 0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char *)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char *)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x * n; ++i) { + est += abs((signed char)line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } } - if (est < best_filter_val) { - best_filter_val = est; - best_filter = filter_type; + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char *)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; } - } - if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); - filter_type = best_filter; - } - } - // when we get here, filter_type contains the filter type, and line_buffer contains the data - filt[j*(x*n+1)] = (unsigned char) filter_type; - STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); - } - STBIW_FREE(line_buffer); - zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); - STBIW_FREE(filt); - if (!zlib) return 0; - - // each tag requires 12 bytes of overhead - out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); - if (!out) return 0; - *out_len = 8 + 12+13 + 12+zlen + 12; - - o=out; - STBIW_MEMMOVE(o,sig,8); o+= 8; - stbiw__wp32(o, 13); // header length - stbiw__wptag(o, "IHDR"); - stbiw__wp32(o, x); - stbiw__wp32(o, y); - *o++ = 8; - *o++ = STBIW_UCHAR(ctype[n]); - *o++ = 0; - *o++ = 0; - *o++ = 0; - stbiw__wpcrc(&o,13); - - stbiw__wp32(o, zlen); - stbiw__wptag(o, "IDAT"); - STBIW_MEMMOVE(o, zlib, zlen); - o += zlen; - STBIW_FREE(zlib); - stbiw__wpcrc(&o, zlen); - - stbiw__wp32(o,0); - stbiw__wptag(o, "IEND"); - stbiw__wpcrc(&o,0); - - STBIW_ASSERT(o == out + *out_len); - - return out; + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j * (x * n + 1)] = (unsigned char)filter_type; + STBIW_MEMMOVE(filt + j * (x * n + 1) + 1, line_buffer, x * n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y * (x * n + 1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) + return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *)STBIW_MALLOC(8 + 12 + 13 + 12 + zlen + 12); + if (!out) + return 0; + *out_len = 8 + 12 + 13 + 12 + zlen + 12; + + o = out; + STBIW_MEMMOVE(o, sig, 8); + o += 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o, 13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o, 0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o, 0); + + STBIW_ASSERT(o == out + *out_len); + + return out; } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) -{ - FILE *f; - int len; - unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); - if (png == NULL) return 0; - - f = stbiw__fopen(filename, "wb"); - if (!f) { STBIW_FREE(png); return 0; } - fwrite(png, 1, len, f); - fclose(f); - STBIW_FREE(png); - return 1; +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) { + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *)data, stride_bytes, x, y, comp, &len); + if (png == NULL) + return 0; + + f = stbiw__fopen(filename, "wb"); + if (!f) { + STBIW_FREE(png); + return 0; + } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; } #endif -STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) -{ - int len; - unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); - if (png == NULL) return 0; - func(context, png, len); - STBIW_FREE(png); - return 1; +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, + int stride_bytes) { + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *)data, stride_bytes, x, y, comp, &len); + if (png == NULL) + return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; } - /* *************************************************************************** * * JPEG writer @@ -1193,337 +1237,406 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html */ -static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, - 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; +static const unsigned char stbiw__jpg_ZigZag[] = {0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63}; static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { - int bitBuf = *bitBufP, bitCnt = *bitCntP; - bitCnt += bs[1]; - bitBuf |= bs[0] << (24 - bitCnt); - while(bitCnt >= 8) { - unsigned char c = (bitBuf >> 16) & 255; - stbiw__putc(s, c); - if(c == 255) { - stbiw__putc(s, 0); - } - bitBuf <<= 8; - bitCnt -= 8; - } - *bitBufP = bitBuf; - *bitCntP = bitCnt; + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while (bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if (c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; } -static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { - float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; - float z1, z2, z3, z4, z5, z11, z13; - - float tmp0 = d0 + d7; - float tmp7 = d0 - d7; - float tmp1 = d1 + d6; - float tmp6 = d1 - d6; - float tmp2 = d2 + d5; - float tmp5 = d2 - d5; - float tmp3 = d3 + d4; - float tmp4 = d3 - d4; - - // Even part - float tmp10 = tmp0 + tmp3; // phase 2 - float tmp13 = tmp0 - tmp3; - float tmp11 = tmp1 + tmp2; - float tmp12 = tmp1 - tmp2; - - d0 = tmp10 + tmp11; // phase 3 - d4 = tmp10 - tmp11; - - z1 = (tmp12 + tmp13) * 0.707106781f; // c4 - d2 = tmp13 + z1; // phase 5 - d6 = tmp13 - z1; - - // Odd part - tmp10 = tmp4 + tmp5; // phase 2 - tmp11 = tmp5 + tmp6; - tmp12 = tmp6 + tmp7; - - // The rotator is modified from fig 4-8 to avoid extra negations. - z5 = (tmp10 - tmp12) * 0.382683433f; // c6 - z2 = tmp10 * 0.541196100f + z5; // c2-c6 - z4 = tmp12 * 1.306562965f + z5; // c2+c6 - z3 = tmp11 * 0.707106781f; // c4 - - z11 = tmp7 + z3; // phase 5 - z13 = tmp7 - z3; - - *d5p = z13 + z2; // phase 6 - *d3p = z13 - z2; - *d1p = z11 + z4; - *d7p = z11 - z4; - - *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, + float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; + *d2p = d2; + *d4p = d4; + *d6p = d6; } static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { - int tmp1 = val < 0 ? -val : val; - val = val < 0 ? val-1 : val; - bits[1] = 1; - while(tmp1 >>= 1) { - ++bits[1]; - } - bits[0] = val & ((1<>= 1) { + ++bits[1]; + } + bits[0] = val & ((1 << bits[1]) - 1); } -static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) { - const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] }; - const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] }; - int dataOff, i, diff, end0pos; - int DU[64]; - - // DCT rows - for(dataOff=0; dataOff<64; dataOff+=8) { - stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]); - } - // DCT columns - for(dataOff=0; dataOff<8; ++dataOff) { - stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]); - } - // Quantize/descale/zigzag the coefficients - for(i=0; i<64; ++i) { - float v = CDU[i]*fdtbl[i]; - // DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); - // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway? - DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f); - } - - // Encode DC - diff = DU[0] - DC; - if (diff == 0) { - stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]); - } else { - unsigned short bits[2]; - stbiw__jpg_calcBits(diff, bits); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); - } - // Encode ACs - end0pos = 63; - for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) { - } - // end0pos = first element in reverse order !=0 - if(end0pos == 0) { - stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); - return DU[0]; - } - for(i = 1; i <= end0pos; ++i) { - int startpos = i; - int nrzeroes; - unsigned short bits[2]; - for (; DU[i]==0 && i<=end0pos; ++i) { - } - nrzeroes = i-startpos; - if ( nrzeroes >= 16 ) { - int lng = nrzeroes>>4; - int nrmarker; - for (nrmarker=1; nrmarker <= lng; ++nrmarker) - stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); - nrzeroes &= 15; - } - stbiw__jpg_calcBits(DU[i], bits); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); - } - if(end0pos != 63) { - stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); - } - return DU[0]; +static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, + const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) { + const unsigned short EOB[2] = {HTAC[0x00][0], HTAC[0x00][1]}; + const unsigned short M16zeroes[2] = {HTAC[0xF0][0], HTAC[0xF0][1]}; + int dataOff, i, diff, end0pos; + int DU[64]; + + // DCT rows + for (dataOff = 0; dataOff < 64; dataOff += 8) { + stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff + 1], &CDU[dataOff + 2], &CDU[dataOff + 3], &CDU[dataOff + 4], + &CDU[dataOff + 5], &CDU[dataOff + 6], &CDU[dataOff + 7]); + } + // DCT columns + for (dataOff = 0; dataOff < 8; ++dataOff) { + stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff + 8], &CDU[dataOff + 16], &CDU[dataOff + 24], &CDU[dataOff + 32], + &CDU[dataOff + 40], &CDU[dataOff + 48], &CDU[dataOff + 56]); + } + // Quantize/descale/zigzag the coefficients + for (i = 0; i < 64; ++i) { + float v = CDU[i] * fdtbl[i]; + // DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); + // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway? + DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f); + } + + // Encode DC + diff = DU[0] - DC; + if (diff == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]); + } else { + unsigned short bits[2]; + stbiw__jpg_calcBits(diff, bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + // Encode ACs + end0pos = 63; + for (; (end0pos > 0) && (DU[end0pos] == 0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if (end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for (i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i] == 0 && i <= end0pos; ++i) { + } + nrzeroes = i - startpos; + if (nrzeroes >= 16) { + int lng = nrzeroes >> 4; + int nrmarker; + for (nrmarker = 1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes << 4) + bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if (end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; } -static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { - // Constants that don't pollute global namespace - static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; - static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; - static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; - static const unsigned char std_ac_luminance_values[] = { - 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, - 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, - 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, - 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, - 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, - 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, - 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa - }; - static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; - static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; - static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; - static const unsigned char std_ac_chrominance_values[] = { - 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, - 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, - 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, - 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, - 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, - 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, - 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa - }; - // Huffman tables - static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; - static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; - static const unsigned short YAC_HT[256][2] = { - {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} - }; - static const unsigned short UVAC_HT[256][2] = { - {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} - }; - static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, - 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; - static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, - 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; - static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, - 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; - - int row, col, i, k; - float fdtbl_Y[64], fdtbl_UV[64]; - unsigned char YTable[64], UVTable[64]; - - if(!data || !width || !height || comp > 4 || comp < 1) { - return 0; - } - - quality = quality ? quality : 90; - quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; - quality = quality < 50 ? 5000 / quality : 200 - quality * 2; - - for(i = 0; i < 64; ++i) { - int uvti, yti = (YQT[i]*quality+50)/100; - YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); - uvti = (UVQT[i]*quality+50)/100; - UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); - } - - for(row = 0, k = 0; row < 8; ++row) { - for(col = 0; col < 8; ++col, ++k) { - fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); - fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); - } - } - - // Write Headers - { - static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; - static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; - const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), - 3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; - s->func(s->context, (void*)head0, sizeof(head0)); - s->func(s->context, (void*)YTable, sizeof(YTable)); - stbiw__putc(s, 1); - s->func(s->context, UVTable, sizeof(UVTable)); - s->func(s->context, (void*)head1, sizeof(head1)); - s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); - s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); - stbiw__putc(s, 0x10); // HTYACinfo - s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); - s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); - stbiw__putc(s, 1); // HTUDCinfo - s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); - s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); - stbiw__putc(s, 0x11); // HTUACinfo - s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); - s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); - s->func(s->context, (void*)head2, sizeof(head2)); - } - - // Encode 8x8 macroblocks - { - static const unsigned short fillBits[] = {0x7F, 7}; - const unsigned char *imageData = (const unsigned char *)data; - int DCY=0, DCU=0, DCV=0; - int bitBuf=0, bitCnt=0; - // comp == 2 is grey+alpha (alpha is ignored) - int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; - int x, y, pos; - for(y = 0; y < height; y += 8) { - for(x = 0; x < width; x += 8) { - float YDU[64], UDU[64], VDU[64]; - for(row = y, pos = 0; row < y+8; ++row) { - // row >= height => use last input row - int clamped_row = (row < height) ? row : height - 1; - int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; - for(col = x; col < x+8; ++col, ++pos) { - float r, g, b; - // if col >= width => use pixel from last input column - int p = base_p + ((col < width) ? col : (width-1))*comp; - - r = imageData[p+0]; - g = imageData[p+ofsG]; - b = imageData[p+ofsB]; - YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128; - UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b; - VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b; - } +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void *data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}; + static const unsigned char std_dc_luminance_values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, + 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, + 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa}; + static const unsigned char std_dc_chrominance_nrcodes[] = {0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; + static const unsigned char std_dc_chrominance_values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, + 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, + 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, + 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, + 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa}; + // Huffman tables + static const unsigned short YDC_HT[256][2] = {{0, 2}, {2, 3}, {3, 3}, {4, 3}, {5, 3}, {6, 3}, + {14, 4}, {30, 5}, {62, 6}, {126, 7}, {254, 8}, {510, 9}}; + static const unsigned short UVDC_HT[256][2] = {{0, 2}, {1, 2}, {2, 2}, {6, 3}, {14, 4}, {30, 5}, + {62, 6}, {126, 7}, {254, 8}, {510, 9}, {1022, 10}, {2046, 11}}; + static const unsigned short YAC_HT[256][2] = { + {10, 4}, {0, 2}, {1, 2}, {4, 3}, {11, 4}, {26, 5}, {120, 7}, {248, 8}, + {1014, 10}, {65410, 16}, {65411, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {12, 4}, {27, 5}, {121, 7}, {502, 9}, {2038, 11}, {65412, 16}, {65413, 16}, + {65414, 16}, {65415, 16}, {65416, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {28, 5}, {249, 8}, {1015, 10}, {4084, 12}, {65417, 16}, {65418, 16}, {65419, 16}, + {65420, 16}, {65421, 16}, {65422, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {58, 6}, {503, 9}, {4085, 12}, {65423, 16}, {65424, 16}, {65425, 16}, {65426, 16}, + {65427, 16}, {65428, 16}, {65429, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {59, 6}, {1016, 10}, {65430, 16}, {65431, 16}, {65432, 16}, {65433, 16}, {65434, 16}, + {65435, 16}, {65436, 16}, {65437, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {122, 7}, {2039, 11}, {65438, 16}, {65439, 16}, {65440, 16}, {65441, 16}, {65442, 16}, + {65443, 16}, {65444, 16}, {65445, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {123, 7}, {4086, 12}, {65446, 16}, {65447, 16}, {65448, 16}, {65449, 16}, {65450, 16}, + {65451, 16}, {65452, 16}, {65453, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {250, 8}, {4087, 12}, {65454, 16}, {65455, 16}, {65456, 16}, {65457, 16}, {65458, 16}, + {65459, 16}, {65460, 16}, {65461, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {504, 9}, {32704, 15}, {65462, 16}, {65463, 16}, {65464, 16}, {65465, 16}, {65466, 16}, + {65467, 16}, {65468, 16}, {65469, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {505, 9}, {65470, 16}, {65471, 16}, {65472, 16}, {65473, 16}, {65474, 16}, {65475, 16}, + {65476, 16}, {65477, 16}, {65478, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {506, 9}, {65479, 16}, {65480, 16}, {65481, 16}, {65482, 16}, {65483, 16}, {65484, 16}, + {65485, 16}, {65486, 16}, {65487, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {1017, 10}, {65488, 16}, {65489, 16}, {65490, 16}, {65491, 16}, {65492, 16}, {65493, 16}, + {65494, 16}, {65495, 16}, {65496, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {1018, 10}, {65497, 16}, {65498, 16}, {65499, 16}, {65500, 16}, {65501, 16}, {65502, 16}, + {65503, 16}, {65504, 16}, {65505, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {2040, 11}, {65506, 16}, {65507, 16}, {65508, 16}, {65509, 16}, {65510, 16}, {65511, 16}, + {65512, 16}, {65513, 16}, {65514, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {65515, 16}, {65516, 16}, {65517, 16}, {65518, 16}, {65519, 16}, {65520, 16}, {65521, 16}, + {65522, 16}, {65523, 16}, {65524, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {2041, 11}, {65525, 16}, {65526, 16}, {65527, 16}, {65528, 16}, {65529, 16}, {65530, 16}, {65531, 16}, + {65532, 16}, {65533, 16}, {65534, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}; + static const unsigned short UVAC_HT[256][2] = { + {0, 2}, {1, 2}, {4, 3}, {10, 4}, {24, 5}, {25, 5}, {56, 6}, {120, 7}, + {500, 9}, {1014, 10}, {4084, 12}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {11, 4}, {57, 6}, {246, 8}, {501, 9}, {2038, 11}, {4085, 12}, {65416, 16}, + {65417, 16}, {65418, 16}, {65419, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {26, 5}, {247, 8}, {1015, 10}, {4086, 12}, {32706, 15}, {65420, 16}, {65421, 16}, + {65422, 16}, {65423, 16}, {65424, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {27, 5}, {248, 8}, {1016, 10}, {4087, 12}, {65425, 16}, {65426, 16}, {65427, 16}, + {65428, 16}, {65429, 16}, {65430, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {58, 6}, {502, 9}, {65431, 16}, {65432, 16}, {65433, 16}, {65434, 16}, {65435, 16}, + {65436, 16}, {65437, 16}, {65438, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {59, 6}, {1017, 10}, {65439, 16}, {65440, 16}, {65441, 16}, {65442, 16}, {65443, 16}, + {65444, 16}, {65445, 16}, {65446, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {121, 7}, {2039, 11}, {65447, 16}, {65448, 16}, {65449, 16}, {65450, 16}, {65451, 16}, + {65452, 16}, {65453, 16}, {65454, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {122, 7}, {2040, 11}, {65455, 16}, {65456, 16}, {65457, 16}, {65458, 16}, {65459, 16}, + {65460, 16}, {65461, 16}, {65462, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {249, 8}, {65463, 16}, {65464, 16}, {65465, 16}, {65466, 16}, {65467, 16}, {65468, 16}, + {65469, 16}, {65470, 16}, {65471, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {503, 9}, {65472, 16}, {65473, 16}, {65474, 16}, {65475, 16}, {65476, 16}, {65477, 16}, + {65478, 16}, {65479, 16}, {65480, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {504, 9}, {65481, 16}, {65482, 16}, {65483, 16}, {65484, 16}, {65485, 16}, {65486, 16}, + {65487, 16}, {65488, 16}, {65489, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {505, 9}, {65490, 16}, {65491, 16}, {65492, 16}, {65493, 16}, {65494, 16}, {65495, 16}, + {65496, 16}, {65497, 16}, {65498, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {506, 9}, {65499, 16}, {65500, 16}, {65501, 16}, {65502, 16}, {65503, 16}, {65504, 16}, + {65505, 16}, {65506, 16}, {65507, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {2041, 11}, {65508, 16}, {65509, 16}, {65510, 16}, {65511, 16}, {65512, 16}, {65513, 16}, + {65514, 16}, {65515, 16}, {65516, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {16352, 14}, {65517, 16}, {65518, 16}, {65519, 16}, {65520, 16}, {65521, 16}, {65522, 16}, + {65523, 16}, {65524, 16}, {65525, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {1018, 10}, {32707, 15}, {65526, 16}, {65527, 16}, {65528, 16}, {65529, 16}, {65530, 16}, {65531, 16}, + {65532, 16}, {65533, 16}, {65534, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}; + static const int YQT[] = {16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99}; + static const int UVQT[] = {17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, + 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}; + static const float aasf[] = {1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, + 1.175875602f * 2.828427125f, 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, + 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f}; + + int row, col, i, k; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if (!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for (i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i] * quality + 50) / 100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char)(yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i] * quality + 50) / 100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char)(uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for (row = 0, k = 0; row < 8; ++row) { + for (col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = {0xFF, 0xD8, 0xFF, 0xE0, 0, 0x10, 'J', 'F', 'I', 'F', 0, 1, 1, + 0, 0, 1, 0, 1, 0, 0, 0xFF, 0xDB, 0, 0x84, 0}; + static const unsigned char head2[] = {0xFF, 0xDA, 0, 0xC, 3, 1, 0, 2, 0x11, 3, 0x11, 0, 0x3F, 0}; + const unsigned char head1[] = {0xFF, + 0xC0, + 0, + 0x11, + 8, + (unsigned char)(height >> 8), + STBIW_UCHAR(height), + (unsigned char)(width >> 8), + STBIW_UCHAR(width), + 3, + 1, + 0x11, + 0, + 2, + 0x11, + 1, + 3, + 0x11, + 1, + 0xFF, + 0xC4, + 0x01, + 0xA2, + 0}; + s->func(s->context, (void *)head0, sizeof(head0)); + s->func(s->context, (void *)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void *)head1, sizeof(head1)); + s->func(s->context, (void *)(std_dc_luminance_nrcodes + 1), sizeof(std_dc_luminance_nrcodes) - 1); + s->func(s->context, (void *)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void *)(std_ac_luminance_nrcodes + 1), sizeof(std_ac_luminance_nrcodes) - 1); + s->func(s->context, (void *)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void *)(std_dc_chrominance_nrcodes + 1), sizeof(std_dc_chrominance_nrcodes) - 1); + s->func(s->context, (void *)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void *)(std_ac_chrominance_nrcodes + 1), sizeof(std_ac_chrominance_nrcodes) - 1); + s->func(s->context, (void *)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void *)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + const unsigned char *imageData = (const unsigned char *)data; + int DCY = 0, DCU = 0, DCV = 0; + int bitBuf = 0, bitCnt = 0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + int x, y, pos; + for (y = 0; y < height; y += 8) { + for (x = 0; x < width; x += 8) { + float YDU[64], UDU[64], VDU[64]; + for (row = y, pos = 0; row < y + 8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = + (stbi__flip_vertically_on_write ? (height - 1 - clamped_row) : clamped_row) * width * comp; + for (col = x; col < x + 8; ++col, ++pos) { + float r, g, b; + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width - 1)) * comp; + + r = imageData[p + 0]; + g = imageData[p + ofsG]; + b = imageData[p + ofsB]; + YDU[pos] = +0.29900f * r + 0.58700f * g + 0.11400f * b - 128; + UDU[pos] = -0.16874f * r - 0.33126f * g + 0.50000f * b; + VDU[pos] = +0.50000f * r - 0.41869f * g - 0.08131f * b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); } + } - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); - DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); - } - } + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } - // Do the bit alignment of the EOI marker - stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); - } + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); - // EOI - stbiw__putc(s, 0xFF); - stbiw__putc(s, 0xD9); - - return 1; + return 1; } -STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, + int quality) { + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *)data, quality); } - #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) { + stbi__write_context s; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; } #endif @@ -1531,7 +1644,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const /* Revision history 1.10 (2019-02-07) - support utf8 filenames in Windows; fix warnings and platform ifdefs + support utf8 filenames in Windows; fix warnings and platform ifdefs 1.09 (2018-02-11) fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1.08 (2018-01-29) @@ -1562,7 +1675,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const add HDR output fix monochrome BMP 0.95 (2014-08-17) - add monochrome TGA output + add monochrome TGA output 0.94 (2014-05-31) rename private functions to avoid conflicts with stb_image.h 0.93 (2014-05-27) @@ -1580,38 +1693,38 @@ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett -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 +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 +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 +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. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. -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 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 +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 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. ------------------------------------------------------------------------------ */ diff --git a/src/stb_truetype.h b/src/stb_truetype.h index bbf2284..622e4ef 100644 --- a/src/stb_truetype.h +++ b/src/stb_truetype.h @@ -275,7 +275,7 @@ // Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless. // See "tests/truetype_demo_win32.c" for a complete version. #if 0 -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation #include "stb_truetype.h" unsigned char ttf_buffer[1<<20]; @@ -326,7 +326,7 @@ void my_stbtt_print(float x, float y, char *text) // #if 0 #include -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation #include "stb_truetype.h" char ttf_buffer[1<<25]; @@ -412,7 +412,6 @@ int main(int arg, char **argv) } #endif - ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //// @@ -423,70 +422,70 @@ int main(int arg, char **argv) //// link with the C runtime library. #ifdef STB_TRUETYPE_IMPLEMENTATION - // #define your own (u)stbtt_int8/16/32 before including to override this - #ifndef stbtt_uint8 - typedef unsigned char stbtt_uint8; - typedef signed char stbtt_int8; - typedef unsigned short stbtt_uint16; - typedef signed short stbtt_int16; - typedef unsigned int stbtt_uint32; - typedef signed int stbtt_int32; - #endif - - typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; - typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; - - // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h - #ifndef STBTT_ifloor - #include - #define STBTT_ifloor(x) ((int) floor(x)) - #define STBTT_iceil(x) ((int) ceil(x)) - #endif - - #ifndef STBTT_sqrt - #include - #define STBTT_sqrt(x) sqrt(x) - #define STBTT_pow(x,y) pow(x,y) - #endif - - #ifndef STBTT_fmod - #include - #define STBTT_fmod(x,y) fmod(x,y) - #endif - - #ifndef STBTT_cos - #include - #define STBTT_cos(x) cos(x) - #define STBTT_acos(x) acos(x) - #endif - - #ifndef STBTT_fabs - #include - #define STBTT_fabs(x) fabs(x) - #endif - - // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h - #ifndef STBTT_malloc - #include - #define STBTT_malloc(x,u) ((void)(u),malloc(x)) - #define STBTT_free(x,u) ((void)(u),free(x)) - #endif - - #ifndef STBTT_assert - #include - #define STBTT_assert(x) assert(x) - #endif - - #ifndef STBTT_strlen - #include - #define STBTT_strlen(x) strlen(x) - #endif - - #ifndef STBTT_memcpy - #include - #define STBTT_memcpy memcpy - #define STBTT_memset memset - #endif +// #define your own (u)stbtt_int8/16/32 before including to override this +#ifndef stbtt_uint8 +typedef unsigned char stbtt_uint8; +typedef signed char stbtt_int8; +typedef unsigned short stbtt_uint16; +typedef signed short stbtt_int16; +typedef unsigned int stbtt_uint32; +typedef signed int stbtt_int32; +#endif + +typedef char stbtt__check_size32[sizeof(stbtt_int32) == 4 ? 1 : -1]; +typedef char stbtt__check_size16[sizeof(stbtt_int16) == 2 ? 1 : -1]; + +// e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h +#ifndef STBTT_ifloor +#include +#define STBTT_ifloor(x) ((int)floor(x)) +#define STBTT_iceil(x) ((int)ceil(x)) +#endif + +#ifndef STBTT_sqrt +#include +#define STBTT_sqrt(x) sqrt(x) +#define STBTT_pow(x, y) pow(x, y) +#endif + +#ifndef STBTT_fmod +#include +#define STBTT_fmod(x, y) fmod(x, y) +#endif + +#ifndef STBTT_cos +#include +#define STBTT_cos(x) cos(x) +#define STBTT_acos(x) acos(x) +#endif + +#ifndef STBTT_fabs +#include +#define STBTT_fabs(x) fabs(x) +#endif + +// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h +#ifndef STBTT_malloc +#include +#define STBTT_malloc(x, u) ((void)(u), malloc(x)) +#define STBTT_free(x, u) ((void)(u), free(x)) +#endif + +#ifndef STBTT_assert +#include +#define STBTT_assert(x) assert(x) +#endif + +#ifndef STBTT_strlen +#include +#define STBTT_strlen(x) strlen(x) +#endif + +#ifndef STBTT_memcpy +#include +#define STBTT_memcpy memcpy +#define STBTT_memset memset +#endif #endif /////////////////////////////////////////////////////////////////////////////// @@ -510,11 +509,10 @@ extern "C" { #endif // private structure -typedef struct -{ - unsigned char *data; - int cursor; - int size; +typedef struct { + unsigned char *data; + int cursor; + int size; } stbtt__buf; ////////////////////////////////////////////////////////////////////////////// @@ -524,33 +522,31 @@ typedef struct // If you use this API, you only have to call two functions ever. // -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; +typedef struct { + unsigned short x0, y0, x1, y1; // coordinates of bbox in bitmap + float xoff, yoff, xadvance; } stbtt_bakedchar; -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata); // you allocate this, it's num_chars long +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata); // you allocate this, it's num_chars long // if return is positive, the first unused row of the bitmap // if return is negative, returns the negative of the number of characters that fit // if return is 0, no characters fit and no rows were used // This uses a very crappy packing. -typedef struct -{ - float x0,y0,s0,t0; // top-left - float x1,y1,s1,t1; // bottom-right +typedef struct { + float x0, y0, s0, t0; // top-left + float x1, y1, s1, t1; // bottom-right } stbtt_aligned_quad; -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier // Call GetBakedQuad with char_index = 'character - first_char', and it // creates the quad you need to draw and advances the current position. // @@ -561,10 +557,10 @@ STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int p // // It's inefficient; you might want to c&p it and optimize it. -STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, + float *descent, float *lineGap); // Query the font vertical metrics without having to create a font first. - ////////////////////////////////////////////////////////////////////////////// // // NEW TEXTURE BAKING API @@ -572,20 +568,20 @@ STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int in // This provides options for packing multiple fonts into one atlas, not // perfectly but better than nothing. -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; - float xoff2,yoff2; +typedef struct { + unsigned short x0, y0, x1, y1; // coordinates of bbox in bitmap + float xoff, yoff, xadvance; + float xoff2, yoff2; } stbtt_packedchar; typedef struct stbtt_pack_context stbtt_pack_context; -typedef struct stbtt_fontinfo stbtt_fontinfo; +typedef struct stbtt_fontinfo stbtt_fontinfo; #ifndef STB_RECT_PACK_VERSION typedef struct stbrp_rect stbrp_rect; #endif -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, + int stride_in_bytes, int padding, void *alloc_context); // Initializes a packing context stored in the passed-in stbtt_pack_context. // Future calls using this context will pack characters into the bitmap passed // in here: a 1-channel bitmap that is width * height. stride_in_bytes is @@ -596,13 +592,14 @@ STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, i // // Returns 0 on failure, 1 on success. -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +STBTT_DEF void stbtt_PackEnd(stbtt_pack_context *spc); // Cleans up the packing context and frees all memory. -#define STBTT_POINT_SIZE(x) (-(x)) +#define STBTT_POINT_SIZE(x) (-(x)) -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, - int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, + float font_size, int first_unicode_char_in_range, int num_chars_in_range, + stbtt_packedchar *chardata_for_range); // Creates character bitmaps from the font_index'th font found in fontdata (use // font_index=0 if you don't know what that is). It creates num_chars_in_range // bitmaps for characters with unicode values starting at first_unicode_char_in_range @@ -616,17 +613,17 @@ STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char // ..., 20 , ... // font max minus min y is 20 pixels tall // ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall -typedef struct -{ - float font_size; - int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint - int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints - int num_chars; - stbtt_packedchar *chardata_for_range; // output - unsigned char h_oversample, v_oversample; // don't set these, they're used internally +typedef struct { + float font_size; + int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint + int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints + int num_chars; + stbtt_packedchar *chardata_for_range; // output + unsigned char h_oversample, v_oversample; // don't set these, they're used internally } stbtt_pack_range; -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, + stbtt_pack_range *ranges, int num_ranges); // Creates character bitmaps from multiple ranges of characters stored in // ranges. This will usually create a better-packed bitmap than multiple // calls to stbtt_PackFontRange. Note that you can call this multiple @@ -654,15 +651,17 @@ STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int s // codepoints without a glyph recived the font's "missing character" glyph, // typically an empty box by convention. -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int align_to_integer); +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int align_to_integer); -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, + stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, + stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); // Calling these functions in sequence is roughly equivalent to calling // stbtt_PackFontRanges(). If you more control over the packing of multiple // fonts, or if you want to pack custom data into a font texture, take a look @@ -676,16 +675,16 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, cons // this is an opaque structure that you shouldn't mess with which holds // all the context needed from PackBegin to PackEnd. struct stbtt_pack_context { - void *user_allocator_context; - void *pack_info; - int width; - int height; - int stride_in_bytes; - int padding; - int skip_missing; - unsigned int h_oversample, v_oversample; - unsigned char *pixels; - void *nodes; + void *user_allocator_context; + void *pack_info; + int width; + int height; + int stride_in_bytes; + int padding; + int skip_missing; + unsigned int h_oversample, v_oversample; + unsigned char *pixels; + void *nodes; }; ////////////////////////////////////////////////////////////////////////////// @@ -710,24 +709,23 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); // The following structure is defined publicly so you can declare one on // the stack or as a global or etc, but you should treat it as opaque. -struct stbtt_fontinfo -{ - void * userdata; - unsigned char * data; // pointer to .ttf file - int fontstart; // offset of start of font - - int numGlyphs; // number of glyphs, needed for range checking - - int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf - int index_map; // a cmap mapping for our chosen character encoding - int indexToLocFormat; // format needed to map from glyph index to glyph - - stbtt__buf cff; // cff font data - stbtt__buf charstrings; // the charstring index - stbtt__buf gsubrs; // global charstring subroutines index - stbtt__buf subrs; // private charstring subroutines index - stbtt__buf fontdicts; // array of font dicts - stbtt__buf fdselect; // map from glyph to fontdict +struct stbtt_fontinfo { + void *userdata; + unsigned char *data; // pointer to .ttf file + int fontstart; // offset of start of font + + int numGlyphs; // number of glyphs, needed for range checking + + int loca, head, glyf, hhea, hmtx, kern, gpos, svg; // table locations as offset from start of .ttf + int index_map; // a cmap mapping for our chosen character encoding + int indexToLocFormat; // format needed to map from glyph index to glyph + + stbtt__buf cff; // cff font data + stbtt__buf charstrings; // the charstring index + stbtt__buf gsubrs; // global charstring subroutines index + stbtt__buf subrs; // private charstring subroutines index + stbtt__buf fontdicts; // array of font dicts + stbtt__buf fdselect; // map from glyph to fontdict }; STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); @@ -737,7 +735,6 @@ STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, in // need to do anything special to free it, because the contents are pure // value data with no additional data structures. Returns 0 on failure. - ////////////////////////////////////////////////////////////////////////////// // // CHARACTER TO GLYPH-INDEX CONVERSIOn @@ -749,7 +746,6 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep // codepoint-based functions. // Returns 0 if the character codepoint is not defined in the font. - ////////////////////////////////////////////////////////////////////////////// // // CHARACTER PROPERTIES @@ -776,7 +772,7 @@ STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, in // these are expressed in unscaled coordinates, so you must multiply by // the scale factor for a given size -STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); // analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 // table (specific to MS/Windows TTF files). // @@ -785,31 +781,32 @@ STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAsc STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); // the bounding box around all possible characters -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, + int *leftSideBearing); // leftSideBearing is the offset from the current horizontal position to the left edge of the character // advanceWidth is the offset from the current horizontal position to the next horizontal position // these are expressed in unscaled coordinates -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); // an additional amount to add to the 'advance' value between ch1 and ch2 STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); // Gets the bounding box of the visible part of the glyph, in unscaled coordinates -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, + int *leftSideBearing); STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); // as above, but takes one or more glyph indices for greater efficiency -typedef struct stbtt_kerningentry -{ - int glyph1; // use stbtt_FindGlyphIndex - int glyph2; - int advance; +typedef struct stbtt_kerningentry { + int glyph1; // use stbtt_FindGlyphIndex + int glyph2; + int advance; } stbtt_kerningentry; -STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); -STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry *table, int table_length); // Retrieves a complete list of all of the kerning pairs provided by the font // stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. // The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) @@ -821,22 +818,16 @@ STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningen // #ifndef STBTT_vmove // you can predefine these to use different values (but why?) - enum { - STBTT_vmove=1, - STBTT_vline, - STBTT_vcurve, - STBTT_vcubic - }; +enum { STBTT_vmove = 1, STBTT_vline, STBTT_vcurve, STBTT_vcubic }; #endif -#ifndef stbtt_vertex // you can predefine this to use different values - // (we share this with other code at RAD) - #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file - typedef struct - { - stbtt_vertex_type x,y,cx,cy,cx1,cy1; - unsigned char type,padding; - } stbtt_vertex; +#ifndef stbtt_vertex // you can predefine this to use different values + // (we share this with other code at RAD) +#define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file +typedef struct { + stbtt_vertex_type x, y, cx, cy, cx1, cy1; + unsigned char type, padding; +} stbtt_vertex; #endif STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); @@ -858,8 +849,8 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertice // frees the data allocated above STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); -STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); -STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); // fills svg with the character's SVG data. // returns data size or 0 if SVG not found. @@ -871,7 +862,8 @@ STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char * STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); // frees the bitmap allocated below -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, + int codepoint, int *width, int *height, int *xoff, int *yoff); // allocates a large-enough single-channel 8bpp bitmap and renders the // specified character/glyph at the specified scale into it, with // antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). @@ -880,63 +872,83 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, fl // // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, + float shift_x, float shift_y, int codepoint, int *width, + int *height, int *xoff, int *yoff); // the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel // shift for the character -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, + int out_stride, float scale_x, float scale_y, int codepoint); // the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap // in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap // is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the // width and height and positioning info for it first. -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, + int out_h, int out_stride, float scale_x, float scale_y, float shift_x, + float shift_y, int codepoint); // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel // shift for the character -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, + int out_h, int out_stride, float scale_x, float scale_y, + float shift_x, float shift_y, int oversample_x, + int oversample_y, float *sub_x, float *sub_y, int codepoint); // same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering // is performed (see stbtt_PackSetOversampling) -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, + int *ix0, int *iy0, int *ix1, int *iy1); // get the bbox of the bitmap centered around the glyph origin; so the // bitmap width is ix1-ix0, height is iy1-iy0, and location to place // the bitmap top left is (leftSideBearing*scale,iy0). // (Note that the bitmap uses y-increases-down, but the shape uses // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, + float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, + int *ix1, int *iy1); // same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel // shift for the character // the following functions are equivalent to the above functions, but operate // on glyph indices instead of Unicode codepoints (for efficiency) -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); - +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, + int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, + float shift_x, float shift_y, int glyph, int *width, int *height, + int *xoff, int *yoff); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, + int out_stride, float scale_x, float scale_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, + int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, + int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, + int out_h, int out_stride, float scale_x, float scale_y, + float shift_x, float shift_y, int oversample_x, int oversample_y, + float *sub_x, float *sub_y, int glyph); +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, + int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, + float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); // @TODO: don't expose this structure -typedef struct -{ - int w,h,stride; - unsigned char *pixels; +typedef struct { + int w, h, stride; + unsigned char *pixels; } stbtt__bitmap; // rasterize a shape with quadratic beziers into a bitmap -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into - float flatness_in_pixels, // allowable error of curve in pixels - stbtt_vertex *vertices, // array of vertices defining shape - int num_verts, // number of vertices in above array - float scale_x, float scale_y, // scale applied to input vertices - float shift_x, float shift_y, // translation applied to input vertices - int x_off, int y_off, // another translation applied to input - int invert, // if non-zero, vertically flip shape - void *userdata); // context for to STBTT_MALLOC +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into + float flatness_in_pixels, // allowable error of curve in pixels + stbtt_vertex *vertices, // array of vertices defining shape + int num_verts, // number of vertices in above array + float scale_x, float scale_y, // scale applied to input vertices + float shift_x, float shift_y, // translation applied to input vertices + int x_off, int y_off, // another translation applied to input + int invert, // if non-zero, vertically flip shape + void *userdata); // context for to STBTT_MALLOC ////////////////////////////////////////////////////////////////////////////// // @@ -945,18 +957,23 @@ STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); // frees the SDF bitmap allocated below -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, + unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, + int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, + unsigned char onedge_value, float pixel_dist_scale, int *width, + int *height, int *xoff, int *yoff); // These functions compute a discretized SDF field for a single character, suitable for storing // in a single-channel texture, sampling with bilinear filtering, and testing against // larger than some threshold to produce scalable fonts. // info -- the font -// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap -// glyph/codepoint -- the character to generate the SDF for -// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), +// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular +// bitmap glyph/codepoint -- the character to generate the SDF for padding -- extra "pixels" around +// the character which are filled with the distance to the character (not 0), // which allows effects like bit outlines -// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) -// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) +// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of +// the character) pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away +// from the edge (on the 0..255 scale) // if positive, > onedge_value is inside; if negative, < onedge_value is inside // width,height -- output height & width of the SDF bitmap (including padding) // xoff,yoff -- output origin of the character @@ -994,8 +1011,6 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // The algorithm has not been optimized at all, so expect it to be slow // if computing lots of characters or very large sizes. - - ////////////////////////////////////////////////////////////////////////////// // // Finding the right font... @@ -1017,23 +1032,23 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // from the file yourself and do your own comparisons on them. // You have to have called stbtt_InitFont() first. - STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); // returns the offset (not index) of the font that matches, or -1 if none // if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". // if you use any other flag, use a font name like "Arial"; this checks // the 'macStyle' header field; i don't know if fonts set this consistently -#define STBTT_MACSTYLE_DONTCARE 0 -#define STBTT_MACSTYLE_BOLD 1 -#define STBTT_MACSTYLE_ITALIC 2 -#define STBTT_MACSTYLE_UNDERSCORE 4 -#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 +#define STBTT_MACSTYLE_DONTCARE 0 +#define STBTT_MACSTYLE_BOLD 1 +#define STBTT_MACSTYLE_ITALIC 2 +#define STBTT_MACSTYLE_UNDERSCORE 4 +#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); // returns 1/0 whether the first string interpreted as utf8 is identical to // the second string interpreted as big-endian utf16... useful for strings from next func -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, + int languageID, int nameID); // returns the string (which may be big-endian double byte, e.g. for unicode) // and puts the length in bytes in *length. // @@ -1042,52 +1057,69 @@ STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *l // http://www.microsoft.com/typography/otspec/name.htm enum { // platformID - STBTT_PLATFORM_ID_UNICODE =0, - STBTT_PLATFORM_ID_MAC =1, - STBTT_PLATFORM_ID_ISO =2, - STBTT_PLATFORM_ID_MICROSOFT =3 + STBTT_PLATFORM_ID_UNICODE = 0, + STBTT_PLATFORM_ID_MAC = 1, + STBTT_PLATFORM_ID_ISO = 2, + STBTT_PLATFORM_ID_MICROSOFT = 3 }; enum { // encodingID for STBTT_PLATFORM_ID_UNICODE - STBTT_UNICODE_EID_UNICODE_1_0 =0, - STBTT_UNICODE_EID_UNICODE_1_1 =1, - STBTT_UNICODE_EID_ISO_10646 =2, - STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, - STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 + STBTT_UNICODE_EID_UNICODE_1_0 = 0, + STBTT_UNICODE_EID_UNICODE_1_1 = 1, + STBTT_UNICODE_EID_ISO_10646 = 2, + STBTT_UNICODE_EID_UNICODE_2_0_BMP = 3, + STBTT_UNICODE_EID_UNICODE_2_0_FULL = 4 }; enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT - STBTT_MS_EID_SYMBOL =0, - STBTT_MS_EID_UNICODE_BMP =1, - STBTT_MS_EID_SHIFTJIS =2, - STBTT_MS_EID_UNICODE_FULL =10 + STBTT_MS_EID_SYMBOL = 0, + STBTT_MS_EID_UNICODE_BMP = 1, + STBTT_MS_EID_SHIFTJIS = 2, + STBTT_MS_EID_UNICODE_FULL = 10 }; enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes - STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, - STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, - STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, - STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 + STBTT_MAC_EID_ROMAN = 0, + STBTT_MAC_EID_ARABIC = 4, + STBTT_MAC_EID_JAPANESE = 1, + STBTT_MAC_EID_HEBREW = 5, + STBTT_MAC_EID_CHINESE_TRAD = 2, + STBTT_MAC_EID_GREEK = 6, + STBTT_MAC_EID_KOREAN = 3, + STBTT_MAC_EID_RUSSIAN = 7 }; enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs - STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, - STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, - STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, - STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, - STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, - STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D + STBTT_MS_LANG_ENGLISH = 0x0409, + STBTT_MS_LANG_ITALIAN = 0x0410, + STBTT_MS_LANG_CHINESE = 0x0804, + STBTT_MS_LANG_JAPANESE = 0x0411, + STBTT_MS_LANG_DUTCH = 0x0413, + STBTT_MS_LANG_KOREAN = 0x0412, + STBTT_MS_LANG_FRENCH = 0x040c, + STBTT_MS_LANG_RUSSIAN = 0x0419, + STBTT_MS_LANG_GERMAN = 0x0407, + STBTT_MS_LANG_SPANISH = 0x0409, + STBTT_MS_LANG_HEBREW = 0x040d, + STBTT_MS_LANG_SWEDISH = 0x041D }; enum { // languageID for STBTT_PLATFORM_ID_MAC - STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, - STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, - STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, - STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , - STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , - STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, - STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 + STBTT_MAC_LANG_ENGLISH = 0, + STBTT_MAC_LANG_JAPANESE = 11, + STBTT_MAC_LANG_ARABIC = 12, + STBTT_MAC_LANG_KOREAN = 23, + STBTT_MAC_LANG_DUTCH = 4, + STBTT_MAC_LANG_RUSSIAN = 32, + STBTT_MAC_LANG_FRENCH = 1, + STBTT_MAC_LANG_SPANISH = 6, + STBTT_MAC_LANG_GERMAN = 2, + STBTT_MAC_LANG_SWEDISH = 5, + STBTT_MAC_LANG_HEBREW = 10, + STBTT_MAC_LANG_CHINESE_SIMPLIFIED = 33, + STBTT_MAC_LANG_ITALIAN = 3, + STBTT_MAC_LANG_CHINESE_TRAD = 19 }; #ifdef __cplusplus @@ -1106,23 +1138,23 @@ enum { // languageID for STBTT_PLATFORM_ID_MAC #ifdef STB_TRUETYPE_IMPLEMENTATION #ifndef STBTT_MAX_OVERSAMPLE -#define STBTT_MAX_OVERSAMPLE 8 +#define STBTT_MAX_OVERSAMPLE 8 #endif #if STBTT_MAX_OVERSAMPLE > 255 #error "STBTT_MAX_OVERSAMPLE cannot be > 255" #endif -typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; +typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE - 1)) == 0 ? 1 : -1]; #ifndef STBTT_RASTERIZER_VERSION #define STBTT_RASTERIZER_VERSION 2 #endif #ifdef _MSC_VER -#define STBTT__NOTUSED(v) (void)(v) +#define STBTT__NOTUSED(v) (void)(v) #else -#define STBTT__NOTUSED(v) (void)sizeof(v) +#define STBTT__NOTUSED(v) (void)sizeof(v) #endif ////////////////////////////////////////////////////////////////////////// @@ -1130,145 +1162,138 @@ typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERS // stbtt__buf helpers to parse data from file // -static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) -{ - if (b->cursor >= b->size) - return 0; - return b->data[b->cursor++]; +static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) { + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor++]; } -static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) -{ - if (b->cursor >= b->size) - return 0; - return b->data[b->cursor]; +static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) { + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor]; } -static void stbtt__buf_seek(stbtt__buf *b, int o) -{ - STBTT_assert(!(o > b->size || o < 0)); - b->cursor = (o > b->size || o < 0) ? b->size : o; +static void stbtt__buf_seek(stbtt__buf *b, int o) { + STBTT_assert(!(o > b->size || o < 0)); + b->cursor = (o > b->size || o < 0) ? b->size : o; } -static void stbtt__buf_skip(stbtt__buf *b, int o) -{ - stbtt__buf_seek(b, b->cursor + o); -} +static void stbtt__buf_skip(stbtt__buf *b, int o) { stbtt__buf_seek(b, b->cursor + o); } -static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) -{ - stbtt_uint32 v = 0; - int i; - STBTT_assert(n >= 1 && n <= 4); - for (i = 0; i < n; i++) - v = (v << 8) | stbtt__buf_get8(b); - return v; +static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) { + stbtt_uint32 v = 0; + int i; + STBTT_assert(n >= 1 && n <= 4); + for (i = 0; i < n; i++) + v = (v << 8) | stbtt__buf_get8(b); + return v; } -static stbtt__buf stbtt__new_buf(const void *p, size_t size) -{ - stbtt__buf r; - STBTT_assert(size < 0x40000000); - r.data = (stbtt_uint8*) p; - r.size = (int) size; - r.cursor = 0; - return r; +static stbtt__buf stbtt__new_buf(const void *p, size_t size) { + stbtt__buf r; + STBTT_assert(size < 0x40000000); + r.data = (stbtt_uint8 *)p; + r.size = (int)size; + r.cursor = 0; + return r; } -#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) -#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) +#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) +#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) -static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) -{ - stbtt__buf r = stbtt__new_buf(NULL, 0); - if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; - r.data = b->data + o; - r.size = s; - return r; +static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) { + stbtt__buf r = stbtt__new_buf(NULL, 0); + if (o < 0 || s < 0 || o > b->size || s > b->size - o) + return r; + r.data = b->data + o; + r.size = s; + return r; } -static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) -{ - int count, start, offsize; - start = b->cursor; - count = stbtt__buf_get16(b); - if (count) { - offsize = stbtt__buf_get8(b); - STBTT_assert(offsize >= 1 && offsize <= 4); - stbtt__buf_skip(b, offsize * count); - stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); - } - return stbtt__buf_range(b, start, b->cursor - start); +static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) { + int count, start, offsize; + start = b->cursor; + count = stbtt__buf_get16(b); + if (count) { + offsize = stbtt__buf_get8(b); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(b, offsize * count); + stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); + } + return stbtt__buf_range(b, start, b->cursor - start); } -static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) -{ - int b0 = stbtt__buf_get8(b); - if (b0 >= 32 && b0 <= 246) return b0 - 139; - else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; - else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; - else if (b0 == 28) return stbtt__buf_get16(b); - else if (b0 == 29) return stbtt__buf_get32(b); - STBTT_assert(0); - return 0; +static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) { + int b0 = stbtt__buf_get8(b); + if (b0 >= 32 && b0 <= 246) + return b0 - 139; + else if (b0 >= 247 && b0 <= 250) + return (b0 - 247) * 256 + stbtt__buf_get8(b) + 108; + else if (b0 >= 251 && b0 <= 254) + return -(b0 - 251) * 256 - stbtt__buf_get8(b) - 108; + else if (b0 == 28) + return stbtt__buf_get16(b); + else if (b0 == 29) + return stbtt__buf_get32(b); + STBTT_assert(0); + return 0; } static void stbtt__cff_skip_operand(stbtt__buf *b) { - int v, b0 = stbtt__buf_peek8(b); - STBTT_assert(b0 >= 28); - if (b0 == 30) { - stbtt__buf_skip(b, 1); - while (b->cursor < b->size) { - v = stbtt__buf_get8(b); - if ((v & 0xF) == 0xF || (v >> 4) == 0xF) - break; - } - } else { - stbtt__cff_int(b); - } -} - -static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) -{ - stbtt__buf_seek(b, 0); - while (b->cursor < b->size) { - int start = b->cursor, end, op; - while (stbtt__buf_peek8(b) >= 28) - stbtt__cff_skip_operand(b); - end = b->cursor; - op = stbtt__buf_get8(b); - if (op == 12) op = stbtt__buf_get8(b) | 0x100; - if (op == key) return stbtt__buf_range(b, start, end-start); - } - return stbtt__buf_range(b, 0, 0); -} - -static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) -{ - int i; - stbtt__buf operands = stbtt__dict_get(b, key); - for (i = 0; i < outcount && operands.cursor < operands.size; i++) - out[i] = stbtt__cff_int(&operands); -} - -static int stbtt__cff_index_count(stbtt__buf *b) -{ - stbtt__buf_seek(b, 0); - return stbtt__buf_get16(b); -} - -static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) -{ - int count, offsize, start, end; - stbtt__buf_seek(&b, 0); - count = stbtt__buf_get16(&b); - offsize = stbtt__buf_get8(&b); - STBTT_assert(i >= 0 && i < count); - STBTT_assert(offsize >= 1 && offsize <= 4); - stbtt__buf_skip(&b, i*offsize); - start = stbtt__buf_get(&b, offsize); - end = stbtt__buf_get(&b, offsize); - return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); + int v, b0 = stbtt__buf_peek8(b); + STBTT_assert(b0 >= 28); + if (b0 == 30) { + stbtt__buf_skip(b, 1); + while (b->cursor < b->size) { + v = stbtt__buf_get8(b); + if ((v & 0xF) == 0xF || (v >> 4) == 0xF) + break; + } + } else { + stbtt__cff_int(b); + } +} + +static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) { + stbtt__buf_seek(b, 0); + while (b->cursor < b->size) { + int start = b->cursor, end, op; + while (stbtt__buf_peek8(b) >= 28) + stbtt__cff_skip_operand(b); + end = b->cursor; + op = stbtt__buf_get8(b); + if (op == 12) + op = stbtt__buf_get8(b) | 0x100; + if (op == key) + return stbtt__buf_range(b, start, end - start); + } + return stbtt__buf_range(b, 0, 0); +} + +static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) { + int i; + stbtt__buf operands = stbtt__dict_get(b, key); + for (i = 0; i < outcount && operands.cursor < operands.size; i++) + out[i] = stbtt__cff_int(&operands); +} + +static int stbtt__cff_index_count(stbtt__buf *b) { + stbtt__buf_seek(b, 0); + return stbtt__buf_get16(b); +} + +static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) { + int count, offsize, start, end; + stbtt__buf_seek(&b, 0); + count = stbtt__buf_get16(&b); + offsize = stbtt__buf_get8(&b); + STBTT_assert(i >= 0 && i < count); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(&b, i * offsize); + start = stbtt__buf_get(&b, offsize); + end = stbtt__buf_get(&b, offsize); + return stbtt__buf_range(&b, 2 + (count + 1) * offsize + start, end - start); } ////////////////////////////////////////////////////////////////////////// @@ -1279,1438 +1304,1495 @@ static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) // on platforms that don't allow misaligned reads, if we want to allow // truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE -#define ttBYTE(p) (* (stbtt_uint8 *) (p)) -#define ttCHAR(p) (* (stbtt_int8 *) (p)) -#define ttFixed(p) ttLONG(p) - -static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } -static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } -static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } -static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } - -#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) -#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) - -static int stbtt__isfont(stbtt_uint8 *font) -{ - // check the version number - if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 - if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! - if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF - if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 - if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts - return 0; +#define ttBYTE(p) (*(stbtt_uint8 *)(p)) +#define ttCHAR(p) (*(stbtt_int8 *)(p)) +#define ttFixed(p) ttLONG(p) + +static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0] * 256 + p[1]; } +static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0] * 256 + p[1]; } +static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; } +static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; } + +#define stbtt_tag4(p, c0, c1, c2, c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) +#define stbtt_tag(p, str) stbtt_tag4(p, str[0], str[1], str[2], str[3]) + +static int stbtt__isfont(stbtt_uint8 *font) { + // check the version number + if (stbtt_tag4(font, '1', 0, 0, 0)) + return 1; // TrueType 1 + if (stbtt_tag(font, "typ1")) + return 1; // TrueType with type 1 font -- we don't support this! + if (stbtt_tag(font, "OTTO")) + return 1; // OpenType with CFF + if (stbtt_tag4(font, 0, 1, 0, 0)) + return 1; // OpenType 1.0 + if (stbtt_tag(font, "true")) + return 1; // Apple specification for TrueType fonts + return 0; } // @OPTIMIZE: binary search -static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) -{ - stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); - stbtt_uint32 tabledir = fontstart + 12; - stbtt_int32 i; - for (i=0; i < num_tables; ++i) { - stbtt_uint32 loc = tabledir + 16*i; - if (stbtt_tag(data+loc+0, tag)) - return ttULONG(data+loc+8); - } - return 0; -} - -static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) -{ - // if it's just a font, there's only one valid index - if (stbtt__isfont(font_collection)) - return index == 0 ? 0 : -1; - - // check if it's a TTC - if (stbtt_tag(font_collection, "ttcf")) { - // version 1? - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - stbtt_int32 n = ttLONG(font_collection+8); - if (index >= n) - return -1; - return ttULONG(font_collection+12+index*4); - } - } - return -1; -} - -static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) -{ - // if it's just a font, there's only one valid font - if (stbtt__isfont(font_collection)) - return 1; - - // check if it's a TTC - if (stbtt_tag(font_collection, "ttcf")) { - // version 1? - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - return ttLONG(font_collection+8); - } - } - return 0; -} - -static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) -{ - stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; - stbtt__buf pdict; - stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); - if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); - pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); - stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); - if (!subrsoff) return stbtt__new_buf(NULL, 0); - stbtt__buf_seek(&cff, private_loc[1]+subrsoff); - return stbtt__cff_get_index(&cff); +static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) { + stbtt_int32 num_tables = ttUSHORT(data + fontstart + 4); + stbtt_uint32 tabledir = fontstart + 12; + stbtt_int32 i; + for (i = 0; i < num_tables; ++i) { + stbtt_uint32 loc = tabledir + 16 * i; + if (stbtt_tag(data + loc + 0, tag)) + return ttULONG(data + loc + 8); + } + return 0; +} + +static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) { + // if it's just a font, there's only one valid index + if (stbtt__isfont(font_collection)) + return index == 0 ? 0 : -1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection + 4) == 0x00010000 || ttULONG(font_collection + 4) == 0x00020000) { + stbtt_int32 n = ttLONG(font_collection + 8); + if (index >= n) + return -1; + return ttULONG(font_collection + 12 + index * 4); + } + } + return -1; +} + +static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) { + // if it's just a font, there's only one valid font + if (stbtt__isfont(font_collection)) + return 1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection + 4) == 0x00010000 || ttULONG(font_collection + 4) == 0x00020000) { + return ttLONG(font_collection + 8); + } + } + return 0; +} + +static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) { + stbtt_uint32 subrsoff = 0, private_loc[2] = {0, 0}; + stbtt__buf pdict; + stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); + if (!private_loc[1] || !private_loc[0]) + return stbtt__new_buf(NULL, 0); + pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); + stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); + if (!subrsoff) + return stbtt__new_buf(NULL, 0); + stbtt__buf_seek(&cff, private_loc[1] + subrsoff); + return stbtt__cff_get_index(&cff); } // since most people won't use this, find this table the first time it's needed -static int stbtt__get_svg(stbtt_fontinfo *info) -{ - stbtt_uint32 t; - if (info->svg < 0) { - t = stbtt__find_table(info->data, info->fontstart, "SVG "); - if (t) { - stbtt_uint32 offset = ttULONG(info->data + t + 2); - info->svg = t + offset; - } else { - info->svg = 0; - } - } - return info->svg; -} - -static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) -{ - stbtt_uint32 cmap, t; - stbtt_int32 i,numTables; - - info->data = data; - info->fontstart = fontstart; - info->cff = stbtt__new_buf(NULL, 0); - - cmap = stbtt__find_table(data, fontstart, "cmap"); // required - info->loca = stbtt__find_table(data, fontstart, "loca"); // required - info->head = stbtt__find_table(data, fontstart, "head"); // required - info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required - info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required - info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required - info->kern = stbtt__find_table(data, fontstart, "kern"); // not required - info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required - - if (!cmap || !info->head || !info->hhea || !info->hmtx) - return 0; - if (info->glyf) { - // required for truetype - if (!info->loca) return 0; - } else { - // initialization for CFF / Type2 fonts (OTF) - stbtt__buf b, topdict, topdictidx; - stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; - stbtt_uint32 cff; - - cff = stbtt__find_table(data, fontstart, "CFF "); - if (!cff) return 0; - - info->fontdicts = stbtt__new_buf(NULL, 0); - info->fdselect = stbtt__new_buf(NULL, 0); - - // @TODO this should use size from table (not 512MB) - info->cff = stbtt__new_buf(data+cff, 512*1024*1024); - b = info->cff; - - // read the header - stbtt__buf_skip(&b, 2); - stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize - - // @TODO the name INDEX could list multiple fonts, - // but we just use the first one. - stbtt__cff_get_index(&b); // name INDEX - topdictidx = stbtt__cff_get_index(&b); - topdict = stbtt__cff_index_get(topdictidx, 0); - stbtt__cff_get_index(&b); // string INDEX - info->gsubrs = stbtt__cff_get_index(&b); - - stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); - stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); - stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); - stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); - info->subrs = stbtt__get_subrs(b, topdict); - - // we only support Type 2 charstrings - if (cstype != 2) return 0; - if (charstrings == 0) return 0; - - if (fdarrayoff) { - // looks like a CID font - if (!fdselectoff) return 0; - stbtt__buf_seek(&b, fdarrayoff); - info->fontdicts = stbtt__cff_get_index(&b); - info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); - } +static int stbtt__get_svg(stbtt_fontinfo *info) { + stbtt_uint32 t; + if (info->svg < 0) { + t = stbtt__find_table(info->data, info->fontstart, "SVG "); + if (t) { + stbtt_uint32 offset = ttULONG(info->data + t + 2); + info->svg = t + offset; + } else { + info->svg = 0; + } + } + return info->svg; +} + +static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) { + stbtt_uint32 cmap, t; + stbtt_int32 i, numTables; + + info->data = data; + info->fontstart = fontstart; + info->cff = stbtt__new_buf(NULL, 0); + + cmap = stbtt__find_table(data, fontstart, "cmap"); // required + info->loca = stbtt__find_table(data, fontstart, "loca"); // required + info->head = stbtt__find_table(data, fontstart, "head"); // required + info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required + info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required + info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required + info->kern = stbtt__find_table(data, fontstart, "kern"); // not required + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required + + if (!cmap || !info->head || !info->hhea || !info->hmtx) + return 0; + if (info->glyf) { + // required for truetype + if (!info->loca) + return 0; + } else { + // initialization for CFF / Type2 fonts (OTF) + stbtt__buf b, topdict, topdictidx; + stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; + stbtt_uint32 cff; + + cff = stbtt__find_table(data, fontstart, "CFF "); + if (!cff) + return 0; - stbtt__buf_seek(&b, charstrings); - info->charstrings = stbtt__cff_get_index(&b); - } + info->fontdicts = stbtt__new_buf(NULL, 0); + info->fdselect = stbtt__new_buf(NULL, 0); + + // @TODO this should use size from table (not 512MB) + info->cff = stbtt__new_buf(data + cff, 512 * 1024 * 1024); + b = info->cff; + + // read the header + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize + + // @TODO the name INDEX could list multiple fonts, + // but we just use the first one. + stbtt__cff_get_index(&b); // name INDEX + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); // string INDEX + info->gsubrs = stbtt__cff_get_index(&b); + + stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); + stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); + stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); + stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); + info->subrs = stbtt__get_subrs(b, topdict); + + // we only support Type 2 charstrings + if (cstype != 2) + return 0; + if (charstrings == 0) + return 0; - t = stbtt__find_table(data, fontstart, "maxp"); - if (t) - info->numGlyphs = ttUSHORT(data+t+4); - else - info->numGlyphs = 0xffff; - - info->svg = -1; - - // find a cmap encoding table we understand *now* to avoid searching - // later. (todo: could make this installable) - // the same regardless of glyph. - numTables = ttUSHORT(data + cmap + 2); - info->index_map = 0; - for (i=0; i < numTables; ++i) { - stbtt_uint32 encoding_record = cmap + 4 + 8 * i; - // find an encoding we understand: - switch(ttUSHORT(data+encoding_record)) { - case STBTT_PLATFORM_ID_MICROSOFT: - switch (ttUSHORT(data+encoding_record+2)) { - case STBTT_MS_EID_UNICODE_BMP: - case STBTT_MS_EID_UNICODE_FULL: - // MS/Unicode - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; + if (fdarrayoff) { + // looks like a CID font + if (!fdselectoff) + return 0; + stbtt__buf_seek(&b, fdarrayoff); + info->fontdicts = stbtt__cff_get_index(&b); + info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size - fdselectoff); + } + + stbtt__buf_seek(&b, charstrings); + info->charstrings = stbtt__cff_get_index(&b); + } + + t = stbtt__find_table(data, fontstart, "maxp"); + if (t) + info->numGlyphs = ttUSHORT(data + t + 4); + else + info->numGlyphs = 0xffff; + + info->svg = -1; + + // find a cmap encoding table we understand *now* to avoid searching + // later. (todo: could make this installable) + // the same regardless of glyph. + numTables = ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i = 0; i < numTables; ++i) { + stbtt_uint32 encoding_record = cmap + 4 + 8 * i; + // find an encoding we understand: + switch (ttUSHORT(data + encoding_record)) { + case STBTT_PLATFORM_ID_MICROSOFT: + switch (ttUSHORT(data + encoding_record + 2)) { + case STBTT_MS_EID_UNICODE_BMP: + case STBTT_MS_EID_UNICODE_FULL: + // MS/Unicode + info->index_map = cmap + ttULONG(data + encoding_record + 4); + break; } break; case STBTT_PLATFORM_ID_UNICODE: // Mac/iOS has these // all the encodingIDs are unicode, so we don't bother to check it - info->index_map = cmap + ttULONG(data+encoding_record+4); + info->index_map = cmap + ttULONG(data + encoding_record + 4); break; - } - } - if (info->index_map == 0) - return 0; - - info->indexToLocFormat = ttUSHORT(data+info->head + 50); - return 1; -} - -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) -{ - stbtt_uint8 *data = info->data; - stbtt_uint32 index_map = info->index_map; - - stbtt_uint16 format = ttUSHORT(data + index_map + 0); - if (format == 0) { // apple byte encoding - stbtt_int32 bytes = ttUSHORT(data + index_map + 2); - if (unicode_codepoint < bytes-6) - return ttBYTE(data + index_map + 6 + unicode_codepoint); - return 0; - } else if (format == 6) { - stbtt_uint32 first = ttUSHORT(data + index_map + 6); - stbtt_uint32 count = ttUSHORT(data + index_map + 8); - if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) - return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); - return 0; - } else if (format == 2) { - STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean - return 0; - } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges - stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; - stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; - stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); - stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; - - // do a binary search of the segments - stbtt_uint32 endCount = index_map + 14; - stbtt_uint32 search = endCount; - - if (unicode_codepoint > 0xffff) - return 0; - - // they lie from endCount .. endCount + segCount - // but searchRange is the nearest power of two, so... - if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) - search += rangeShift*2; - - // now decrement to bias correctly to find smallest - search -= 2; - while (entrySelector) { - stbtt_uint16 end; - searchRange >>= 1; - end = ttUSHORT(data + search + searchRange*2); - if (unicode_codepoint > end) - search += searchRange*2; - --entrySelector; - } - search += 2; - - { - stbtt_uint16 offset, start, last; - stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); - - start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - last = ttUSHORT(data + endCount + 2*item); - if (unicode_codepoint < start || unicode_codepoint > last) + } + } + if (info->index_map == 0) + return 0; + + info->indexToLocFormat = ttUSHORT(data + info->head + 50); + return 1; +} + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) { + stbtt_uint8 *data = info->data; + stbtt_uint32 index_map = info->index_map; + + stbtt_uint16 format = ttUSHORT(data + index_map + 0); + if (format == 0) { // apple byte encoding + stbtt_int32 bytes = ttUSHORT(data + index_map + 2); + if (unicode_codepoint < bytes - 6) + return ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; + } else if (format == 6) { + stbtt_uint32 first = ttUSHORT(data + index_map + 6); + stbtt_uint32 count = ttUSHORT(data + index_map + 8); + if ((stbtt_uint32)unicode_codepoint >= first && (stbtt_uint32)unicode_codepoint < first + count) + return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first) * 2); + return 0; + } else if (format == 2) { + STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean + return 0; + } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges + stbtt_uint16 segcount = ttUSHORT(data + index_map + 6) >> 1; + stbtt_uint16 searchRange = ttUSHORT(data + index_map + 8) >> 1; + stbtt_uint16 entrySelector = ttUSHORT(data + index_map + 10); + stbtt_uint16 rangeShift = ttUSHORT(data + index_map + 12) >> 1; + + // do a binary search of the segments + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; + + if (unicode_codepoint > 0xffff) return 0; - offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); - - return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); - } - } else if (format == 12 || format == 13) { - stbtt_uint32 ngroups = ttULONG(data+index_map+12); - stbtt_int32 low,high; - low = 0; high = (stbtt_int32)ngroups; - // Binary search the right group. - while (low < high) { - stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high - stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); - stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); - if ((stbtt_uint32) unicode_codepoint < start_char) - high = mid; - else if ((stbtt_uint32) unicode_codepoint > end_char) - low = mid+1; - else { - stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); - if (format == 12) - return start_glyph + unicode_codepoint-start_char; - else // format == 13 - return start_glyph; - } - } - return 0; // not found - } - // @TODO - STBTT_assert(0); - return 0; + // they lie from endCount .. endCount + segCount + // but searchRange is the nearest power of two, so... + if (unicode_codepoint >= ttUSHORT(data + search + rangeShift * 2)) + search += rangeShift * 2; + + // now decrement to bias correctly to find smallest + search -= 2; + while (entrySelector) { + stbtt_uint16 end; + searchRange >>= 1; + end = ttUSHORT(data + search + searchRange * 2); + if (unicode_codepoint > end) + search += searchRange * 2; + --entrySelector; + } + search += 2; + + { + stbtt_uint16 offset, start, last; + stbtt_uint16 item = (stbtt_uint16)((search - endCount) >> 1); + + start = ttUSHORT(data + index_map + 14 + segcount * 2 + 2 + 2 * item); + last = ttUSHORT(data + endCount + 2 * item); + if (unicode_codepoint < start || unicode_codepoint > last) + return 0; + + offset = ttUSHORT(data + index_map + 14 + segcount * 6 + 2 + 2 * item); + if (offset == 0) + return (stbtt_uint16)(unicode_codepoint + ttSHORT(data + index_map + 14 + segcount * 4 + 2 + 2 * item)); + + return ttUSHORT(data + offset + (unicode_codepoint - start) * 2 + index_map + 14 + segcount * 6 + 2 + + 2 * item); + } + } else if (format == 12 || format == 13) { + stbtt_uint32 ngroups = ttULONG(data + index_map + 12); + stbtt_int32 low, high; + low = 0; + high = (stbtt_int32)ngroups; + // Binary search the right group. + while (low < high) { + stbtt_int32 mid = low + ((high - low) >> 1); // rounds down, so low <= mid < high + stbtt_uint32 start_char = ttULONG(data + index_map + 16 + mid * 12); + stbtt_uint32 end_char = ttULONG(data + index_map + 16 + mid * 12 + 4); + if ((stbtt_uint32)unicode_codepoint < start_char) + high = mid; + else if ((stbtt_uint32)unicode_codepoint > end_char) + low = mid + 1; + else { + stbtt_uint32 start_glyph = ttULONG(data + index_map + 16 + mid * 12 + 8); + if (format == 12) + return start_glyph + unicode_codepoint - start_char; + else // format == 13 + return start_glyph; + } + } + return 0; // not found + } + // @TODO + STBTT_assert(0); + return 0; } -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) -{ - return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) { + return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); } -static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) -{ - v->type = type; - v->x = (stbtt_int16) x; - v->y = (stbtt_int16) y; - v->cx = (stbtt_int16) cx; - v->cy = (stbtt_int16) cy; +static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, + stbtt_int32 cy) { + v->type = type; + v->x = (stbtt_int16)x; + v->y = (stbtt_int16)y; + v->cx = (stbtt_int16)cx; + v->cy = (stbtt_int16)cy; } -static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) -{ - int g1,g2; +static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) { + int g1, g2; - STBTT_assert(!info->cff.size); + STBTT_assert(!info->cff.size); - if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range - if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format + if (glyph_index >= info->numGlyphs) + return -1; // glyph index out of range + if (info->indexToLocFormat >= 2) + return -1; // unknown index->glyph map format - if (info->indexToLocFormat == 0) { - g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; - g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; - } else { - g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); - g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); - } + if (info->indexToLocFormat == 0) { + g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; + g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; + } else { + g1 = info->glyf + ttULONG(info->data + info->loca + glyph_index * 4); + g2 = info->glyf + ttULONG(info->data + info->loca + glyph_index * 4 + 4); + } - return g1==g2 ? -1 : g1; // if length is 0, return -1 + return g1 == g2 ? -1 : g1; // if length is 0, return -1 } static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - if (info->cff.size) { - stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); - } else { - int g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 0; - - if (x0) *x0 = ttSHORT(info->data + g + 2); - if (y0) *y0 = ttSHORT(info->data + g + 4); - if (x1) *x1 = ttSHORT(info->data + g + 6); - if (y1) *y1 = ttSHORT(info->data + g + 8); - } - return 1; -} - -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) -{ - return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); -} - -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt_int16 numberOfContours; - int g; - if (info->cff.size) - return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; - g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 1; - numberOfContours = ttSHORT(info->data + g); - return numberOfContours == 0; -} - -static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, - stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) -{ - if (start_off) { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); - } - return num_vertices; -} - -static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - stbtt_int16 numberOfContours; - stbtt_uint8 *endPtsOfContours; - stbtt_uint8 *data = info->data; - stbtt_vertex *vertices=0; - int num_vertices=0; - int g = stbtt__GetGlyfOffset(info, glyph_index); - - *pvertices = NULL; - - if (g < 0) return 0; - - numberOfContours = ttSHORT(data + g); - - if (numberOfContours > 0) { - stbtt_uint8 flags=0,flagcount; - stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; - stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; - stbtt_uint8 *points; - endPtsOfContours = (data + g + 10); - ins = ttUSHORT(data + g + 10 + numberOfContours * 2); - points = data + g + 10 + numberOfContours * 2 + 2 + ins; - - n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); - - m = n + 2*numberOfContours; // a loose bound on how many vertices we might need - vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); - if (vertices == 0) - return 0; - - next_move = 0; - flagcount=0; - - // in first pass, we load uninterpreted data into the allocated array - // above, shifted to the end of the array so we won't overwrite it when - // we create our final data starting from the front - - off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated - - // first load flags - - for (i=0; i < n; ++i) { - if (flagcount == 0) { - flags = *points++; - if (flags & 8) - flagcount = *points++; - } else - --flagcount; - vertices[off+i].type = flags; - } - - // now load x coordinates - x=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 2) { - stbtt_int16 dx = *points++; - x += (flags & 16) ? dx : -dx; // ??? - } else { - if (!(flags & 16)) { - x = x + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].x = (stbtt_int16) x; - } +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) { + if (info->cff.size) { + stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); + } else { + int g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) + return 0; - // now load y coordinates - y=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 4) { - stbtt_int16 dy = *points++; - y += (flags & 32) ? dy : -dy; // ??? - } else { - if (!(flags & 32)) { - y = y + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].y = (stbtt_int16) y; - } + if (x0) + *x0 = ttSHORT(info->data + g + 2); + if (y0) + *y0 = ttSHORT(info->data + g + 4); + if (x1) + *x1 = ttSHORT(info->data + g + 6); + if (y1) + *y1 = ttSHORT(info->data + g + 8); + } + return 1; +} + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) { + return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info, codepoint), x0, y0, x1, y1); +} + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) { + stbtt_int16 numberOfContours; + int g; + if (info->cff.size) + return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; + g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) + return 1; + numberOfContours = ttSHORT(info->data + g); + return numberOfContours == 0; +} + +static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, stbtt_int32 sx, + stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) { + if (start_off) { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx + scx) >> 1, (cy + scy) >> 1, cx, cy); + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, scx, scy); + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, cx, cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, sx, sy, 0, 0); + } + return num_vertices; +} + +static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) { + stbtt_int16 numberOfContours; + stbtt_uint8 *endPtsOfContours; + stbtt_uint8 *data = info->data; + stbtt_vertex *vertices = 0; + int num_vertices = 0; + int g = stbtt__GetGlyfOffset(info, glyph_index); + + *pvertices = NULL; + + if (g < 0) + return 0; + + numberOfContours = ttSHORT(data + g); + + if (numberOfContours > 0) { + stbtt_uint8 flags = 0, flagcount; + stbtt_int32 ins, i, j = 0, m, n, next_move, was_off = 0, off, start_off = 0; + stbtt_int32 x, y, cx, cy, sx, sy, scx, scy; + stbtt_uint8 *points; + endPtsOfContours = (data + g + 10); + ins = ttUSHORT(data + g + 10 + numberOfContours * 2); + points = data + g + 10 + numberOfContours * 2 + 2 + ins; + + n = 1 + ttUSHORT(endPtsOfContours + numberOfContours * 2 - 2); + + m = n + 2 * numberOfContours; // a loose bound on how many vertices we might need + vertices = (stbtt_vertex *)STBTT_malloc(m * sizeof(vertices[0]), info->userdata); + if (vertices == 0) + return 0; - // now convert them to our format - num_vertices=0; - sx = sy = cx = cy = scx = scy = 0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - x = (stbtt_int16) vertices[off+i].x; - y = (stbtt_int16) vertices[off+i].y; - - if (next_move == i) { - if (i != 0) - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - - // now start the new one - start_off = !(flags & 1); - if (start_off) { - // if we start off with an off-curve point, then when we need to find a point on the curve - // where we can start, and we need to save some state for when we wraparound. - scx = x; - scy = y; - if (!(vertices[off+i+1].type & 1)) { - // next point is also a curve point, so interpolate an on-point curve - sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; - sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; - } else { - // otherwise just use the next point as our start point - sx = (stbtt_int32) vertices[off+i+1].x; - sy = (stbtt_int32) vertices[off+i+1].y; - ++i; // we're using point i+1 as the starting point, so skip it - } + next_move = 0; + flagcount = 0; + + // in first pass, we load uninterpreted data into the allocated array + // above, shifted to the end of the array so we won't overwrite it when + // we create our final data starting from the front + + off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated + + // first load flags + + for (i = 0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else + --flagcount; + vertices[off + i].type = flags; + } + + // now load x coordinates + x = 0; + for (i = 0; i < n; ++i) { + flags = vertices[off + i].type; + if (flags & 2) { + stbtt_int16 dx = *points++; + x += (flags & 16) ? dx : -dx; // ??? } else { - sx = x; - sy = y; + if (!(flags & 16)) { + x = x + (stbtt_int16)(points[0] * 256 + points[1]); + points += 2; + } } - stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); - was_off = 0; - next_move = 1 + ttUSHORT(endPtsOfContours+j*2); - ++j; - } else { - if (!(flags & 1)) { // if it's a curve - if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); - cx = x; - cy = y; - was_off = 1; + vertices[off + i].x = (stbtt_int16)x; + } + + // now load y coordinates + y = 0; + for (i = 0; i < n; ++i) { + flags = vertices[off + i].type; + if (flags & 4) { + stbtt_int16 dy = *points++; + y += (flags & 32) ? dy : -dy; // ??? } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); - was_off = 0; + if (!(flags & 32)) { + y = y + (stbtt_int16)(points[0] * 256 + points[1]); + points += 2; + } } - } - } - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - } else if (numberOfContours < 0) { - // Compound shapes. - int more = 1; - stbtt_uint8 *comp = data + g + 10; - num_vertices = 0; - vertices = 0; - while (more) { - stbtt_uint16 flags, gidx; - int comp_num_verts = 0, i; - stbtt_vertex *comp_verts = 0, *tmp = 0; - float mtx[6] = {1,0,0,1,0,0}, m, n; - - flags = ttSHORT(comp); comp+=2; - gidx = ttSHORT(comp); comp+=2; - - if (flags & 2) { // XY values - if (flags & 1) { // shorts - mtx[4] = ttSHORT(comp); comp+=2; - mtx[5] = ttSHORT(comp); comp+=2; + vertices[off + i].y = (stbtt_int16)y; + } + + // now convert them to our format + num_vertices = 0; + sx = sy = cx = cy = scx = scy = 0; + for (i = 0; i < n; ++i) { + flags = vertices[off + i].type; + x = (stbtt_int16)vertices[off + i].x; + y = (stbtt_int16)vertices[off + i].y; + + if (next_move == i) { + if (i != 0) + num_vertices = + stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy); + + // now start the new one + start_off = !(flags & 1); + if (start_off) { + // if we start off with an off-curve point, then when we need to find a point on the curve + // where we can start, and we need to save some state for when we wraparound. + scx = x; + scy = y; + if (!(vertices[off + i + 1].type & 1)) { + // next point is also a curve point, so interpolate an on-point curve + sx = (x + (stbtt_int32)vertices[off + i + 1].x) >> 1; + sy = (y + (stbtt_int32)vertices[off + i + 1].y) >> 1; + } else { + // otherwise just use the next point as our start point + sx = (stbtt_int32)vertices[off + i + 1].x; + sy = (stbtt_int32)vertices[off + i + 1].y; + ++i; // we're using point i+1 as the starting point, so skip it + } + } else { + sx = x; + sy = y; + } + stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove, sx, sy, 0, 0); + was_off = 0; + next_move = 1 + ttUSHORT(endPtsOfContours + j * 2); + ++j; } else { - mtx[4] = ttCHAR(comp); comp+=1; - mtx[5] = ttCHAR(comp); comp+=1; + if (!(flags & 1)) { // if it's a curve + if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx + x) >> 1, (cy + y) >> 1, cx, cy); + cx = x; + cy = y; + was_off = 1; + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x, y, cx, cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x, y, 0, 0); + was_off = 0; + } } - } - else { - // @TODO handle matching point - STBTT_assert(0); - } - if (flags & (1<<3)) { // WE_HAVE_A_SCALE - mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } - - // Find transformation scales. - m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); - n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); - - // Get indexed glyph. - comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); - if (comp_num_verts > 0) { - // Transform vertices. - for (i = 0; i < comp_num_verts; ++i) { - stbtt_vertex* v = &comp_verts[i]; - stbtt_vertex_type x,y; - x=v->x; y=v->y; - v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - x=v->cx; y=v->cy; - v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + } + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy); + } else if (numberOfContours < 0) { + // Compound shapes. + int more = 1; + stbtt_uint8 *comp = data + g + 10; + num_vertices = 0; + vertices = 0; + while (more) { + stbtt_uint16 flags, gidx; + int comp_num_verts = 0, i; + stbtt_vertex *comp_verts = 0, *tmp = 0; + float mtx[6] = {1, 0, 0, 1, 0, 0}, m, n; + + flags = ttSHORT(comp); + comp += 2; + gidx = ttSHORT(comp); + comp += 2; + + if (flags & 2) { // XY values + if (flags & 1) { // shorts + mtx[4] = ttSHORT(comp); + comp += 2; + mtx[5] = ttSHORT(comp); + comp += 2; + } else { + mtx[4] = ttCHAR(comp); + comp += 1; + mtx[5] = ttCHAR(comp); + comp += 1; + } + } else { + // @TODO handle matching point + STBTT_assert(0); } - // Append vertices. - tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); - if (!tmp) { - if (vertices) STBTT_free(vertices, info->userdata); - if (comp_verts) STBTT_free(comp_verts, info->userdata); - return 0; + if (flags & (1 << 3)) { // WE_HAVE_A_SCALE + mtx[0] = mtx[3] = ttSHORT(comp) / 16384.0f; + comp += 2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1 << 6)) { // WE_HAVE_AN_X_AND_YSCALE + mtx[0] = ttSHORT(comp) / 16384.0f; + comp += 2; + mtx[1] = mtx[2] = 0; + mtx[3] = ttSHORT(comp) / 16384.0f; + comp += 2; + } else if (flags & (1 << 7)) { // WE_HAVE_A_TWO_BY_TWO + mtx[0] = ttSHORT(comp) / 16384.0f; + comp += 2; + mtx[1] = ttSHORT(comp) / 16384.0f; + comp += 2; + mtx[2] = ttSHORT(comp) / 16384.0f; + comp += 2; + mtx[3] = ttSHORT(comp) / 16384.0f; + comp += 2; } - if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); - STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); - if (vertices) STBTT_free(vertices, info->userdata); - vertices = tmp; - STBTT_free(comp_verts, info->userdata); - num_vertices += comp_num_verts; - } - // More components ? - more = flags & (1<<5); - } - } else { - // numberOfCounters == 0, do nothing - } - *pvertices = vertices; - return num_vertices; -} - -typedef struct -{ - int bounds; - int started; - float first_x, first_y; - float x, y; - stbtt_int32 min_x, max_x, min_y, max_y; - - stbtt_vertex *pvertices; - int num_vertices; + // Find transformation scales. + m = (float)STBTT_sqrt(mtx[0] * mtx[0] + mtx[1] * mtx[1]); + n = (float)STBTT_sqrt(mtx[2] * mtx[2] + mtx[3] * mtx[3]); + + // Get indexed glyph. + comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); + if (comp_num_verts > 0) { + // Transform vertices. + for (i = 0; i < comp_num_verts; ++i) { + stbtt_vertex *v = &comp_verts[i]; + stbtt_vertex_type x, y; + x = v->x; + y = v->y; + v->x = (stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] * y + mtx[4])); + v->y = (stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] * y + mtx[5])); + x = v->cx; + y = v->cy; + v->cx = (stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] * y + mtx[4])); + v->cy = (stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] * y + mtx[5])); + } + // Append vertices. + tmp = (stbtt_vertex *)STBTT_malloc((num_vertices + comp_num_verts) * sizeof(stbtt_vertex), + info->userdata); + if (!tmp) { + if (vertices) + STBTT_free(vertices, info->userdata); + if (comp_verts) + STBTT_free(comp_verts, info->userdata); + return 0; + } + if (num_vertices > 0 && vertices) + STBTT_memcpy(tmp, vertices, num_vertices * sizeof(stbtt_vertex)); + STBTT_memcpy(tmp + num_vertices, comp_verts, comp_num_verts * sizeof(stbtt_vertex)); + if (vertices) + STBTT_free(vertices, info->userdata); + vertices = tmp; + STBTT_free(comp_verts, info->userdata); + num_vertices += comp_num_verts; + } + // More components ? + more = flags & (1 << 5); + } + } else { + // numberOfCounters == 0, do nothing + } + + *pvertices = vertices; + return num_vertices; +} + +typedef struct { + int bounds; + int started; + float first_x, first_y; + float x, y; + stbtt_int32 min_x, max_x, min_y, max_y; + + stbtt_vertex *pvertices; + int num_vertices; } stbtt__csctx; -#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} - -static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) -{ - if (x > c->max_x || !c->started) c->max_x = x; - if (y > c->max_y || !c->started) c->max_y = y; - if (x < c->min_x || !c->started) c->min_x = x; - if (y < c->min_y || !c->started) c->min_y = y; - c->started = 1; -} - -static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) -{ - if (c->bounds) { - stbtt__track_vertex(c, x, y); - if (type == STBTT_vcubic) { - stbtt__track_vertex(c, cx, cy); - stbtt__track_vertex(c, cx1, cy1); - } - } else { - stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); - c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; - c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; - } - c->num_vertices++; -} - -static void stbtt__csctx_close_shape(stbtt__csctx *ctx) -{ - if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) -{ - stbtt__csctx_close_shape(ctx); - ctx->first_x = ctx->x = ctx->x + dx; - ctx->first_y = ctx->y = ctx->y + dy; - stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +#define STBTT__CSCTX_INIT(bounds) \ + { bounds, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0 } + +static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) { + if (x > c->max_x || !c->started) + c->max_x = x; + if (y > c->max_y || !c->started) + c->max_y = y; + if (x < c->min_x || !c->started) + c->min_x = x; + if (y < c->min_y || !c->started) + c->min_y = y; + c->started = 1; +} + +static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, + stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) { + if (c->bounds) { + stbtt__track_vertex(c, x, y); + if (type == STBTT_vcubic) { + stbtt__track_vertex(c, cx, cy); + stbtt__track_vertex(c, cx1, cy1); + } + } else { + stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); + c->pvertices[c->num_vertices].cx1 = (stbtt_int16)cx1; + c->pvertices[c->num_vertices].cy1 = (stbtt_int16)cy1; + } + c->num_vertices++; +} + +static void stbtt__csctx_close_shape(stbtt__csctx *ctx) { + if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) { + stbtt__csctx_close_shape(ctx); + ctx->first_x = ctx->x = ctx->x + dx; + ctx->first_y = ctx->y = ctx->y + dy; + stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) { + ctx->x += dx; + ctx->y += dy; + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, + float dy3) { + float cx1 = ctx->x + dx1; + float cy1 = ctx->y + dy1; + float cx2 = cx1 + dx2; + float cy2 = cy1 + dy2; + ctx->x = cx2 + dx3; + ctx->y = cy2 + dy3; + stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); +} + +static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) { + int count = stbtt__cff_index_count(&idx); + int bias = 107; + if (count >= 33900) + bias = 32768; + else if (count >= 1240) + bias = 1131; + n += bias; + if (n < 0 || n >= count) + return stbtt__new_buf(NULL, 0); + return stbtt__cff_index_get(idx, n); +} + +static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) { + stbtt__buf fdselect = info->fdselect; + int nranges, start, end, v, fmt, fdselector = -1, i; + + stbtt__buf_seek(&fdselect, 0); + fmt = stbtt__buf_get8(&fdselect); + if (fmt == 0) { + // untested + stbtt__buf_skip(&fdselect, glyph_index); + fdselector = stbtt__buf_get8(&fdselect); + } else if (fmt == 3) { + nranges = stbtt__buf_get16(&fdselect); + start = stbtt__buf_get16(&fdselect); + for (i = 0; i < nranges; i++) { + v = stbtt__buf_get8(&fdselect); + end = stbtt__buf_get16(&fdselect); + if (glyph_index >= start && glyph_index < end) { + fdselector = v; + break; + } + start = end; + } + } + if (fdselector == -1) + stbtt__new_buf(NULL, 0); + return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); } -static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) -{ - ctx->x += dx; - ctx->y += dy; - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); -} +static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) { + int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; + int has_subrs = 0, clear_stack; + float s[48]; + stbtt__buf subr_stack[10], subrs = info->subrs, b; + float f; -static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) -{ - float cx1 = ctx->x + dx1; - float cy1 = ctx->y + dy1; - float cx2 = cx1 + dx2; - float cy2 = cy1 + dy2; - ctx->x = cx2 + dx3; - ctx->y = cy2 + dy3; - stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); -} +#define STBTT__CSERR(s) (0) -static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) -{ - int count = stbtt__cff_index_count(&idx); - int bias = 107; - if (count >= 33900) - bias = 32768; - else if (count >= 1240) - bias = 1131; - n += bias; - if (n < 0 || n >= count) - return stbtt__new_buf(NULL, 0); - return stbtt__cff_index_get(idx, n); -} - -static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt__buf fdselect = info->fdselect; - int nranges, start, end, v, fmt, fdselector = -1, i; - - stbtt__buf_seek(&fdselect, 0); - fmt = stbtt__buf_get8(&fdselect); - if (fmt == 0) { - // untested - stbtt__buf_skip(&fdselect, glyph_index); - fdselector = stbtt__buf_get8(&fdselect); - } else if (fmt == 3) { - nranges = stbtt__buf_get16(&fdselect); - start = stbtt__buf_get16(&fdselect); - for (i = 0; i < nranges; i++) { - v = stbtt__buf_get8(&fdselect); - end = stbtt__buf_get16(&fdselect); - if (glyph_index >= start && glyph_index < end) { - fdselector = v; + // this currently ignores the initial width value, which isn't needed if we have hmtx + b = stbtt__cff_index_get(info->charstrings, glyph_index); + while (b.cursor < b.size) { + i = 0; + clear_stack = 1; + b0 = stbtt__buf_get8(&b); + switch (b0) { + // @TODO implement hinting + case 0x13: // hintmask + case 0x14: // cntrmask + if (in_header) + maskbits += (sp / 2); // implicit "vstem" + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); break; - } - start = end; - } - } - if (fdselector == -1) stbtt__new_buf(NULL, 0); - return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); -} - -static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) -{ - int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; - int has_subrs = 0, clear_stack; - float s[48]; - stbtt__buf subr_stack[10], subrs = info->subrs, b; - float f; - -#define STBTT__CSERR(s) (0) - // this currently ignores the initial width value, which isn't needed if we have hmtx - b = stbtt__cff_index_get(info->charstrings, glyph_index); - while (b.cursor < b.size) { - i = 0; - clear_stack = 1; - b0 = stbtt__buf_get8(&b); - switch (b0) { - // @TODO implement hinting - case 0x13: // hintmask - case 0x14: // cntrmask - if (in_header) - maskbits += (sp / 2); // implicit "vstem" - in_header = 0; - stbtt__buf_skip(&b, (maskbits + 7) / 8); - break; - - case 0x01: // hstem - case 0x03: // vstem - case 0x12: // hstemhm - case 0x17: // vstemhm - maskbits += (sp / 2); - break; - - case 0x15: // rmoveto - in_header = 0; - if (sp < 2) return STBTT__CSERR("rmoveto stack"); - stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); - break; - case 0x04: // vmoveto - in_header = 0; - if (sp < 1) return STBTT__CSERR("vmoveto stack"); - stbtt__csctx_rmove_to(c, 0, s[sp-1]); - break; - case 0x16: // hmoveto - in_header = 0; - if (sp < 1) return STBTT__CSERR("hmoveto stack"); - stbtt__csctx_rmove_to(c, s[sp-1], 0); - break; - - case 0x05: // rlineto - if (sp < 2) return STBTT__CSERR("rlineto stack"); - for (; i + 1 < sp; i += 2) - stbtt__csctx_rline_to(c, s[i], s[i+1]); - break; - - // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical - // starting from a different place. - - case 0x07: // vlineto - if (sp < 1) return STBTT__CSERR("vlineto stack"); - goto vlineto; - case 0x06: // hlineto - if (sp < 1) return STBTT__CSERR("hlineto stack"); - for (;;) { - if (i >= sp) break; - stbtt__csctx_rline_to(c, s[i], 0); - i++; - vlineto: - if (i >= sp) break; - stbtt__csctx_rline_to(c, 0, s[i]); - i++; - } - break; - - case 0x1F: // hvcurveto - if (sp < 4) return STBTT__CSERR("hvcurveto stack"); - goto hvcurveto; - case 0x1E: // vhcurveto - if (sp < 4) return STBTT__CSERR("vhcurveto stack"); - for (;;) { - if (i + 3 >= sp) break; - stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); - i += 4; - hvcurveto: - if (i + 3 >= sp) break; - stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); - i += 4; - } - break; - - case 0x08: // rrcurveto - if (sp < 6) return STBTT__CSERR("rcurveline stack"); - for (; i + 5 < sp; i += 6) - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - break; - - case 0x18: // rcurveline - if (sp < 8) return STBTT__CSERR("rcurveline stack"); - for (; i + 5 < sp - 2; i += 6) - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); - stbtt__csctx_rline_to(c, s[i], s[i+1]); - break; - - case 0x19: // rlinecurve - if (sp < 8) return STBTT__CSERR("rlinecurve stack"); - for (; i + 1 < sp - 6; i += 2) - stbtt__csctx_rline_to(c, s[i], s[i+1]); - if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - break; - - case 0x1A: // vvcurveto - case 0x1B: // hhcurveto - if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); - f = 0.0; - if (sp & 1) { f = s[i]; i++; } - for (; i + 3 < sp; i += 4) { - if (b0 == 0x1B) - stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); - else - stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); - f = 0.0; - } - break; - - case 0x0A: // callsubr - if (!has_subrs) { - if (info->fdselect.size) - subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); - has_subrs = 1; - } - // FALLTHROUGH - case 0x1D: // callgsubr - if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); - v = (int) s[--sp]; - if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); - subr_stack[subr_stack_height++] = b; - b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); - if (b.size == 0) return STBTT__CSERR("subr not found"); - b.cursor = 0; - clear_stack = 0; - break; - - case 0x0B: // return - if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); - b = subr_stack[--subr_stack_height]; - clear_stack = 0; - break; - - case 0x0E: // endchar - stbtt__csctx_close_shape(c); - return 1; - - case 0x0C: { // two-byte escape - float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; - float dx, dy; - int b1 = stbtt__buf_get8(&b); - switch (b1) { - // @TODO These "flex" implementations ignore the flex-depth and resolution, - // and always draw beziers. - case 0x22: // hflex - if (sp < 7) return STBTT__CSERR("hflex stack"); - dx1 = s[0]; - dx2 = s[1]; - dy2 = s[2]; - dx3 = s[3]; - dx4 = s[4]; - dx5 = s[5]; - dx6 = s[6]; - stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + case 0x01: // hstem + case 0x03: // vstem + case 0x12: // hstemhm + case 0x17: // vstemhm + maskbits += (sp / 2); break; - case 0x23: // flex - if (sp < 13) return STBTT__CSERR("flex stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dy3 = s[5]; - dx4 = s[6]; - dy4 = s[7]; - dx5 = s[8]; - dy5 = s[9]; - dx6 = s[10]; - dy6 = s[11]; - //fd is s[12] - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + case 0x15: // rmoveto + in_header = 0; + if (sp < 2) + return STBTT__CSERR("rmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp - 2], s[sp - 1]); + break; + case 0x04: // vmoveto + in_header = 0; + if (sp < 1) + return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp - 1]); + break; + case 0x16: // hmoveto + in_header = 0; + if (sp < 1) + return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp - 1], 0); break; - case 0x24: // hflex1 - if (sp < 9) return STBTT__CSERR("hflex1 stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dx4 = s[5]; - dx5 = s[6]; - dy5 = s[7]; - dx6 = s[8]; - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); + case 0x05: // rlineto + if (sp < 2) + return STBTT__CSERR("rlineto stack"); + for (; i + 1 < sp; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i + 1]); break; - case 0x25: // flex1 - if (sp < 11) return STBTT__CSERR("flex1 stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dy3 = s[5]; - dx4 = s[6]; - dy4 = s[7]; - dx5 = s[8]; - dy5 = s[9]; - dx6 = dy6 = s[10]; - dx = dx1+dx2+dx3+dx4+dx5; - dy = dy1+dy2+dy3+dy4+dy5; - if (STBTT_fabs(dx) > STBTT_fabs(dy)) - dy6 = -dy; - else - dx6 = -dx; - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical + // starting from a different place. + + case 0x07: // vlineto + if (sp < 1) + return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: // hlineto + if (sp < 1) + return STBTT__CSERR("hlineto stack"); + for (;;) { + if (i >= sp) + break; + stbtt__csctx_rline_to(c, s[i], 0); + i++; + vlineto: + if (i >= sp) + break; + stbtt__csctx_rline_to(c, 0, s[i]); + i++; + } break; - default: - return STBTT__CSERR("unimplemented"); - } - } break; - - default: - if (b0 != 255 && b0 != 28 && b0 < 32) - return STBTT__CSERR("reserved operator"); - - // push immediate - if (b0 == 255) { - f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; - } else { - stbtt__buf_skip(&b, -1); - f = (float)(stbtt_int16)stbtt__cff_int(&b); - } - if (sp >= 48) return STBTT__CSERR("push stack overflow"); - s[sp++] = f; - clear_stack = 0; - break; - } - if (clear_stack) sp = 0; - } - return STBTT__CSERR("no endchar"); + case 0x1F: // hvcurveto + if (sp < 4) + return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: // vhcurveto + if (sp < 4) + return STBTT__CSERR("vhcurveto stack"); + for (;;) { + if (i + 3 >= sp) + break; + stbtt__csctx_rccurve_to(c, 0, s[i], s[i + 1], s[i + 2], s[i + 3], (sp - i == 5) ? s[i + 4] : 0.0f); + i += 4; + hvcurveto: + if (i + 3 >= sp) + break; + stbtt__csctx_rccurve_to(c, s[i], 0, s[i + 1], s[i + 2], (sp - i == 5) ? s[i + 4] : 0.0f, s[i + 3]); + i += 4; + } + break; -#undef STBTT__CSERR -} + case 0x08: // rrcurveto + if (sp < 6) + return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i + 5]); + break; -static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - // runs the charstring twice, once to count and once to output (to avoid realloc) - stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); - stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); - if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { - *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); - output_ctx.pvertices = *pvertices; - if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { - STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); - return output_ctx.num_vertices; - } - } - *pvertices = NULL; - return 0; -} + case 0x18: // rcurveline + if (sp < 8) + return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp - 2; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i + 5]); + if (i + 1 >= sp) + return STBTT__CSERR("rcurveline stack"); + stbtt__csctx_rline_to(c, s[i], s[i + 1]); + break; -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - stbtt__csctx c = STBTT__CSCTX_INIT(1); - int r = stbtt__run_charstring(info, glyph_index, &c); - if (x0) *x0 = r ? c.min_x : 0; - if (y0) *y0 = r ? c.min_y : 0; - if (x1) *x1 = r ? c.max_x : 0; - if (y1) *y1 = r ? c.max_y : 0; - return r ? c.num_vertices : 0; -} + case 0x19: // rlinecurve + if (sp < 8) + return STBTT__CSERR("rlinecurve stack"); + for (; i + 1 < sp - 6; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i + 1]); + if (i + 5 >= sp) + return STBTT__CSERR("rlinecurve stack"); + stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i + 5]); + break; -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - if (!info->cff.size) - return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); - else - return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); -} + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) + return STBTT__CSERR("(vv|hh)curveto stack"); + f = 0.0; + if (sp & 1) { + f = s[i]; + i++; + } + for (; i + 3 < sp; i += 4) { + if (b0 == 0x1B) + stbtt__csctx_rccurve_to(c, s[i], f, s[i + 1], s[i + 2], s[i + 3], 0.0); + else + stbtt__csctx_rccurve_to(c, f, s[i], s[i + 1], s[i + 2], 0.0, s[i + 3]); + f = 0.0; + } + break; -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) -{ - stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); - if (glyph_index < numOfLongHorMetrics) { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); - } else { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); - } -} + case 0x0A: // callsubr + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + // FALLTHROUGH + case 0x1D: // callgsubr + if (sp < 1) + return STBTT__CSERR("call(g|)subr stack"); + v = (int)s[--sp]; + if (subr_stack_height >= 10) + return STBTT__CSERR("recursion limit"); + subr_stack[subr_stack_height++] = b; + b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); + if (b.size == 0) + return STBTT__CSERR("subr not found"); + b.cursor = 0; + clear_stack = 0; + break; -STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) -{ - stbtt_uint8 *data = info->data + info->kern; + case 0x0B: // return + if (subr_stack_height <= 0) + return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; + case 0x0E: // endchar + stbtt__csctx_close_shape(c); + return 1; + + case 0x0C: { // two-byte escape + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + // @TODO These "flex" implementations ignore the flex-depth and resolution, + // and always draw beziers. + case 0x22: // hflex + if (sp < 7) + return STBTT__CSERR("hflex stack"); + dx1 = s[0]; + dx2 = s[1]; + dy2 = s[2]; + dx3 = s[3]; + dx4 = s[4]; + dx5 = s[5]; + dx6 = s[6]; + stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + break; + + case 0x23: // flex + if (sp < 13) + return STBTT__CSERR("flex stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = s[10]; + dy6 = s[11]; + // fd is s[12] + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + case 0x24: // hflex1 + if (sp < 9) + return STBTT__CSERR("hflex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dx4 = s[5]; + dx5 = s[6]; + dy5 = s[7]; + dx6 = s[8]; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1 + dy2 + dy5)); + break; + + case 0x25: // flex1 + if (sp < 11) + return STBTT__CSERR("flex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = dy6 = s[10]; + dx = dx1 + dx2 + dx3 + dx4 + dx5; + dy = dy1 + dy2 + dy3 + dy4 + dy5; + if (STBTT_fabs(dx) > STBTT_fabs(dy)) + dy6 = -dy; + else + dx6 = -dx; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; - return ttUSHORT(data+10); -} + default: + return STBTT__CSERR("unimplemented"); + } + } break; -STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) -{ - stbtt_uint8 *data = info->data + info->kern; - int k, length; - - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; - - length = ttUSHORT(data+10); - if (table_length < length) - length = table_length; - - for (k = 0; k < length; k++) - { - table[k].glyph1 = ttUSHORT(data+18+(k*6)); - table[k].glyph2 = ttUSHORT(data+20+(k*6)); - table[k].advance = ttSHORT(data+22+(k*6)); - } + default: + if (b0 != 255 && b0 != 28 && b0 < 32) + return STBTT__CSERR("reserved operator"); - return length; -} + // push immediate + if (b0 == 255) { + f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; + } else { + stbtt__buf_skip(&b, -1); + f = (float)(stbtt_int16)stbtt__cff_int(&b); + } + if (sp >= 48) + return STBTT__CSERR("push stack overflow"); + s[sp++] = f; + clear_stack = 0; + break; + } + if (clear_stack) + sp = 0; + } + return STBTT__CSERR("no endchar"); -static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint8 *data = info->data + info->kern; - stbtt_uint32 needle, straw; - int l, r, m; - - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; - - l = 0; - r = ttUSHORT(data+10) - 1; - needle = glyph1 << 16 | glyph2; - while (l <= r) { - m = (l + r) >> 1; - straw = ttULONG(data+18+(m*6)); // note: unaligned read - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else - return ttSHORT(data+22+(m*6)); - } - return 0; +#undef STBTT__CSERR } -static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) -{ - stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); - switch (coverageFormat) { - case 1: { - stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); - - // Binary search. - stbtt_int32 l=0, r=glyphCount-1, m; - int straw, needle=glyph; - while (l <= r) { +static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) { + // runs the charstring twice, once to count and once to output (to avoid realloc) + stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); + stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); + if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { + *pvertices = (stbtt_vertex *)STBTT_malloc(count_ctx.num_vertices * sizeof(stbtt_vertex), info->userdata); + output_ctx.pvertices = *pvertices; + if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { + STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); + return output_ctx.num_vertices; + } + } + *pvertices = NULL; + return 0; +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) { + stbtt__csctx c = STBTT__CSCTX_INIT(1); + int r = stbtt__run_charstring(info, glyph_index, &c); + if (x0) + *x0 = r ? c.min_x : 0; + if (y0) + *y0 = r ? c.min_y : 0; + if (x1) + *x1 = r ? c.max_x : 0; + if (y1) + *y1 = r ? c.max_y : 0; + return r ? c.num_vertices : 0; +} + +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) { + if (!info->cff.size) + return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); + else + return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); +} + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, + int *leftSideBearing) { + stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data + info->hhea + 34); + if (glyph_index < numOfLongHorMetrics) { + if (advanceWidth) + *advanceWidth = ttSHORT(info->data + info->hmtx + 4 * glyph_index); + if (leftSideBearing) + *leftSideBearing = ttSHORT(info->data + info->hmtx + 4 * glyph_index + 2); + } else { + if (advanceWidth) + *advanceWidth = ttSHORT(info->data + info->hmtx + 4 * (numOfLongHorMetrics - 1)); + if (leftSideBearing) + *leftSideBearing = + ttSHORT(info->data + info->hmtx + 4 * numOfLongHorMetrics + 2 * (glyph_index - numOfLongHorMetrics)); + } +} + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) { + stbtt_uint8 *data = info->data + info->kern; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data + 2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data + 8) != 1) // horizontal flag must be set in format + return 0; + + return ttUSHORT(data + 10); +} + +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry *table, int table_length) { + stbtt_uint8 *data = info->data + info->kern; + int k, length; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data + 2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data + 8) != 1) // horizontal flag must be set in format + return 0; + + length = ttUSHORT(data + 10); + if (table_length < length) + length = table_length; + + for (k = 0; k < length; k++) { + table[k].glyph1 = ttUSHORT(data + 18 + (k * 6)); + table[k].glyph2 = ttUSHORT(data + 20 + (k * 6)); + table[k].advance = ttSHORT(data + 22 + (k * 6)); + } + + return length; +} + +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) { + stbtt_uint8 *data = info->data + info->kern; + stbtt_uint32 needle, straw; + int l, r, m; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data + 2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data + 8) != 1) // horizontal flag must be set in format + return 0; + + l = 0; + r = ttUSHORT(data + 10) - 1; + needle = glyph1 << 16 | glyph2; + while (l <= r) { + m = (l + r) >> 1; + straw = ttULONG(data + 18 + (m * 6)); // note: unaligned read + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else + return ttSHORT(data + 22 + (m * 6)); + } + return 0; +} + +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) { + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch (coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + + // Binary search. + stbtt_int32 l = 0, r = glyphCount - 1, m; + int straw, needle = glyph; + while (l <= r) { stbtt_uint8 *glyphArray = coverageTable + 4; stbtt_uint16 glyphID; - m = (l + r) >> 1; + m = (l + r) >> 1; glyphID = ttUSHORT(glyphArray + 2 * m); - straw = glyphID; + straw = glyphID; if (needle < straw) - r = m - 1; + r = m - 1; else if (needle > straw) - l = m + 1; + l = m + 1; else { - return m; + return m; } - } - break; - } - - case 2: { - stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); - stbtt_uint8 *rangeArray = coverageTable + 4; - - // Binary search. - stbtt_int32 l=0, r=rangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { + } + break; + } + + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; + + // Binary search. + stbtt_int32 l = 0, r = rangeCount - 1, m; + int strawStart, strawEnd, needle = glyph; + while (l <= r) { stbtt_uint8 *rangeRecord; - m = (l + r) >> 1; + m = (l + r) >> 1; rangeRecord = rangeArray + 6 * m; - strawStart = ttUSHORT(rangeRecord); - strawEnd = ttUSHORT(rangeRecord + 2); + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); if (needle < strawStart) - r = m - 1; + r = m - 1; else if (needle > strawEnd) - l = m + 1; + l = m + 1; else { - stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); - return startCoverageIndex + glyph - strawStart; + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; } - } - break; - } + } + break; + } - default: return -1; // unsupported - } + default: + return -1; // unsupported + } - return -1; + return -1; } -static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) -{ - stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); - switch (classDefFormat) - { - case 1: { - stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); - stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); - stbtt_uint8 *classDef1ValueArray = classDefTable + 6; - - if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) +static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) { + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch (classDefFormat) { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); - break; - } + break; + } - case 2: { - stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); - stbtt_uint8 *classRangeRecords = classDefTable + 4; + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; - // Binary search. - stbtt_int32 l=0, r=classRangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { + // Binary search. + stbtt_int32 l = 0, r = classRangeCount - 1, m; + int strawStart, strawEnd, needle = glyph; + while (l <= r) { stbtt_uint8 *classRangeRecord; - m = (l + r) >> 1; + m = (l + r) >> 1; classRangeRecord = classRangeRecords + 6 * m; - strawStart = ttUSHORT(classRangeRecord); - strawEnd = ttUSHORT(classRangeRecord + 2); + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); if (needle < strawStart) - r = m - 1; + r = m - 1; else if (needle > strawEnd) - l = m + 1; + l = m + 1; else - return (stbtt_int32)ttUSHORT(classRangeRecord + 4); - } - break; - } + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + break; + } - default: - return -1; // Unsupported definition type, return an error. - } + default: + return -1; // Unsupported definition type, return an error. + } - // "All glyphs not assigned to a class fall into class 0". (OpenType spec) - return 0; + // "All glyphs not assigned to a class fall into class 0". (OpenType spec) + return 0; } // Define to STBTT_assert(x) if you want to break on unimplemented formats. #define STBTT_GPOS_TODO_assert(x) -static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint16 lookupListOffset; - stbtt_uint8 *lookupList; - stbtt_uint16 lookupCount; - stbtt_uint8 *data; - stbtt_int32 i, sti; - - if (!info->gpos) return 0; - - data = info->data + info->gpos; - - if (ttUSHORT(data+0) != 1) return 0; // Major version 1 - if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 - - lookupListOffset = ttUSHORT(data+8); - lookupList = data + lookupListOffset; - lookupCount = ttUSHORT(lookupList); - - for (i=0; igpos) + return 0; + + data = info->data + info->gpos; + + if (ttUSHORT(data + 0) != 1) + return 0; // Major version 1 + if (ttUSHORT(data + 2) != 0) + return 0; // Minor version 0 + + lookupListOffset = ttUSHORT(data + 8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i = 0; i < lookupCount; ++i) { + stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i); + stbtt_uint8 *lookupTable = lookupList + lookupOffset; + + stbtt_uint16 lookupType = ttUSHORT(lookupTable); + stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4); + stbtt_uint8 *subTableOffsets = lookupTable + 6; + if (lookupType != 2) // Pair Adjustment Positioning Subtable + continue; + + for (sti = 0; sti < subTableCount; sti++) { + stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti); + stbtt_uint8 *table = lookupTable + subtableOffset; + stbtt_uint16 posFormat = ttUSHORT(table); + stbtt_uint16 coverageOffset = ttUSHORT(table + 2); + stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1); + if (coverageIndex == -1) + continue; + + switch (posFormat) { case 1: { - stbtt_int32 l, r, m; - int straw, needle; - stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); - stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); - if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? - stbtt_int32 valueRecordPairSizeInBytes = 2; - stbtt_uint16 pairSetCount = ttUSHORT(table + 8); - stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex); - stbtt_uint8 *pairValueTable = table + pairPosOffset; - stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable); - stbtt_uint8 *pairValueArray = pairValueTable + 2; - - if (coverageIndex >= pairSetCount) return 0; - - needle=glyph2; - r=pairValueCount-1; - l=0; - - // Binary search. - while (l <= r) { - stbtt_uint16 secondGlyph; - stbtt_uint8 *pairValue; - m = (l + r) >> 1; - pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; - secondGlyph = ttUSHORT(pairValue); - straw = secondGlyph; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - stbtt_int16 xAdvance = ttSHORT(pairValue + 2); - return xAdvance; - } - } - } else - return 0; - break; + stbtt_int32 l, r, m; + int straw, needle; + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? + stbtt_int32 valueRecordPairSizeInBytes = 2; + stbtt_uint16 pairSetCount = ttUSHORT(table + 8); + stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex); + stbtt_uint8 *pairValueTable = table + pairPosOffset; + stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable); + stbtt_uint8 *pairValueArray = pairValueTable + 2; + + if (coverageIndex >= pairSetCount) + return 0; + + needle = glyph2; + r = pairValueCount - 1; + l = 0; + + // Binary search. + while (l <= r) { + stbtt_uint16 secondGlyph; + stbtt_uint8 *pairValue; + m = (l + r) >> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; + } + } + } else + return 0; + break; } case 2: { - stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); - stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); - if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? - stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); - stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); - int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); - int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); - - stbtt_uint16 class1Count = ttUSHORT(table + 12); - stbtt_uint16 class2Count = ttUSHORT(table + 14); - stbtt_uint8 *class1Records, *class2Records; - stbtt_int16 xAdvance; - - if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed - if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed - - class1Records = table + 16; - class2Records = class1Records + 2 * (glyph1class * class2Count); - xAdvance = ttSHORT(class2Records + 2 * glyph2class); - return xAdvance; - } else - return 0; - break; + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + stbtt_uint8 *class1Records, *class2Records; + stbtt_int16 xAdvance; + + if (glyph1class < 0 || glyph1class >= class1Count) + return 0; // malformed + if (glyph2class < 0 || glyph2class >= class2Count) + return 0; // malformed + + class1Records = table + 16; + class2Records = class1Records + 2 * (glyph1class * class2Count); + xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } else + return 0; + break; } default: - return 0; // Unsupported position format - } - } - } + return 0; // Unsupported position format + } + } + } - return 0; + return 0; } -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) -{ - int xAdvance = 0; +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) { + int xAdvance = 0; - if (info->gpos) - xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); - else if (info->kern) - xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + else if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); - return xAdvance; + return xAdvance; } -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) -{ - if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs - return 0; - return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) { + if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs + return 0; + return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info, ch1), stbtt_FindGlyphIndex(info, ch2)); } -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) -{ - stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, + int *leftSideBearing) { + stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info, codepoint), advanceWidth, leftSideBearing); } -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) -{ - if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); - if (descent) *descent = ttSHORT(info->data+info->hhea + 6); - if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) { + if (ascent) + *ascent = ttSHORT(info->data + info->hhea + 4); + if (descent) + *descent = ttSHORT(info->data + info->hhea + 6); + if (lineGap) + *lineGap = ttSHORT(info->data + info->hhea + 8); } -STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) -{ - int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); - if (!tab) - return 0; - if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); - if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); - if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); - return 1; +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, + int *typoLineGap) { + int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); + if (!tab) + return 0; + if (typoAscent) + *typoAscent = ttSHORT(info->data + tab + 68); + if (typoDescent) + *typoDescent = ttSHORT(info->data + tab + 70); + if (typoLineGap) + *typoLineGap = ttSHORT(info->data + tab + 72); + return 1; } -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) -{ - *x0 = ttSHORT(info->data + info->head + 36); - *y0 = ttSHORT(info->data + info->head + 38); - *x1 = ttSHORT(info->data + info->head + 40); - *y1 = ttSHORT(info->data + info->head + 42); +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) { + *x0 = ttSHORT(info->data + info->head + 36); + *y0 = ttSHORT(info->data + info->head + 38); + *x1 = ttSHORT(info->data + info->head + 40); + *y1 = ttSHORT(info->data + info->head + 42); } -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) -{ - int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); - return (float) height / fheight; +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) { + int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); + return (float)height / fheight; } -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) -{ - int unitsPerEm = ttUSHORT(info->data + info->head + 18); - return pixels / unitsPerEm; +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) { + int unitsPerEm = ttUSHORT(info->data + info->head + 18); + return pixels / unitsPerEm; } -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) -{ - STBTT_free(v, info->userdata); -} +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) { STBTT_free(v, info->userdata); } -STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) -{ - int i; - stbtt_uint8 *data = info->data; - stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); +STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) { + int i; + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *)info); - int numEntries = ttUSHORT(svg_doc_list); - stbtt_uint8 *svg_docs = svg_doc_list + 2; + int numEntries = ttUSHORT(svg_doc_list); + stbtt_uint8 *svg_docs = svg_doc_list + 2; - for(i=0; i= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) - return svg_doc; - } - return 0; + for (i = 0; i < numEntries; i++) { + stbtt_uint8 *svg_doc = svg_docs + (12 * i); + if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) + return svg_doc; + } + return 0; } -STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) -{ - stbtt_uint8 *data = info->data; - stbtt_uint8 *svg_doc; - - if (info->svg == 0) - return 0; - - svg_doc = stbtt_FindSVGDoc(info, gl); - if (svg_doc != NULL) { - *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); - return ttULONG(svg_doc + 8); - } else { - return 0; - } +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) { + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc; + + if (info->svg == 0) + return 0; + + svg_doc = stbtt_FindSVGDoc(info, gl); + if (svg_doc != NULL) { + *svg = (char *)data + info->svg + ttULONG(svg_doc + 4); + return ttULONG(svg_doc + 8); + } else { + return 0; + } } -STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) -{ - return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) { + return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); } ////////////////////////////////////////////////////////////////////////////// @@ -2718,158 +2800,165 @@ STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_code // antialiasing software rasterizer // -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning - if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { - // e.g. space character - if (ix0) *ix0 = 0; - if (iy0) *iy0 = 0; - if (ix1) *ix1 = 0; - if (iy1) *iy1 = 0; - } else { - // move to integral bboxes (treating pixels as little squares, what pixels get touched)? - if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); - if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); - if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); - if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); - } -} - -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); -} - -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); -} - -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, + float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) { + int x0 = 0, y0 = 0, x1, y1; // =0 suppresses compiler warning + if (!stbtt_GetGlyphBox(font, glyph, &x0, &y0, &x1, &y1)) { + // e.g. space character + if (ix0) + *ix0 = 0; + if (iy0) + *iy0 = 0; + if (ix1) + *ix1 = 0; + if (iy1) + *iy1 = 0; + } else { + // move to integral bboxes (treating pixels as little squares, what pixels get touched)? + if (ix0) + *ix0 = STBTT_ifloor(x0 * scale_x + shift_x); + if (iy0) + *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); + if (ix1) + *ix1 = STBTT_iceil(x1 * scale_x + shift_x); + if (iy1) + *iy1 = STBTT_iceil(-y0 * scale_y + shift_y); + } +} + +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, + int *iy0, int *ix1, int *iy1) { + stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y, 0.0f, 0.0f, ix0, iy0, ix1, iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, + float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, + int *ix1, int *iy1) { + stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font, codepoint), scale_x, scale_y, shift_x, shift_y, + ix0, iy0, ix1, iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, + int *ix0, int *iy0, int *ix1, int *iy1) { + stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y, 0.0f, 0.0f, ix0, iy0, ix1, iy1); } ////////////////////////////////////////////////////////////////////////////// // // Rasterizer -typedef struct stbtt__hheap_chunk -{ - struct stbtt__hheap_chunk *next; +typedef struct stbtt__hheap_chunk { + struct stbtt__hheap_chunk *next; } stbtt__hheap_chunk; -typedef struct stbtt__hheap -{ - struct stbtt__hheap_chunk *head; - void *first_free; - int num_remaining_in_head_chunk; +typedef struct stbtt__hheap { + struct stbtt__hheap_chunk *head; + void *first_free; + int num_remaining_in_head_chunk; } stbtt__hheap; -static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) -{ - if (hh->first_free) { - void *p = hh->first_free; - hh->first_free = * (void **) p; - return p; - } else { - if (hh->num_remaining_in_head_chunk == 0) { - int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); - stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); - if (c == NULL) - return NULL; - c->next = hh->head; - hh->head = c; - hh->num_remaining_in_head_chunk = count; - } - --hh->num_remaining_in_head_chunk; - return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; - } -} - -static void stbtt__hheap_free(stbtt__hheap *hh, void *p) -{ - *(void **) p = hh->first_free; - hh->first_free = p; -} - -static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) -{ - stbtt__hheap_chunk *c = hh->head; - while (c) { - stbtt__hheap_chunk *n = c->next; - STBTT_free(c, userdata); - c = n; - } +static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) { + if (hh->first_free) { + void *p = hh->first_free; + hh->first_free = *(void **)p; + return p; + } else { + if (hh->num_remaining_in_head_chunk == 0) { + int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); + stbtt__hheap_chunk *c = + (stbtt__hheap_chunk *)STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); + if (c == NULL) + return NULL; + c->next = hh->head; + hh->head = c; + hh->num_remaining_in_head_chunk = count; + } + --hh->num_remaining_in_head_chunk; + return (char *)(hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; + } +} + +static void stbtt__hheap_free(stbtt__hheap *hh, void *p) { + *(void **)p = hh->first_free; + hh->first_free = p; +} + +static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) { + stbtt__hheap_chunk *c = hh->head; + while (c) { + stbtt__hheap_chunk *n = c->next; + STBTT_free(c, userdata); + c = n; + } } typedef struct stbtt__edge { - float x0,y0, x1,y1; - int invert; + float x0, y0, x1, y1; + int invert; } stbtt__edge; - -typedef struct stbtt__active_edge -{ - struct stbtt__active_edge *next; - #if STBTT_RASTERIZER_VERSION==1 - int x,dx; - float ey; - int direction; - #elif STBTT_RASTERIZER_VERSION==2 - float fx,fdx,fdy; - float direction; - float sy; - float ey; - #else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" - #endif +typedef struct stbtt__active_edge { + struct stbtt__active_edge *next; +#if STBTT_RASTERIZER_VERSION == 1 + int x, dx; + float ey; + int direction; +#elif STBTT_RASTERIZER_VERSION == 2 + float fx, fdx, fdy; + float direction; + float sy; + float ey; +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif } stbtt__active_edge; #if STBTT_RASTERIZER_VERSION == 1 -#define STBTT_FIXSHIFT 10 -#define STBTT_FIX (1 << STBTT_FIXSHIFT) -#define STBTT_FIXMASK (STBTT_FIX-1) - -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(z != NULL); - if (!z) return z; - - // round dx down to avoid overshooting - if (dxdy < 0) - z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); - else - z->dx = STBTT_ifloor(STBTT_FIX * dxdy); - - z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount - z->x -= off_x * STBTT_FIX; - - z->ey = e->y1; - z->next = 0; - z->direction = e->invert ? 1 : -1; - return z; +#define STBTT_FIXSHIFT 10 +#define STBTT_FIX (1 << STBTT_FIXSHIFT) +#define STBTT_FIXMASK (STBTT_FIX - 1) + +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, + void *userdata) { + stbtt__active_edge *z = (stbtt__active_edge *)stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + if (!z) + return z; + + // round dx down to avoid overshooting + if (dxdy < 0) + z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); + else + z->dx = STBTT_ifloor(STBTT_FIX * dxdy); + + z->x = STBTT_ifloor(STBTT_FIX * e->x0 + + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount + z->x -= off_x * STBTT_FIX; + + z->ey = e->y1; + z->next = 0; + z->direction = e->invert ? 1 : -1; + return z; } #elif STBTT_RASTERIZER_VERSION == 2 -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(z != NULL); - //STBTT_assert(e->y0 <= start_point); - if (!z) return z; - z->fdx = dxdy; - z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; - z->fx = e->x0 + dxdy * (start_point - e->y0); - z->fx -= off_x; - z->direction = e->invert ? 1.0f : -1.0f; - z->sy = e->y0; - z->ey = e->y1; - z->next = 0; - return z; +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, + void *userdata) { + stbtt__active_edge *z = (stbtt__active_edge *)stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + // STBTT_assert(e->y0 <= start_point); + if (!z) + return z; + z->fdx = dxdy; + z->fdy = dxdy != 0.0f ? (1.0f / dxdy) : 0.0f; + z->fx = e->x0 + dxdy * (start_point - e->y0); + z->fx -= off_x; + z->direction = e->invert ? 1.0f : -1.0f; + z->sy = e->y0; + z->ey = e->y1; + z->next = 0; + return z; } #else #error "Unrecognized value of STBTT_RASTERIZER_VERSION" @@ -2879,929 +2968,957 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i // note: this routine clips fills that extend off the edges... ideally this // wouldn't happen, but it could happen if the truetype glyph bounding boxes // are wrong, or if the user supplies a too-small bitmap -static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) -{ - // non-zero winding fill - int x0=0, w=0; - - while (e) { - if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w += e->direction; - } else { - int x1 = e->x; w += e->direction; - // if we went to zero, we need to draw - if (w == 0) { - int i = x0 >> STBTT_FIXSHIFT; - int j = x1 >> STBTT_FIXSHIFT; - - if (i < len && j >= 0) { - if (i == j) { - // x0,x1 are the same pixel, so compute combined coverage - scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); - } else { - if (i >= 0) // add antialiasing for x0 - scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); - else - i = -1; // clip - - if (j < len) // add antialiasing for x1 - scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); - else - j = len; // clip - - for (++i; i < j; ++i) // fill pixels between x0 and x1 - scanline[i] = scanline[i] + (stbtt_uint8) max_weight; - } +static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) { + // non-zero winding fill + int x0 = 0, w = 0; + + while (e) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; + w += e->direction; + } else { + int x1 = e->x; + w += e->direction; + // if we went to zero, we need to draw + if (w == 0) { + int i = x0 >> STBTT_FIXSHIFT; + int j = x1 >> STBTT_FIXSHIFT; + + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = scanline[i] + (stbtt_uint8)((x1 - x0) * max_weight >> STBTT_FIXSHIFT); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = + scanline[i] + + (stbtt_uint8)(((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = + scanline[j] + (stbtt_uint8)(((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = scanline[i] + (stbtt_uint8)max_weight; + } + } } - } - } - - e = e->next; - } -} - -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__hheap hh = { 0, 0, 0 }; - stbtt__active_edge *active = NULL; - int y,j=0; - int max_weight = (255 / vsubsample); // weight per vertical scanline - int s; // vertical subsample index - unsigned char scanline_data[512], *scanline; - - if (result->w > 512) - scanline = (unsigned char *) STBTT_malloc(result->w, userdata); - else - scanline = scanline_data; - - y = off_y * vsubsample; - e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; - - while (j < result->h) { - STBTT_memset(scanline, 0, result->w); - for (s=0; s < vsubsample; ++s) { - // find center of pixel for this scanline - float scan_y = y + 0.5f; - stbtt__active_edge **step = &active; - - // update all active edges; - // remove all active edges that terminate before the center of this scanline - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y) { - *step = z->next; // delete from list - STBTT_assert(z->direction); - z->direction = 0; - stbtt__hheap_free(&hh, z); - } else { - z->x += z->dx; // advance to position for current scanline - step = &((*step)->next); // advance through list + } + + e = e->next; + } +} + +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, + int off_y, void *userdata) { + stbtt__hheap hh = {0, 0, 0}; + stbtt__active_edge *active = NULL; + int y, j = 0; + int max_weight = (255 / vsubsample); // weight per vertical scanline + int s; // vertical subsample index + unsigned char scanline_data[512], *scanline; + + if (result->w > 512) + scanline = (unsigned char *)STBTT_malloc(result->w, userdata); + else + scanline = scanline_data; + + y = off_y * vsubsample; + e[n].y0 = (off_y + result->h) * (float)vsubsample + 1; + + while (j < result->h) { + STBTT_memset(scanline, 0, result->w); + for (s = 0; s < vsubsample; ++s) { + // find center of pixel for this scanline + float scan_y = y + 0.5f; + stbtt__active_edge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + stbtt__active_edge *z = *step; + if (z->ey <= scan_y) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } } - } - - // resort the list if needed - for(;;) { - int changed=0; - step = &active; - while (*step && (*step)->next) { - if ((*step)->x > (*step)->next->x) { - stbtt__active_edge *t = *step; - stbtt__active_edge *q = t->next; - - t->next = q->next; - q->next = t; - *step = q; - changed = 1; - } - step = &(*step)->next; + + // resort the list if needed + for (;;) { + int changed = 0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + stbtt__active_edge *t = *step; + stbtt__active_edge *q = t->next; + + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) + break; } - if (!changed) break; - } - - // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline - while (e->y0 <= scan_y) { - if (e->y1 > scan_y) { - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); - if (z != NULL) { - // find insertion point - if (active == NULL) - active = z; - else if (z->x < active->x) { - // insert at front - z->next = active; - active = z; - } else { - // find thing to insert AFTER - stbtt__active_edge *p = active; - while (p->next && p->next->x < z->x) - p = p->next; - // at this point, p->next->x is NOT < z->x - z->next = p->next; - p->next = z; - } - } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this + // scanline + while (e->y0 <= scan_y) { + if (e->y1 > scan_y) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); + if (z != NULL) { + // find insertion point + if (active == NULL) + active = z; + else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + } + ++e; } - ++e; - } - // now process all active edges in XOR fashion - if (active) - stbtt__fill_active_edges(scanline, result->w, active, max_weight); + // now process all active edges in XOR fashion + if (active) + stbtt__fill_active_edges(scanline, result->w, active, max_weight); - ++y; - } - STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); - ++j; - } + ++y; + } + STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); + ++j; + } - stbtt__hheap_cleanup(&hh, userdata); + stbtt__hheap_cleanup(&hh, userdata); - if (scanline != scanline_data) - STBTT_free(scanline, userdata); + if (scanline != scanline_data) + STBTT_free(scanline, userdata); } #elif STBTT_RASTERIZER_VERSION == 2 // the edge passed in here does not cross the vertical line at x or the vertical line at x+1 // (i.e. it has already been clipped to those) -static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) -{ - if (y0 == y1) return; - STBTT_assert(y0 < y1); - STBTT_assert(e->sy <= e->ey); - if (y0 > e->ey) return; - if (y1 < e->sy) return; - if (y0 < e->sy) { - x0 += (x1-x0) * (e->sy - y0) / (y1-y0); - y0 = e->sy; - } - if (y1 > e->ey) { - x1 += (x1-x0) * (e->ey - y1) / (y1-y0); - y1 = e->ey; - } - - if (x0 == x) - STBTT_assert(x1 <= x+1); - else if (x0 == x+1) - STBTT_assert(x1 >= x); - else if (x0 <= x) - STBTT_assert(x1 <= x); - else if (x0 >= x+1) - STBTT_assert(x1 >= x+1); - else - STBTT_assert(x1 >= x && x1 <= x+1); - - if (x0 <= x && x1 <= x) - scanline[x] += e->direction * (y1-y0); - else if (x0 >= x+1 && x1 >= x+1) - ; - else { - STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); - scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position - } -} - -static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) -{ - STBTT_assert(top_width >= 0); - STBTT_assert(bottom_width >= 0); - return (top_width + bottom_width) / 2.0f * height; -} - -static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) -{ - return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); -} - -static float stbtt__sized_triangle_area(float height, float width) -{ - return height * width / 2; -} - -static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) -{ - float y_bottom = y_top+1; - - while (e) { - // brute force every pixel - - // compute intersection points with top & bottom - STBTT_assert(e->ey >= y_top); - - if (e->fdx == 0) { - float x0 = e->fx; - if (x0 < len) { - if (x0 >= 0) { - stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); - stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); +static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, + float y1) { + if (y0 == y1) + return; + STBTT_assert(y0 < y1); + STBTT_assert(e->sy <= e->ey); + if (y0 > e->ey) + return; + if (y1 < e->sy) + return; + if (y0 < e->sy) { + x0 += (x1 - x0) * (e->sy - y0) / (y1 - y0); + y0 = e->sy; + } + if (y1 > e->ey) { + x1 += (x1 - x0) * (e->ey - y1) / (y1 - y0); + y1 = e->ey; + } + + if (x0 == x) + STBTT_assert(x1 <= x + 1); + else if (x0 == x + 1) + STBTT_assert(x1 >= x); + else if (x0 <= x) + STBTT_assert(x1 <= x); + else if (x0 >= x + 1) + STBTT_assert(x1 >= x + 1); + else + STBTT_assert(x1 >= x && x1 <= x + 1); + + if (x0 <= x && x1 <= x) + scanline[x] += e->direction * (y1 - y0); + else if (x0 >= x + 1 && x1 >= x + 1) + ; + else { + STBTT_assert(x0 >= x && x0 <= x + 1 && x1 >= x && x1 <= x + 1); + scanline[x] += e->direction * (y1 - y0) * (1 - ((x0 - x) + (x1 - x)) / 2); // coverage = 1 - average x position + } +} + +static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) { + STBTT_assert(top_width >= 0); + STBTT_assert(bottom_width >= 0); + return (top_width + bottom_width) / 2.0f * height; +} + +static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) { + return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); +} + +static float stbtt__sized_triangle_area(float height, float width) { return height * width / 2; } + +static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, + float y_top) { + float y_bottom = y_top + 1; + + while (e) { + // brute force every pixel + + // compute intersection points with top & bottom + STBTT_assert(e->ey >= y_top); + + if (e->fdx == 0) { + float x0 = e->fx; + if (x0 < len) { + if (x0 >= 0) { + stbtt__handle_clipped_edge(scanline, (int)x0, e, x0, y_top, x0, y_bottom); + stbtt__handle_clipped_edge(scanline_fill - 1, (int)x0 + 1, e, x0, y_top, x0, y_bottom); + } else { + stbtt__handle_clipped_edge(scanline_fill - 1, 0, e, x0, y_top, x0, y_bottom); + } + } + } else { + float x0 = e->fx; + float dx = e->fdx; + float xb = x0 + dx; + float x_top, x_bottom; + float sy0, sy1; + float dy = e->fdy; + STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); + + // compute endpoints of line segment clipped to this scanline (if the + // line segment starts on this scanline. x0 is the intersection of the + // line with y_top, but that may be off the line segment. + if (e->sy > y_top) { + x_top = x0 + dx * (e->sy - y_top); + sy0 = e->sy; } else { - stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); + x_top = x0; + sy0 = y_top; } - } - } else { - float x0 = e->fx; - float dx = e->fdx; - float xb = x0 + dx; - float x_top, x_bottom; - float sy0,sy1; - float dy = e->fdy; - STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); - - // compute endpoints of line segment clipped to this scanline (if the - // line segment starts on this scanline. x0 is the intersection of the - // line with y_top, but that may be off the line segment. - if (e->sy > y_top) { - x_top = x0 + dx * (e->sy - y_top); - sy0 = e->sy; - } else { - x_top = x0; - sy0 = y_top; - } - if (e->ey < y_bottom) { - x_bottom = x0 + dx * (e->ey - y_top); - sy1 = e->ey; - } else { - x_bottom = xb; - sy1 = y_bottom; - } - - if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { - // from here on, we don't have to range check x values - - if ((int) x_top == (int) x_bottom) { - float height; - // simple case, only spans one pixel - int x = (int) x_top; - height = (sy1 - sy0) * e->direction; - STBTT_assert(x >= 0 && x < len); - scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); - scanline_fill[x] += height; // everything right of this pixel is filled + if (e->ey < y_bottom) { + x_bottom = x0 + dx * (e->ey - y_top); + sy1 = e->ey; } else { - int x,x1,x2; - float y_crossing, y_final, step, sign, area; - // covers 2+ pixels - if (x_top > x_bottom) { - // flip scanline vertically; signed area is the same - float t; - sy0 = y_bottom - (sy0 - y_top); - sy1 = y_bottom - (sy1 - y_top); - t = sy0, sy0 = sy1, sy1 = t; - t = x_bottom, x_bottom = x_top, x_top = t; - dx = -dx; - dy = -dy; - t = x0, x0 = xb, xb = t; - } - STBTT_assert(dy >= 0); - STBTT_assert(dx >= 0); - - x1 = (int) x_top; - x2 = (int) x_bottom; - // compute intersection with y axis at x1+1 - y_crossing = y_top + dy * (x1+1 - x0); - - // compute intersection with y axis at x2 - y_final = y_top + dy * (x2 - x0); - - // x1 x_top x2 x_bottom - // y_top +------|-----+------------+------------+--------|---+------------+ - // | | | | | | - // | | | | | | - // sy0 | Txxxxx|............|............|............|............| - // y_crossing | *xxxxx.......|............|............|............| - // | | xxxxx..|............|............|............| - // | | /- xx*xxxx........|............|............| - // | | dy < | xxxxxx..|............|............| - // y_final | | \- | xx*xxx.........|............| - // sy1 | | | | xxxxxB...|............| - // | | | | | | - // | | | | | | - // y_bottom +------------+------------+------------+------------+------------+ - // - // goal is to measure the area covered by '.' in each pixel - - // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 - // @TODO: maybe test against sy1 rather than y_bottom? - if (y_crossing > y_bottom) - y_crossing = y_bottom; - - sign = e->direction; - - // area of the rectangle covered from sy0..y_crossing - area = sign * (y_crossing-sy0); - - // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) - scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); - - // check if final y_crossing is blown up; no test case for this - if (y_final > y_bottom) { - y_final = y_bottom; - dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom - } - - // in second pixel, area covered by line segment found in first pixel - // is always a rectangle 1 wide * the height of that line segment; this - // is exactly what the variable 'area' stores. it also gets a contribution - // from the line segment within it. the THIRD pixel will get the first - // pixel's rectangle contribution, the second pixel's rectangle contribution, - // and its own contribution. the 'own contribution' is the same in every pixel except - // the leftmost and rightmost, a trapezoid that slides down in each pixel. - // the second pixel's contribution to the third pixel will be the - // rectangle 1 wide times the height change in the second pixel, which is dy. - - step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, - // which multiplied by 1-pixel-width is how much pixel area changes for each step in x - // so the area advances by 'step' every time - - for (x = x1+1; x < x2; ++x) { - scanline[x] += area + step/2; // area of trapezoid is 1*step/2 - area += step; - } - STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down - STBTT_assert(sy1 > y_final-0.01f); - - // area covered in the last pixel is the rectangle from all the pixels to the left, - // plus the trapezoid filled by the line segment in this pixel all the way to the right edge - scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); - - // the rest of the line is filled based on the total height of the line segment in this pixel - scanline_fill[x2] += sign * (sy1-sy0); + x_bottom = xb; + sy1 = y_bottom; } - } else { - // if edge goes outside of box we're drawing, we require - // clipping logic. since this does not match the intended use - // of this library, we use a different, very slow brute - // force implementation - // note though that this does happen some of the time because - // x_top and x_bottom can be extrapolated at the top & bottom of - // the shape and actually lie outside the bounding box - int x; - for (x=0; x < len; ++x) { - // cases: - // - // there can be up to two intersections with the pixel. any intersection - // with left or right edges can be handled by splitting into two (or three) - // regions. intersections with top & bottom do not necessitate case-wise logic. - // - // the old way of doing this found the intersections with the left & right edges, - // then used some simple logic to produce up to three segments in sorted order - // from top-to-bottom. however, this had a problem: if an x edge was epsilon - // across the x border, then the corresponding y position might not be distinct - // from the other y segment, and it might ignored as an empty segment. to avoid - // that, we need to explicitly produce segments based on x positions. - - // rename variables to clearly-defined pairs - float y0 = y_top; - float x1 = (float) (x); - float x2 = (float) (x+1); - float x3 = xb; - float y3 = y_bottom; - - // x = e->x + e->dx * (y-y_top) - // (y-y_top) = (x - e->x) / e->dx - // y = (x - e->x) / e->dx + y_top - float y1 = (x - x0) / dx + y_top; - float y2 = (x+1 - x0) / dx + y_top; - - if (x0 < x1 && x3 > x2) { // three segments descending down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x1 && x0 > x2) { // three segments descending down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else { // one segment - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); - } + + if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { + // from here on, we don't have to range check x values + + if ((int)x_top == (int)x_bottom) { + float height; + // simple case, only spans one pixel + int x = (int)x_top; + height = (sy1 - sy0) * e->direction; + STBTT_assert(x >= 0 && x < len); + scanline[x] += stbtt__position_trapezoid_area(height, x_top, x + 1.0f, x_bottom, x + 1.0f); + scanline_fill[x] += height; // everything right of this pixel is filled + } else { + int x, x1, x2; + float y_crossing, y_final, step, sign, area; + // covers 2+ pixels + if (x_top > x_bottom) { + // flip scanline vertically; signed area is the same + float t; + sy0 = y_bottom - (sy0 - y_top); + sy1 = y_bottom - (sy1 - y_top); + t = sy0, sy0 = sy1, sy1 = t; + t = x_bottom, x_bottom = x_top, x_top = t; + dx = -dx; + dy = -dy; + t = x0, x0 = xb, xb = t; + } + STBTT_assert(dy >= 0); + STBTT_assert(dx >= 0); + + x1 = (int)x_top; + x2 = (int)x_bottom; + // compute intersection with y axis at x1+1 + y_crossing = y_top + dy * (x1 + 1 - x0); + + // compute intersection with y axis at x2 + y_final = y_top + dy * (x2 - x0); + + // x1 x_top x2 x_bottom + // y_top +------|-----+------------+------------+--------|---+------------+ + // | | | | | | + // | | | | | | + // sy0 | Txxxxx|............|............|............|............| + // y_crossing | *xxxxx.......|............|............|............| + // | | xxxxx..|............|............|............| + // | | /- xx*xxxx........|............|............| + // | | dy < | xxxxxx..|............|............| + // y_final | | \- | xx*xxx.........|............| + // sy1 | | | | xxxxxB...|............| + // | | | | | | + // | | | | | | + // y_bottom +------------+------------+------------+------------+------------+ + // + // goal is to measure the area covered by '.' in each pixel + + // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 + // @TODO: maybe test against sy1 rather than y_bottom? + if (y_crossing > y_bottom) + y_crossing = y_bottom; + + sign = e->direction; + + // area of the rectangle covered from sy0..y_crossing + area = sign * (y_crossing - sy0); + + // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) + scanline[x1] += stbtt__sized_triangle_area(area, x1 + 1 - x_top); + + // check if final y_crossing is blown up; no test case for this + if (y_final > y_bottom) { + y_final = y_bottom; + dy = (y_final - y_crossing) / + (x2 - (x1 + 1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom + } + + // in second pixel, area covered by line segment found in first pixel + // is always a rectangle 1 wide * the height of that line segment; this + // is exactly what the variable 'area' stores. it also gets a contribution + // from the line segment within it. the THIRD pixel will get the first + // pixel's rectangle contribution, the second pixel's rectangle contribution, + // and its own contribution. the 'own contribution' is the same in every pixel except + // the leftmost and rightmost, a trapezoid that slides down in each pixel. + // the second pixel's contribution to the third pixel will be the + // rectangle 1 wide times the height change in the second pixel, which is dy. + + step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, + // which multiplied by 1-pixel-width is how much pixel area changes for each step in x + // so the area advances by 'step' every time + + for (x = x1 + 1; x < x2; ++x) { + scanline[x] += area + step / 2; // area of trapezoid is 1*step/2 + area += step; + } + STBTT_assert(STBTT_fabs(area) <= + 1.01f); // accumulated error from area += step unless we round step down + STBTT_assert(sy1 > y_final - 0.01f); + + // area covered in the last pixel is the rectangle from all the pixels to the left, + // plus the trapezoid filled by the line segment in this pixel all the way to the right edge + scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1 - y_final, (float)x2, x2 + 1.0f, + x_bottom, x2 + 1.0f); + + // the rest of the line is filled based on the total height of the line segment in this pixel + scanline_fill[x2] += sign * (sy1 - sy0); + } + } else { + // if edge goes outside of box we're drawing, we require + // clipping logic. since this does not match the intended use + // of this library, we use a different, very slow brute + // force implementation + // note though that this does happen some of the time because + // x_top and x_bottom can be extrapolated at the top & bottom of + // the shape and actually lie outside the bounding box + int x; + for (x = 0; x < len; ++x) { + // cases: + // + // there can be up to two intersections with the pixel. any intersection + // with left or right edges can be handled by splitting into two (or three) + // regions. intersections with top & bottom do not necessitate case-wise logic. + // + // the old way of doing this found the intersections with the left & right edges, + // then used some simple logic to produce up to three segments in sorted order + // from top-to-bottom. however, this had a problem: if an x edge was epsilon + // across the x border, then the corresponding y position might not be distinct + // from the other y segment, and it might ignored as an empty segment. to avoid + // that, we need to explicitly produce segments based on x positions. + + // rename variables to clearly-defined pairs + float y0 = y_top; + float x1 = (float)(x); + float x2 = (float)(x + 1); + float x3 = xb; + float y3 = y_bottom; + + // x = e->x + e->dx * (y-y_top) + // (y-y_top) = (x - e->x) / e->dx + // y = (x - e->x) / e->dx + y_top + float y1 = (x - x0) / dx + y_top; + float y2 = (x + 1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { // three segments descending down-right + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1); + stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x2, y2); + stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3); + } else if (x3 < x1 && x0 > x2) { // three segments descending down-left + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2); + stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x1, y1); + stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3); + } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1); + stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3); + } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1); + stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3); + } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2); + stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3); + } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2); + stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3); + } else { // one segment + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x3, y3); + } + } } - } - } - e = e->next; - } + } + e = e->next; + } } // directly AA rasterize edges w/o supersampling -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__hheap hh = { 0, 0, 0 }; - stbtt__active_edge *active = NULL; - int y,j=0, i; - float scanline_data[129], *scanline, *scanline2; - - STBTT__NOTUSED(vsubsample); - - if (result->w > 64) - scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); - else - scanline = scanline_data; - - scanline2 = scanline + result->w; - - y = off_y; - e[n].y0 = (float) (off_y + result->h) + 1; - - while (j < result->h) { - // find center of pixel for this scanline - float scan_y_top = y + 0.0f; - float scan_y_bottom = y + 1.0f; - stbtt__active_edge **step = &active; - - STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); - STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); - - // update all active edges; - // remove all active edges that terminate before the top of this scanline - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y_top) { - *step = z->next; // delete from list - STBTT_assert(z->direction); - z->direction = 0; - stbtt__hheap_free(&hh, z); - } else { - step = &((*step)->next); // advance through list - } - } - - // insert all edges that start before the bottom of this scanline - while (e->y0 <= scan_y_bottom) { - if (e->y0 != e->y1) { - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); - if (z != NULL) { - if (j == 0 && off_y != 0) { - if (z->ey < scan_y_top) { - // this can happen due to subpixel positioning and some kind of fp rounding error i think - z->ey = scan_y_top; - } - } - STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds - // insert at front - z->next = active; - active = z; +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, + int off_y, void *userdata) { + stbtt__hheap hh = {0, 0, 0}; + stbtt__active_edge *active = NULL; + int y, j = 0, i; + float scanline_data[129], *scanline, *scanline2; + + STBTT__NOTUSED(vsubsample); + + if (result->w > 64) + scanline = (float *)STBTT_malloc((result->w * 2 + 1) * sizeof(float), userdata); + else + scanline = scanline_data; + + scanline2 = scanline + result->w; + + y = off_y; + e[n].y0 = (float)(off_y + result->h) + 1; + + while (j < result->h) { + // find center of pixel for this scanline + float scan_y_top = y + 0.0f; + float scan_y_bottom = y + 1.0f; + stbtt__active_edge **step = &active; + + STBTT_memset(scanline, 0, result->w * sizeof(scanline[0])); + STBTT_memset(scanline2, 0, (result->w + 1) * sizeof(scanline[0])); + + // update all active edges; + // remove all active edges that terminate before the top of this scanline + while (*step) { + stbtt__active_edge *z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + step = &((*step)->next); // advance through list } - } - ++e; - } - - // now process all active edges - if (active) - stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); - - { - float sum = 0; - for (i=0; i < result->w; ++i) { - float k; - int m; - sum += scanline2[i]; - k = scanline[i] + sum; - k = (float) STBTT_fabs(k)*255 + 0.5f; - m = (int) k; - if (m > 255) m = 255; - result->pixels[j*result->stride + i] = (unsigned char) m; - } - } - // advance all the edges - step = &active; - while (*step) { - stbtt__active_edge *z = *step; - z->fx += z->fdx; // advance to position for current scanline - step = &((*step)->next); // advance through list - } + } + + // insert all edges that start before the bottom of this scanline + while (e->y0 <= scan_y_bottom) { + if (e->y0 != e->y1) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); + if (z != NULL) { + if (j == 0 && off_y != 0) { + if (z->ey < scan_y_top) { + // this can happen due to subpixel positioning and some kind of fp rounding error i think + z->ey = scan_y_top; + } + } + STBTT_assert(z->ey >= + scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds + // insert at front + z->next = active; + active = z; + } + } + ++e; + } + + // now process all active edges + if (active) + stbtt__fill_active_edges_new(scanline, scanline2 + 1, result->w, active, scan_y_top); + + { + float sum = 0; + for (i = 0; i < result->w; ++i) { + float k; + int m; + sum += scanline2[i]; + k = scanline[i] + sum; + k = (float)STBTT_fabs(k) * 255 + 0.5f; + m = (int)k; + if (m > 255) + m = 255; + result->pixels[j * result->stride + i] = (unsigned char)m; + } + } + // advance all the edges + step = &active; + while (*step) { + stbtt__active_edge *z = *step; + z->fx += z->fdx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } - ++y; - ++j; - } + ++y; + ++j; + } - stbtt__hheap_cleanup(&hh, userdata); + stbtt__hheap_cleanup(&hh, userdata); - if (scanline != scanline_data) - STBTT_free(scanline, userdata); + if (scanline != scanline_data) + STBTT_free(scanline, userdata); } #else #error "Unrecognized value of STBTT_RASTERIZER_VERSION" #endif -#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) - -static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) -{ - int i,j; - for (i=1; i < n; ++i) { - stbtt__edge t = p[i], *a = &t; - j = i; - while (j > 0) { - stbtt__edge *b = &p[j-1]; - int c = STBTT__COMPARE(a,b); - if (!c) break; - p[j] = p[j-1]; - --j; - } - if (i != j) - p[j] = t; - } -} - -static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) -{ - /* threshold for transitioning to insertion sort */ - while (n > 12) { - stbtt__edge t; - int c01,c12,c,m,i,j; - - /* compute median of three */ - m = n >> 1; - c01 = STBTT__COMPARE(&p[0],&p[m]); - c12 = STBTT__COMPARE(&p[m],&p[n-1]); - /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ - if (c01 != c12) { - /* otherwise, we'll need to swap something else to middle */ - int z; - c = STBTT__COMPARE(&p[0],&p[n-1]); - /* 0>mid && midn => n; 0 0 */ - /* 0n: 0>n => 0; 0 n */ - z = (c == c12) ? 0 : n-1; - t = p[z]; - p[z] = p[m]; - p[m] = t; - } - /* now p[m] is the median-of-three */ - /* swap it to the beginning so it won't move around */ - t = p[0]; - p[0] = p[m]; - p[m] = t; - - /* partition loop */ - i=1; - j=n-1; - for(;;) { - /* handling of equality is crucial here */ - /* for sentinels & efficiency with duplicates */ - for (;;++i) { - if (!STBTT__COMPARE(&p[i], &p[0])) break; - } - for (;;--j) { - if (!STBTT__COMPARE(&p[0], &p[j])) break; - } - /* make sure we haven't crossed */ - if (i >= j) break; - t = p[i]; - p[i] = p[j]; - p[j] = t; - - ++i; - --j; - } - /* recurse on smaller side, iterate on larger */ - if (j < (n-i)) { - stbtt__sort_edges_quicksort(p,j); - p = p+i; - n = n-i; - } else { - stbtt__sort_edges_quicksort(p+i, n-i); - n = j; - } - } -} - -static void stbtt__sort_edges(stbtt__edge *p, int n) -{ - stbtt__sort_edges_quicksort(p, n); - stbtt__sort_edges_ins_sort(p, n); -} - -typedef struct -{ - float x,y; +#define STBTT__COMPARE(a, b) ((a)->y0 < (b)->y0) + +static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) { + int i, j; + for (i = 1; i < n; ++i) { + stbtt__edge t = p[i], *a = &t; + j = i; + while (j > 0) { + stbtt__edge *b = &p[j - 1]; + int c = STBTT__COMPARE(a, b); + if (!c) + break; + p[j] = p[j - 1]; + --j; + } + if (i != j) + p[j] = t; + } +} + +static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) { + /* threshold for transitioning to insertion sort */ + while (n > 12) { + stbtt__edge t; + int c01, c12, c, m, i, j; + + /* compute median of three */ + m = n >> 1; + c01 = STBTT__COMPARE(&p[0], &p[m]); + c12 = STBTT__COMPARE(&p[m], &p[n - 1]); + /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ + if (c01 != c12) { + /* otherwise, we'll need to swap something else to middle */ + int z; + c = STBTT__COMPARE(&p[0], &p[n - 1]); + /* 0>mid && midn => n; 0 0 */ + /* 0n: 0>n => 0; 0 n */ + z = (c == c12) ? 0 : n - 1; + t = p[z]; + p[z] = p[m]; + p[m] = t; + } + /* now p[m] is the median-of-three */ + /* swap it to the beginning so it won't move around */ + t = p[0]; + p[0] = p[m]; + p[m] = t; + + /* partition loop */ + i = 1; + j = n - 1; + for (;;) { + /* handling of equality is crucial here */ + /* for sentinels & efficiency with duplicates */ + for (;; ++i) { + if (!STBTT__COMPARE(&p[i], &p[0])) + break; + } + for (;; --j) { + if (!STBTT__COMPARE(&p[0], &p[j])) + break; + } + /* make sure we haven't crossed */ + if (i >= j) + break; + t = p[i]; + p[i] = p[j]; + p[j] = t; + + ++i; + --j; + } + /* recurse on smaller side, iterate on larger */ + if (j < (n - i)) { + stbtt__sort_edges_quicksort(p, j); + p = p + i; + n = n - i; + } else { + stbtt__sort_edges_quicksort(p + i, n - i); + n = j; + } + } +} + +static void stbtt__sort_edges(stbtt__edge *p, int n) { + stbtt__sort_edges_quicksort(p, n); + stbtt__sort_edges_ins_sort(p, n); +} + +typedef struct { + float x, y; } stbtt__point; -static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) -{ - float y_scale_inv = invert ? -scale_y : scale_y; - stbtt__edge *e; - int n,i,j,k,m; +static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, + float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, + void *userdata) { + float y_scale_inv = invert ? -scale_y : scale_y; + stbtt__edge *e; + int n, i, j, k, m; #if STBTT_RASTERIZER_VERSION == 1 - int vsubsample = result->h < 8 ? 15 : 5; + int vsubsample = result->h < 8 ? 15 : 5; #elif STBTT_RASTERIZER_VERSION == 2 - int vsubsample = 1; + int vsubsample = 1; #else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" #endif - // vsubsample should divide 255 evenly; otherwise we won't reach full opacity - - // now we have to blow out the windings into explicit edge lists - n = 0; - for (i=0; i < windings; ++i) - n += wcount[i]; - - e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel - if (e == 0) return; - n = 0; - - m=0; - for (i=0; i < windings; ++i) { - stbtt__point *p = pts + m; - m += wcount[i]; - j = wcount[i]-1; - for (k=0; k < wcount[i]; j=k++) { - int a=k,b=j; - // skip the edge if horizontal - if (p[j].y == p[k].y) - continue; - // add edge from j to k to the list - e[n].invert = 0; - if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { - e[n].invert = 1; - a=j,b=k; - } - e[n].x0 = p[a].x * scale_x + shift_x; - e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; - e[n].x1 = p[b].x * scale_x + shift_x; - e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; - ++n; - } - } + // vsubsample should divide 255 evenly; otherwise we won't reach full opacity + + // now we have to blow out the windings into explicit edge lists + n = 0; + for (i = 0; i < windings; ++i) + n += wcount[i]; + + e = (stbtt__edge *)STBTT_malloc(sizeof(*e) * (n + 1), userdata); // add an extra one as a sentinel + if (e == 0) + return; + n = 0; + + m = 0; + for (i = 0; i < windings; ++i) { + stbtt__point *p = pts + m; + m += wcount[i]; + j = wcount[i] - 1; + for (k = 0; k < wcount[i]; j = k++) { + int a = k, b = j; + // skip the edge if horizontal + if (p[j].y == p[k].y) + continue; + // add edge from j to k to the list + e[n].invert = 0; + if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { + e[n].invert = 1; + a = j, b = k; + } + e[n].x0 = p[a].x * scale_x + shift_x; + e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; + e[n].x1 = p[b].x * scale_x + shift_x; + e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; + ++n; + } + } - // now sort the edges by their highest point (should snap to integer, and then by x) - //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); - stbtt__sort_edges(e, n); + // now sort the edges by their highest point (should snap to integer, and then by x) + // STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); + stbtt__sort_edges(e, n); - // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule - stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); + // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule + stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); - STBTT_free(e, userdata); + STBTT_free(e, userdata); } -static void stbtt__add_point(stbtt__point *points, int n, float x, float y) -{ - if (!points) return; // during first pass, it's unallocated - points[n].x = x; - points[n].y = y; +static void stbtt__add_point(stbtt__point *points, int n, float x, float y) { + if (!points) + return; // during first pass, it's unallocated + points[n].x = x; + points[n].y = y; } // tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching -static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) -{ - // midpoint - float mx = (x0 + 2*x1 + x2)/4; - float my = (y0 + 2*y1 + y2)/4; - // versus directly drawn line - float dx = (x0+x2)/2 - mx; - float dy = (y0+y2)/2 - my; - if (n > 16) // 65536 segments on one curve better be enough! - return 1; - if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA - stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x2,y2); - *num_points = *num_points+1; - } - return 1; -} - -static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) -{ - // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough - float dx0 = x1-x0; - float dy0 = y1-y0; - float dx1 = x2-x1; - float dy1 = y2-y1; - float dx2 = x3-x2; - float dy2 = y3-y2; - float dx = x3-x0; - float dy = y3-y0; - float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); - float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); - float flatness_squared = longlen*longlen-shortlen*shortlen; - - if (n > 16) // 65536 segments on one curve better be enough! - return; - - if (flatness_squared > objspace_flatness_squared) { - float x01 = (x0+x1)/2; - float y01 = (y0+y1)/2; - float x12 = (x1+x2)/2; - float y12 = (y1+y2)/2; - float x23 = (x2+x3)/2; - float y23 = (y2+y3)/2; - - float xa = (x01+x12)/2; - float ya = (y01+y12)/2; - float xb = (x12+x23)/2; - float yb = (y12+y23)/2; - - float mx = (xa+xb)/2; - float my = (ya+yb)/2; - - stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x3,y3); - *num_points = *num_points+1; - } +static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, + float x2, float y2, float objspace_flatness_squared, int n) { + // midpoint + float mx = (x0 + 2 * x1 + x2) / 4; + float my = (y0 + 2 * y1 + y2) / 4; + // versus directly drawn line + float dx = (x0 + x2) / 2 - mx; + float dy = (y0 + y2) / 2 - my; + if (n > 16) // 65536 segments on one curve better be enough! + return 1; + if (dx * dx + dy * dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA + stbtt__tesselate_curve(points, num_points, x0, y0, (x0 + x1) / 2.0f, (y0 + y1) / 2.0f, mx, my, + objspace_flatness_squared, n + 1); + stbtt__tesselate_curve(points, num_points, mx, my, (x1 + x2) / 2.0f, (y1 + y2) / 2.0f, x2, y2, + objspace_flatness_squared, n + 1); + } else { + stbtt__add_point(points, *num_points, x2, y2); + *num_points = *num_points + 1; + } + return 1; +} + +static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) { + // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough + float dx0 = x1 - x0; + float dy0 = y1 - y0; + float dx1 = x2 - x1; + float dy1 = y2 - y1; + float dx2 = x3 - x2; + float dy2 = y3 - y2; + float dx = x3 - x0; + float dy = y3 - y0; + float longlen = (float)(STBTT_sqrt(dx0 * dx0 + dy0 * dy0) + STBTT_sqrt(dx1 * dx1 + dy1 * dy1) + + STBTT_sqrt(dx2 * dx2 + dy2 * dy2)); + float shortlen = (float)STBTT_sqrt(dx * dx + dy * dy); + float flatness_squared = longlen * longlen - shortlen * shortlen; + + if (n > 16) // 65536 segments on one curve better be enough! + return; + + if (flatness_squared > objspace_flatness_squared) { + float x01 = (x0 + x1) / 2; + float y01 = (y0 + y1) / 2; + float x12 = (x1 + x2) / 2; + float y12 = (y1 + y2) / 2; + float x23 = (x2 + x3) / 2; + float y23 = (y2 + y3) / 2; + + float xa = (x01 + x12) / 2; + float ya = (y01 + y12) / 2; + float xb = (x12 + x23) / 2; + float yb = (y12 + y23) / 2; + + float mx = (xa + xb) / 2; + float my = (ya + yb) / 2; + + stbtt__tesselate_cubic(points, num_points, x0, y0, x01, y01, xa, ya, mx, my, objspace_flatness_squared, n + 1); + stbtt__tesselate_cubic(points, num_points, mx, my, xb, yb, x23, y23, x3, y3, objspace_flatness_squared, n + 1); + } else { + stbtt__add_point(points, *num_points, x3, y3); + *num_points = *num_points + 1; + } } // returns number of contours -static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) -{ - stbtt__point *points=0; - int num_points=0; - - float objspace_flatness_squared = objspace_flatness * objspace_flatness; - int i,n=0,start=0, pass; - - // count how many "moves" there are to get the contour count - for (i=0; i < num_verts; ++i) - if (vertices[i].type == STBTT_vmove) - ++n; - - *num_contours = n; - if (n == 0) return 0; - - *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); - - if (*contour_lengths == 0) { - *num_contours = 0; - return 0; - } - - // make two passes through the points so we don't need to realloc - for (pass=0; pass < 2; ++pass) { - float x=0,y=0; - if (pass == 1) { - points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); - if (points == NULL) goto error; - } - num_points = 0; - n= -1; - for (i=0; i < num_verts; ++i) { - switch (vertices[i].type) { +static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, + int **contour_lengths, int *num_contours, void *userdata) { + stbtt__point *points = 0; + int num_points = 0; + + float objspace_flatness_squared = objspace_flatness * objspace_flatness; + int i, n = 0, start = 0, pass; + + // count how many "moves" there are to get the contour count + for (i = 0; i < num_verts; ++i) + if (vertices[i].type == STBTT_vmove) + ++n; + + *num_contours = n; + if (n == 0) + return 0; + + *contour_lengths = (int *)STBTT_malloc(sizeof(**contour_lengths) * n, userdata); + + if (*contour_lengths == 0) { + *num_contours = 0; + return 0; + } + + // make two passes through the points so we don't need to realloc + for (pass = 0; pass < 2; ++pass) { + float x = 0, y = 0; + if (pass == 1) { + points = (stbtt__point *)STBTT_malloc(num_points * sizeof(points[0]), userdata); + if (points == NULL) + goto error; + } + num_points = 0; + n = -1; + for (i = 0; i < num_verts; ++i) { + switch (vertices[i].type) { case STBTT_vmove: - // start the next contour - if (n >= 0) - (*contour_lengths)[n] = num_points - start; - ++n; - start = num_points; - - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x,y); - break; + // start the next contour + if (n >= 0) + (*contour_lengths)[n] = num_points - start; + ++n; + start = num_points; + + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; case STBTT_vline: - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x, y); - break; + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; case STBTT_vcurve: - stbtt__tesselate_curve(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; + stbtt__tesselate_curve(points, &num_points, x, y, vertices[i].cx, vertices[i].cy, vertices[i].x, + vertices[i].y, objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; case STBTT_vcubic: - stbtt__tesselate_cubic(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].cx1, vertices[i].cy1, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - } - } - (*contour_lengths)[n] = num_points - start; - } + stbtt__tesselate_cubic(points, &num_points, x, y, vertices[i].cx, vertices[i].cy, vertices[i].cx1, + vertices[i].cy1, vertices[i].x, vertices[i].y, objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + } + } + (*contour_lengths)[n] = num_points - start; + } - return points; + return points; error: - STBTT_free(points, userdata); - STBTT_free(*contour_lengths, userdata); - *contour_lengths = 0; - *num_contours = 0; - return NULL; -} - -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) -{ - float scale = scale_x > scale_y ? scale_y : scale_x; - int winding_count = 0; - int *winding_lengths = NULL; - stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); - if (windings) { - stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); - STBTT_free(winding_lengths, userdata); - STBTT_free(windings, userdata); - } -} - -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); -} - -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - int ix0,iy0,ix1,iy1; - stbtt__bitmap gbm; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - - if (scale_x == 0) scale_x = scale_y; - if (scale_y == 0) { - if (scale_x == 0) { - STBTT_free(vertices, info->userdata); - return NULL; - } - scale_y = scale_x; - } + STBTT_free(points, userdata); + STBTT_free(*contour_lengths, userdata); + *contour_lengths = 0; + *num_contours = 0; + return NULL; +} + +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, + float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, + int invert, void *userdata) { + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count = 0; + int *winding_lengths = NULL; + stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, + &winding_count, userdata); + if (windings) { + stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, + y_off, invert, userdata); + STBTT_free(winding_lengths, userdata); + STBTT_free(windings, userdata); + } +} + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) { STBTT_free(bitmap, userdata); } + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, + float shift_x, float shift_y, int glyph, int *width, int *height, + int *xoff, int *yoff) { + int ix0, iy0, ix1, iy1; + stbtt__bitmap gbm; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + + if (scale_x == 0) + scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) { + STBTT_free(vertices, info->userdata); + return NULL; + } + scale_y = scale_x; + } - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0, &iy0, &ix1, &iy1); - // now we get the size - gbm.w = (ix1 - ix0); - gbm.h = (iy1 - iy0); - gbm.pixels = NULL; // in case we error + // now we get the size + gbm.w = (ix1 - ix0); + gbm.h = (iy1 - iy0); + gbm.pixels = NULL; // in case we error - if (width ) *width = gbm.w; - if (height) *height = gbm.h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; + if (width) + *width = gbm.w; + if (height) + *height = gbm.h; + if (xoff) + *xoff = ix0; + if (yoff) + *yoff = iy0; - if (gbm.w && gbm.h) { - gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); - if (gbm.pixels) { - gbm.stride = gbm.w; + if (gbm.w && gbm.h) { + gbm.pixels = (unsigned char *)STBTT_malloc(gbm.w * gbm.h, info->userdata); + if (gbm.pixels) { + gbm.stride = gbm.w; - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); - } - } - STBTT_free(vertices, info->userdata); - return gbm.pixels; + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, + info->userdata); + } + } + STBTT_free(vertices, info->userdata); + return gbm.pixels; } -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, + int *width, int *height, int *xoff, int *yoff) { + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); } -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) -{ - int ix0,iy0; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - stbtt__bitmap gbm; +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, + int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, + int glyph) { + int ix0, iy0; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + stbtt__bitmap gbm; - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); - gbm.pixels = output; - gbm.w = out_w; - gbm.h = out_h; - gbm.stride = out_stride; + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0, &iy0, 0, 0); + gbm.pixels = output; + gbm.w = out_w; + gbm.h = out_h; + gbm.stride = out_stride; - if (gbm.w && gbm.h) - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); + if (gbm.w && gbm.h) + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, + info->userdata); - STBTT_free(vertices, info->userdata); + STBTT_free(vertices, info->userdata); } -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, + int out_stride, float scale_x, float scale_y, int glyph) { + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f, 0.0f, glyph); } -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, + float shift_x, float shift_y, int codepoint, int *width, + int *height, int *xoff, int *yoff) { + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info, codepoint), + width, height, xoff, yoff); } -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) -{ - stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, + int out_h, int out_stride, float scale_x, float scale_y, + float shift_x, float shift_y, int oversample_x, + int oversample_y, float *sub_x, float *sub_y, int codepoint) { + stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, + oversample_x, oversample_y, sub_x, sub_y, + stbtt_FindGlyphIndex(info, codepoint)); } -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, + int out_h, int out_stride, float scale_x, float scale_y, float shift_x, + float shift_y, int codepoint) { + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, + stbtt_FindGlyphIndex(info, codepoint)); } -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, + int codepoint, int *width, int *height, int *xoff, int *yoff) { + return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, codepoint, width, height, xoff, yoff); } -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) -{ - stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, + int out_stride, float scale_x, float scale_y, int codepoint) { + stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f, 0.0f, codepoint); } ////////////////////////////////////////////////////////////////////////////// @@ -3810,71 +3927,70 @@ STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned ch // // This is SUPER-CRAPPY packing to keep source code small -static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata) -{ - float scale; - int x,y,bottom_y, i; - stbtt_fontinfo f; - f.userdata = NULL; - if (!stbtt_InitFont(&f, data, offset)) - return -1; - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels - x=y=1; - bottom_y = 1; - - scale = stbtt_ScaleForPixelHeight(&f, pixel_height); - - for (i=0; i < num_chars; ++i) { - int advance, lsb, x0,y0,x1,y1,gw,gh; - int g = stbtt_FindGlyphIndex(&f, first_char + i); - stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); - stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); - gw = x1-x0; - gh = y1-y0; - if (x + gw + 1 >= pw) - y = bottom_y, x = 1; // advance to next row - if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row - return -i; - STBTT_assert(x+gw < pw); - STBTT_assert(y+gh < ph); - stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); - chardata[i].x0 = (stbtt_int16) x; - chardata[i].y0 = (stbtt_int16) y; - chardata[i].x1 = (stbtt_int16) (x + gw); - chardata[i].y1 = (stbtt_int16) (y + gh); - chardata[i].xadvance = scale * advance; - chardata[i].xoff = (float) x0; - chardata[i].yoff = (float) y0; - x = x + gw + 1; - if (y+gh+1 > bottom_y) - bottom_y = y+gh+1; - } - return bottom_y; -} - -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) -{ - float d3d_bias = opengl_fillrule ? 0 : -0.5f; - float ipw = 1.0f / pw, iph = 1.0f / ph; - const stbtt_bakedchar *b = chardata + char_index; - int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); - int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); - - q->x0 = round_x + d3d_bias; - q->y0 = round_y + d3d_bias; - q->x1 = round_x + b->x1 - b->x0 + d3d_bias; - q->y1 = round_y + b->y1 - b->y0 + d3d_bias; - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - *xpos += b->xadvance; +static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata) { + float scale; + int x, y, bottom_y, i; + stbtt_fontinfo f; + f.userdata = NULL; + if (!stbtt_InitFont(&f, data, offset)) + return -1; + STBTT_memset(pixels, 0, pw * ph); // background of 0 around pixels + x = y = 1; + bottom_y = 1; + + scale = stbtt_ScaleForPixelHeight(&f, pixel_height); + + for (i = 0; i < num_chars; ++i) { + int advance, lsb, x0, y0, x1, y1, gw, gh; + int g = stbtt_FindGlyphIndex(&f, first_char + i); + stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); + stbtt_GetGlyphBitmapBox(&f, g, scale, scale, &x0, &y0, &x1, &y1); + gw = x1 - x0; + gh = y1 - y0; + if (x + gw + 1 >= pw) + y = bottom_y, x = 1; // advance to next row + if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row + return -i; + STBTT_assert(x + gw < pw); + STBTT_assert(y + gh < ph); + stbtt_MakeGlyphBitmap(&f, pixels + x + y * pw, gw, gh, pw, scale, scale, g); + chardata[i].x0 = (stbtt_int16)x; + chardata[i].y0 = (stbtt_int16)y; + chardata[i].x1 = (stbtt_int16)(x + gw); + chardata[i].y1 = (stbtt_int16)(y + gh); + chardata[i].xadvance = scale * advance; + chardata[i].xoff = (float)x0; + chardata[i].yoff = (float)y0; + x = x + gw + 1; + if (y + gh + 1 > bottom_y) + bottom_y = y + gh + 1; + } + return bottom_y; +} + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, + float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) { + float d3d_bias = opengl_fillrule ? 0 : -0.5f; + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_bakedchar *b = chardata + char_index; + int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); + int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); + + q->x0 = round_x + d3d_bias; + q->y0 = round_y + d3d_bias; + q->x1 = round_x + b->x1 - b->x0 + d3d_bias; + q->y1 = round_y + b->y1 - b->y0 + d3d_bias; + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; } ////////////////////////////////////////////////////////////////////////////// @@ -3897,53 +4013,48 @@ typedef int stbrp_coord; // // //////////////////////////////////////////////////////////////////////////////////// -typedef struct -{ - int width,height; - int x,y,bottom_y; +typedef struct { + int width, height; + int x, y, bottom_y; } stbrp_context; -typedef struct -{ - unsigned char x; +typedef struct { + unsigned char x; } stbrp_node; -struct stbrp_rect -{ - stbrp_coord x,y; - int id,w,h,was_packed; +struct stbrp_rect { + stbrp_coord x, y; + int id, w, h, was_packed; }; -static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) -{ - con->width = pw; - con->height = ph; - con->x = 0; - con->y = 0; - con->bottom_y = 0; - STBTT__NOTUSED(nodes); - STBTT__NOTUSED(num_nodes); -} - -static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) -{ - int i; - for (i=0; i < num_rects; ++i) { - if (con->x + rects[i].w > con->width) { - con->x = 0; - con->y = con->bottom_y; - } - if (con->y + rects[i].h > con->height) - break; - rects[i].x = con->x; - rects[i].y = con->y; - rects[i].was_packed = 1; - con->x += rects[i].w; - if (con->y + rects[i].h > con->bottom_y) - con->bottom_y = con->y + rects[i].h; - } - for ( ; i < num_rects; ++i) - rects[i].was_packed = 0; +static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) { + con->width = pw; + con->height = ph; + con->x = 0; + con->y = 0; + con->bottom_y = 0; + STBTT__NOTUSED(nodes); + STBTT__NOTUSED(num_nodes); +} + +static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) { + int i; + for (i = 0; i < num_rects; ++i) { + if (con->x + rects[i].w > con->width) { + con->x = 0; + con->y = con->bottom_y; + } + if (con->y + rects[i].h > con->height) + break; + rects[i].x = con->x; + rects[i].y = con->y; + rects[i].was_packed = 1; + con->x += rects[i].w; + if (con->y + rects[i].h > con->bottom_y) + con->bottom_y = con->y + rects[i].h; + } + for (; i < num_rects; ++i) + rects[i].was_packed = 0; } #endif @@ -3954,437 +4065,415 @@ static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rect // This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If // stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) -{ - stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); - int num_nodes = pw - padding; - stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); - - if (context == NULL || nodes == NULL) { - if (context != NULL) STBTT_free(context, alloc_context); - if (nodes != NULL) STBTT_free(nodes , alloc_context); - return 0; - } - - spc->user_allocator_context = alloc_context; - spc->width = pw; - spc->height = ph; - spc->pixels = pixels; - spc->pack_info = context; - spc->nodes = nodes; - spc->padding = padding; - spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; - spc->h_oversample = 1; - spc->v_oversample = 1; - spc->skip_missing = 0; - - stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); - - if (pixels) - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels - - return 1; -} - -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) -{ - STBTT_free(spc->nodes , spc->user_allocator_context); - STBTT_free(spc->pack_info, spc->user_allocator_context); -} - -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) -{ - STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); - STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); - if (h_oversample <= STBTT_MAX_OVERSAMPLE) - spc->h_oversample = h_oversample; - if (v_oversample <= STBTT_MAX_OVERSAMPLE) - spc->v_oversample = v_oversample; -} - -STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) -{ - spc->skip_missing = skip; -} - -#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) - -static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_w = w - kernel_width; - int j; - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze - for (j=0; j < h; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - // make kernel_width a constant in common cases so compiler can optimize out the divide - switch (kernel_width) { - case 2: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 2); +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, + int padding, void *alloc_context) { + stbrp_context *context = (stbrp_context *)STBTT_malloc(sizeof(*context), alloc_context); + int num_nodes = pw - padding; + stbrp_node *nodes = (stbrp_node *)STBTT_malloc(sizeof(*nodes) * num_nodes, alloc_context); + + if (context == NULL || nodes == NULL) { + if (context != NULL) + STBTT_free(context, alloc_context); + if (nodes != NULL) + STBTT_free(nodes, alloc_context); + return 0; + } + + spc->user_allocator_context = alloc_context; + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->padding = padding; + spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; + spc->skip_missing = 0; + + stbrp_init_target(context, pw - padding, ph - padding, nodes, num_nodes); + + if (pixels) + STBTT_memset(pixels, 0, pw * ph); // background of 0 around pixels + + return 1; +} + +STBTT_DEF void stbtt_PackEnd(stbtt_pack_context *spc) { + STBTT_free(spc->nodes, spc->user_allocator_context); + STBTT_free(spc->pack_info, spc->user_allocator_context); +} + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, + unsigned int v_oversample) { + STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + if (h_oversample <= STBTT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= STBTT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; +} + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) { spc->skip_missing = skip; } + +#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE - 1) + +static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) { + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j = 0; j < h; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i = 0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char)(total / 2); } break; - case 3: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 3); + case 3: + for (i = 0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char)(total / 3); } break; - case 4: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 4); + case 4: + for (i = 0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char)(total / 4); } break; - case 5: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 5); + case 5: + for (i = 0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char)(total / 5); } break; - default: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / kernel_width); + default: + for (i = 0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char)(total / kernel_width); } break; - } - - for (; i < w; ++i) { - STBTT_assert(pixels[i] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i] = (unsigned char) (total / kernel_width); - } - - pixels += stride_in_bytes; - } -} - -static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_h = h - kernel_width; - int j; - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze - for (j=0; j < w; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - // make kernel_width a constant in common cases so compiler can optimize out the divide - switch (kernel_width) { - case 2: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 2); + } + + for (; i < w; ++i) { + STBTT_assert(pixels[i] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i] = (unsigned char)(total / kernel_width); + } + + pixels += stride_in_bytes; + } +} + +static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) { + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j = 0; j < w; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i = 0; i <= safe_h; ++i) { + total += pixels[i * stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i * stride_in_bytes]; + pixels[i * stride_in_bytes] = (unsigned char)(total / 2); } break; - case 3: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 3); + case 3: + for (i = 0; i <= safe_h; ++i) { + total += pixels[i * stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i * stride_in_bytes]; + pixels[i * stride_in_bytes] = (unsigned char)(total / 3); } break; - case 4: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 4); + case 4: + for (i = 0; i <= safe_h; ++i) { + total += pixels[i * stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i * stride_in_bytes]; + pixels[i * stride_in_bytes] = (unsigned char)(total / 4); } break; - case 5: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 5); + case 5: + for (i = 0; i <= safe_h; ++i) { + total += pixels[i * stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i * stride_in_bytes]; + pixels[i * stride_in_bytes] = (unsigned char)(total / 5); } break; - default: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + default: + for (i = 0; i <= safe_h; ++i) { + total += pixels[i * stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i * stride_in_bytes]; + pixels[i * stride_in_bytes] = (unsigned char)(total / kernel_width); } break; - } + } - for (; i < h; ++i) { - STBTT_assert(pixels[i*stride_in_bytes] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } + for (; i < h; ++i) { + STBTT_assert(pixels[i * stride_in_bytes] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i * stride_in_bytes] = (unsigned char)(total / kernel_width); + } - pixels += 1; - } + pixels += 1; + } } -static float stbtt__oversample_shift(int oversample) -{ - if (!oversample) - return 0.0f; +static float stbtt__oversample_shift(int oversample) { + if (!oversample) + return 0.0f; - // The prefilter is a box filter of width "oversample", - // which shifts phase by (oversample - 1)/2 pixels in - // oversampled space. We want to shift in the opposite - // direction to counter this. - return (float)-(oversample - 1) / (2.0f * (float)oversample); + // The prefilter is a box filter of width "oversample", + // which shifts phase by (oversample - 1)/2 pixels in + // oversampled space. We want to shift in the opposite + // direction to counter this. + return (float)-(oversample - 1) / (2.0f * (float)oversample); } // rects array must be big enough to accommodate all characters in the given ranges -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) -{ - int i,j,k; - int missing_glyph_added = 0; - - k=0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); - ranges[i].h_oversample = (unsigned char) spc->h_oversample; - ranges[i].v_oversample = (unsigned char) spc->v_oversample; - for (j=0; j < ranges[i].num_chars; ++j) { - int x0,y0,x1,y1; - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; - int glyph = stbtt_FindGlyphIndex(info, codepoint); - if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { - rects[k].w = rects[k].h = 0; - } else { - stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - &x0,&y0,&x1,&y1); - rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); - rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); - if (glyph == 0) - missing_glyph_added = 1; - } - ++k; - } - } +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, + stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) { + int i, j, k; + int missing_glyph_added = 0; + + k = 0; + for (i = 0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + ranges[i].h_oversample = (unsigned char)spc->h_oversample; + ranges[i].v_oversample = (unsigned char)spc->v_oversample; + for (j = 0; j < ranges[i].num_chars; ++j) { + int x0, y0, x1, y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL + ? ranges[i].first_unicode_codepoint_in_range + j + : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { + rects[k].w = rects[k].h = 0; + } else { + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale * spc->h_oversample, scale * spc->v_oversample, 0, 0, + &x0, &y0, &x1, &y1); + rects[k].w = (stbrp_coord)(x1 - x0 + spc->padding + spc->h_oversample - 1); + rects[k].h = (stbrp_coord)(y1 - y0 + spc->padding + spc->v_oversample - 1); + if (glyph == 0) + missing_glyph_added = 1; + } + ++k; + } + } - return k; + return k; } -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, - output, - out_w - (prefilter_x - 1), - out_h - (prefilter_y - 1), - out_stride, - scale_x, - scale_y, - shift_x, - shift_y, - glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, + int out_h, int out_stride, float scale_x, float scale_y, + float shift_x, float shift_y, int prefilter_x, int prefilter_y, + float *sub_x, float *sub_y, int glyph) { + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w - (prefilter_x - 1), out_h - (prefilter_y - 1), out_stride, + scale_x, scale_y, shift_x, shift_y, glyph); - if (prefilter_x > 1) - stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); + if (prefilter_x > 1) + stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); - if (prefilter_y > 1) - stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); + if (prefilter_y > 1) + stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); - *sub_x = stbtt__oversample_shift(prefilter_x); - *sub_y = stbtt__oversample_shift(prefilter_y); + *sub_x = stbtt__oversample_shift(prefilter_x); + *sub_y = stbtt__oversample_shift(prefilter_y); } // rects array must be big enough to accommodate all characters in the given ranges -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) -{ - int i,j,k, missing_glyph = -1, return_value = 1; - - // save current values - int old_h_over = spc->h_oversample; - int old_v_over = spc->v_oversample; - - k = 0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); - float recip_h,recip_v,sub_x,sub_y; - spc->h_oversample = ranges[i].h_oversample; - spc->v_oversample = ranges[i].v_oversample; - recip_h = 1.0f / spc->h_oversample; - recip_v = 1.0f / spc->v_oversample; - sub_x = stbtt__oversample_shift(spc->h_oversample); - sub_y = stbtt__oversample_shift(spc->v_oversample); - for (j=0; j < ranges[i].num_chars; ++j) { - stbrp_rect *r = &rects[k]; - if (r->was_packed && r->w != 0 && r->h != 0) { - stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; - int advance, lsb, x0,y0,x1,y1; - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; - int glyph = stbtt_FindGlyphIndex(info, codepoint); - stbrp_coord pad = (stbrp_coord) spc->padding; - - // pad on left and top - r->x += pad; - r->y += pad; - r->w -= pad; - r->h -= pad; - stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); - stbtt_GetGlyphBitmapBox(info, glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - &x0,&y0,&x1,&y1); - stbtt_MakeGlyphBitmapSubpixel(info, - spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w - spc->h_oversample+1, - r->h - spc->v_oversample+1, - spc->stride_in_bytes, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - glyph); - - if (spc->h_oversample > 1) - stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->h_oversample); - - if (spc->v_oversample > 1) - stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->v_oversample); - - bc->x0 = (stbtt_int16) r->x; - bc->y0 = (stbtt_int16) r->y; - bc->x1 = (stbtt_int16) (r->x + r->w); - bc->y1 = (stbtt_int16) (r->y + r->h); - bc->xadvance = scale * advance; - bc->xoff = (float) x0 * recip_h + sub_x; - bc->yoff = (float) y0 * recip_v + sub_y; - bc->xoff2 = (x0 + r->w) * recip_h + sub_x; - bc->yoff2 = (y0 + r->h) * recip_v + sub_y; - - if (glyph == 0) - missing_glyph = j; - } else if (spc->skip_missing) { - return_value = 0; - } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { - ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; - } else { - return_value = 0; // if any fail, report failure - } - - ++k; - } - } +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, + stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) { + int i, j, k, missing_glyph = -1, return_value = 1; + + // save current values + int old_h_over = spc->h_oversample; + int old_v_over = spc->v_oversample; + + k = 0; + for (i = 0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + float recip_h, recip_v, sub_x, sub_y; + spc->h_oversample = ranges[i].h_oversample; + spc->v_oversample = ranges[i].v_oversample; + recip_h = 1.0f / spc->h_oversample; + recip_v = 1.0f / spc->v_oversample; + sub_x = stbtt__oversample_shift(spc->h_oversample); + sub_y = stbtt__oversample_shift(spc->v_oversample); + for (j = 0; j < ranges[i].num_chars; ++j) { + stbrp_rect *r = &rects[k]; + if (r->was_packed && r->w != 0 && r->h != 0) { + stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0, y0, x1, y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL + ? ranges[i].first_unicode_codepoint_in_range + j + : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + stbrp_coord pad = (stbrp_coord)spc->padding; + + // pad on left and top + r->x += pad; + r->y += pad; + r->w -= pad; + r->h -= pad; + stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); + stbtt_GetGlyphBitmapBox(info, glyph, scale * spc->h_oversample, scale * spc->v_oversample, &x0, &y0, + &x1, &y1); + stbtt_MakeGlyphBitmapSubpixel(info, spc->pixels + r->x + r->y * spc->stride_in_bytes, + r->w - spc->h_oversample + 1, r->h - spc->v_oversample + 1, + spc->stride_in_bytes, scale * spc->h_oversample, + scale * spc->v_oversample, 0, 0, glyph); + + if (spc->h_oversample > 1) + stbtt__h_prefilter(spc->pixels + r->x + r->y * spc->stride_in_bytes, r->w, r->h, + spc->stride_in_bytes, spc->h_oversample); + + if (spc->v_oversample > 1) + stbtt__v_prefilter(spc->pixels + r->x + r->y * spc->stride_in_bytes, r->w, r->h, + spc->stride_in_bytes, spc->v_oversample); + + bc->x0 = (stbtt_int16)r->x; + bc->y0 = (stbtt_int16)r->y; + bc->x1 = (stbtt_int16)(r->x + r->w); + bc->y1 = (stbtt_int16)(r->y + r->h); + bc->xadvance = scale * advance; + bc->xoff = (float)x0 * recip_h + sub_x; + bc->yoff = (float)y0 * recip_v + sub_y; + bc->xoff2 = (x0 + r->w) * recip_h + sub_x; + bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + + if (glyph == 0) + missing_glyph = j; + } else if (spc->skip_missing) { + return_value = 0; + } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { + ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; + } else { + return_value = 0; // if any fail, report failure + } - // restore original values - spc->h_oversample = old_h_over; - spc->v_oversample = old_v_over; + ++k; + } + } - return return_value; + // restore original values + spc->h_oversample = old_h_over; + spc->v_oversample = old_v_over; + + return return_value; } -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) -{ - stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) { + stbrp_pack_rects((stbrp_context *)spc->pack_info, rects, num_rects); } -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) -{ - stbtt_fontinfo info; - int i,j,n, return_value = 1; - //stbrp_context *context = (stbrp_context *) spc->pack_info; - stbrp_rect *rects; +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, + stbtt_pack_range *ranges, int num_ranges) { + stbtt_fontinfo info; + int i, j, n, return_value = 1; + // stbrp_context *context = (stbrp_context *) spc->pack_info; + stbrp_rect *rects; - // flag all characters as NOT packed - for (i=0; i < num_ranges; ++i) - for (j=0; j < ranges[i].num_chars; ++j) - ranges[i].chardata_for_range[j].x0 = - ranges[i].chardata_for_range[j].y0 = - ranges[i].chardata_for_range[j].x1 = - ranges[i].chardata_for_range[j].y1 = 0; + // flag all characters as NOT packed + for (i = 0; i < num_ranges; ++i) + for (j = 0; j < ranges[i].num_chars; ++j) + ranges[i].chardata_for_range[j].x0 = ranges[i].chardata_for_range[j].y0 = + ranges[i].chardata_for_range[j].x1 = ranges[i].chardata_for_range[j].y1 = 0; - n = 0; - for (i=0; i < num_ranges; ++i) - n += ranges[i].num_chars; + n = 0; + for (i = 0; i < num_ranges; ++i) + n += ranges[i].num_chars; - rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); - if (rects == NULL) - return 0; + rects = (stbrp_rect *)STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); + if (rects == NULL) + return 0; - info.userdata = spc->user_allocator_context; - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); + info.userdata = spc->user_allocator_context; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, font_index)); - n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); + n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); - stbtt_PackFontRangesPackRects(spc, rects, n); + stbtt_PackFontRangesPackRects(spc, rects, n); - return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); - STBTT_free(rects, spc->user_allocator_context); - return return_value; + STBTT_free(rects, spc->user_allocator_context); + return return_value; } -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, - int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) -{ - stbtt_pack_range range; - range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; - range.array_of_unicode_codepoints = NULL; - range.num_chars = num_chars_in_range; - range.chardata_for_range = chardata_for_range; - range.font_size = font_size; - return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, + float font_size, int first_unicode_codepoint_in_range, int num_chars_in_range, + stbtt_packedchar *chardata_for_range) { + stbtt_pack_range range; + range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; + range.array_of_unicode_codepoints = NULL; + range.num_chars = num_chars_in_range; + range.chardata_for_range = chardata_for_range; + range.font_size = font_size; + return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); } -STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) -{ - int i_ascent, i_descent, i_lineGap; - float scale; - stbtt_fontinfo info; - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); - scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); - stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); - *ascent = (float) i_ascent * scale; - *descent = (float) i_descent * scale; - *lineGap = (float) i_lineGap * scale; -} - -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) -{ - float ipw = 1.0f / pw, iph = 1.0f / ph; - const stbtt_packedchar *b = chardata + char_index; - - if (align_to_integer) { - float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); - float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); - q->x0 = x; - q->y0 = y; - q->x1 = x + b->xoff2 - b->xoff; - q->y1 = y + b->yoff2 - b->yoff; - } else { - q->x0 = *xpos + b->xoff; - q->y0 = *ypos + b->yoff; - q->x1 = *xpos + b->xoff2; - q->y1 = *ypos + b->yoff2; - } +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, + float *descent, float *lineGap) { + int i_ascent, i_descent, i_lineGap; + float scale; + stbtt_fontinfo info; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); + scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); + stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); + *ascent = (float)i_ascent * scale; + *descent = (float)i_descent * scale; + *lineGap = (float)i_lineGap * scale; +} + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, + float *ypos, stbtt_aligned_quad *q, int align_to_integer) { + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_packedchar *b = chardata + char_index; - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; + if (align_to_integer) { + float x = (float)STBTT_ifloor((*xpos + b->xoff) + 0.5f); + float y = (float)STBTT_ifloor((*ypos + b->yoff) + 0.5f); + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } - *xpos += b->xadvance; + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; } ////////////////////////////////////////////////////////////////////////////// @@ -4392,380 +4481,385 @@ STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int // sdf computation // -#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) -#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) - -static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) -{ - float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; - float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; - float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; - float roperp = orig[1]*ray[0] - orig[0]*ray[1]; - - float a = q0perp - 2*q1perp + q2perp; - float b = q1perp - q0perp; - float c = q0perp - roperp; - - float s0 = 0., s1 = 0.; - int num_s = 0; - - if (a != 0.0) { - float discr = b*b - a*c; - if (discr > 0.0) { - float rcpna = -1 / a; - float d = (float) STBTT_sqrt(discr); - s0 = (b+d) * rcpna; - s1 = (b-d) * rcpna; - if (s0 >= 0.0 && s0 <= 1.0) +#define STBTT_min(a, b) ((a) < (b) ? (a) : (b)) +#define STBTT_max(a, b) ((a) < (b) ? (b) : (a)) + +static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], + float hits[2][2]) { + float q0perp = q0[1] * ray[0] - q0[0] * ray[1]; + float q1perp = q1[1] * ray[0] - q1[0] * ray[1]; + float q2perp = q2[1] * ray[0] - q2[0] * ray[1]; + float roperp = orig[1] * ray[0] - orig[0] * ray[1]; + + float a = q0perp - 2 * q1perp + q2perp; + float b = q1perp - q0perp; + float c = q0perp - roperp; + + float s0 = 0., s1 = 0.; + int num_s = 0; + + if (a != 0.0) { + float discr = b * b - a * c; + if (discr > 0.0) { + float rcpna = -1 / a; + float d = (float)STBTT_sqrt(discr); + s0 = (b + d) * rcpna; + s1 = (b - d) * rcpna; + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { + if (num_s == 0) + s0 = s1; + ++num_s; + } + } + } else { + // 2*b*s + c = 0 + // s = -c / (2*b) + s0 = c / (-2 * b); + if (s0 >= 0.0 && s0 <= 1.0) num_s = 1; - if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { - if (num_s == 0) s0 = s1; - ++num_s; - } - } - } else { - // 2*b*s + c = 0 - // s = -c / (2*b) - s0 = c / (-2 * b); - if (s0 >= 0.0 && s0 <= 1.0) - num_s = 1; - } - - if (num_s == 0) - return 0; - else { - float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); - float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; - - float q0d = q0[0]*rayn_x + q0[1]*rayn_y; - float q1d = q1[0]*rayn_x + q1[1]*rayn_y; - float q2d = q2[0]*rayn_x + q2[1]*rayn_y; - float rod = orig[0]*rayn_x + orig[1]*rayn_y; - - float q10d = q1d - q0d; - float q20d = q2d - q0d; - float q0rd = q0d - rod; - - hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; - hits[0][1] = a*s0+b; - - if (num_s > 1) { - hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; - hits[1][1] = a*s1+b; - return 2; - } else { - return 1; - } - } -} - -static int equal(float *a, float *b) -{ - return (a[0] == b[0] && a[1] == b[1]); -} - -static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) -{ - int i; - float orig[2], ray[2] = { 1, 0 }; - float y_frac; - int winding = 0; - - // make sure y never passes through a vertex of the shape - y_frac = (float) STBTT_fmod(y, 1.0f); - if (y_frac < 0.01f) - y += 0.01f; - else if (y_frac > 0.99f) - y -= 0.01f; - - orig[0] = x; - orig[1] = y; - - // test a ray from (-infinity,y) to (x,y) - for (i=0; i < nverts; ++i) { - if (verts[i].type == STBTT_vline) { - int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; - int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) - winding += (y0 < y1) ? 1 : -1; - } - } - if (verts[i].type == STBTT_vcurve) { - int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; - int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; - int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; - int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); - int by = STBTT_max(y0,STBTT_max(y1,y2)); - if (y > ay && y < by && x > ax) { - float q0[2],q1[2],q2[2]; - float hits[2][2]; - q0[0] = (float)x0; - q0[1] = (float)y0; - q1[0] = (float)x1; - q1[1] = (float)y1; - q2[0] = (float)x2; - q2[1] = (float)y2; - if (equal(q0,q1) || equal(q1,q2)) { - x0 = (int)verts[i-1].x; - y0 = (int)verts[i-1].y; - x1 = (int)verts[i ].x; - y1 = (int)verts[i ].y; - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) - winding += (y0 < y1) ? 1 : -1; - } - } else { - int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); - if (num_hits >= 1) - if (hits[0][0] < 0) - winding += (hits[0][1] < 0 ? -1 : 1); - if (num_hits >= 2) - if (hits[1][0] < 0) - winding += (hits[1][1] < 0 ? -1 : 1); + } + + if (num_s == 0) + return 0; + else { + float rcp_len2 = 1 / (ray[0] * ray[0] + ray[1] * ray[1]); + float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; + + float q0d = q0[0] * rayn_x + q0[1] * rayn_y; + float q1d = q1[0] * rayn_x + q1[1] * rayn_y; + float q2d = q2[0] * rayn_x + q2[1] * rayn_y; + float rod = orig[0] * rayn_x + orig[1] * rayn_y; + + float q10d = q1d - q0d; + float q20d = q2d - q0d; + float q0rd = q0d - rod; + + hits[0][0] = q0rd + s0 * (2.0f - 2.0f * s0) * q10d + s0 * s0 * q20d; + hits[0][1] = a * s0 + b; + + if (num_s > 1) { + hits[1][0] = q0rd + s1 * (2.0f - 2.0f * s1) * q10d + s1 * s1 * q20d; + hits[1][1] = a * s1 + b; + return 2; + } else { + return 1; + } + } +} + +static int equal(float *a, float *b) { return (a[0] == b[0] && a[1] == b[1]); } + +static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) { + int i; + float orig[2], ray[2] = {1, 0}; + float y_frac; + int winding = 0; + + // make sure y never passes through a vertex of the shape + y_frac = (float)STBTT_fmod(y, 1.0f); + if (y_frac < 0.01f) + y += 0.01f; + else if (y_frac > 0.99f) + y -= 0.01f; + + orig[0] = x; + orig[1] = y; + + // test a ray from (-infinity,y) to (x,y) + for (i = 0; i < nverts; ++i) { + if (verts[i].type == STBTT_vline) { + int x0 = (int)verts[i - 1].x, y0 = (int)verts[i - 1].y; + int x1 = (int)verts[i].x, y1 = (int)verts[i].y; + if (y > STBTT_min(y0, y1) && y < STBTT_max(y0, y1) && x > STBTT_min(x0, x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1 - x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; } - } - } - } - return winding; + } + if (verts[i].type == STBTT_vcurve) { + int x0 = (int)verts[i - 1].x, y0 = (int)verts[i - 1].y; + int x1 = (int)verts[i].cx, y1 = (int)verts[i].cy; + int x2 = (int)verts[i].x, y2 = (int)verts[i].y; + int ax = STBTT_min(x0, STBTT_min(x1, x2)), ay = STBTT_min(y0, STBTT_min(y1, y2)); + int by = STBTT_max(y0, STBTT_max(y1, y2)); + if (y > ay && y < by && x > ax) { + float q0[2], q1[2], q2[2]; + float hits[2][2]; + q0[0] = (float)x0; + q0[1] = (float)y0; + q1[0] = (float)x1; + q1[1] = (float)y1; + q2[0] = (float)x2; + q2[1] = (float)y2; + if (equal(q0, q1) || equal(q1, q2)) { + x0 = (int)verts[i - 1].x; + y0 = (int)verts[i - 1].y; + x1 = (int)verts[i].x; + y1 = (int)verts[i].y; + if (y > STBTT_min(y0, y1) && y < STBTT_max(y0, y1) && x > STBTT_min(x0, x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1 - x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } else { + int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); + if (num_hits >= 1) + if (hits[0][0] < 0) + winding += (hits[0][1] < 0 ? -1 : 1); + if (num_hits >= 2) + if (hits[1][0] < 0) + winding += (hits[1][1] < 0 ? -1 : 1); + } + } + } + } + return winding; } -static float stbtt__cuberoot( float x ) -{ - if (x<0) - return -(float) STBTT_pow(-x,1.0f/3.0f); - else - return (float) STBTT_pow( x,1.0f/3.0f); +static float stbtt__cuberoot(float x) { + if (x < 0) + return -(float)STBTT_pow(-x, 1.0f / 3.0f); + else + return (float)STBTT_pow(x, 1.0f / 3.0f); } // x^3 + a*x^2 + b*x + c = 0 -static int stbtt__solve_cubic(float a, float b, float c, float* r) -{ - float s = -a / 3; - float p = b - a*a / 3; - float q = a * (2*a*a - 9*b) / 27 + c; - float p3 = p*p*p; - float d = q*q + 4*p3 / 27; - if (d >= 0) { - float z = (float) STBTT_sqrt(d); - float u = (-q + z) / 2; - float v = (-q - z) / 2; - u = stbtt__cuberoot(u); - v = stbtt__cuberoot(v); - r[0] = s + u + v; - return 1; - } else { - float u = (float) STBTT_sqrt(-p/3); - float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative - float m = (float) STBTT_cos(v); - float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; - r[0] = s + u * 2 * m; - r[1] = s - u * (m + n); - r[2] = s - u * (m - n); - - //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? - //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); - //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); - return 3; - } -} - -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) -{ - float scale_x = scale, scale_y = scale; - int ix0,iy0,ix1,iy1; - int w,h; - unsigned char *data; - - if (scale == 0) return NULL; - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); - - // if empty, return NULL - if (ix0 == ix1 || iy0 == iy1) - return NULL; - - ix0 -= padding; - iy0 -= padding; - ix1 += padding; - iy1 += padding; - - w = (ix1 - ix0); - h = (iy1 - iy0); - - if (width ) *width = w; - if (height) *height = h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; - - // invert for y-downwards bitmaps - scale_y = -scale_y; - - { - int x,y,i,j; - float *precompute; - stbtt_vertex *verts; - int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); - data = (unsigned char *) STBTT_malloc(w * h, info->userdata); - precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); - - for (i=0,j=num_verts-1; i < num_verts; j=i++) { - if (verts[i].type == STBTT_vline) { - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; - float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); - precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; - } else if (verts[i].type == STBTT_vcurve) { - float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; - float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; - float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; - float len2 = bx*bx + by*by; - if (len2 != 0.0f) - precompute[i] = 1.0f / (bx*bx + by*by); - else - precompute[i] = 0.0f; - } else - precompute[i] = 0.0f; - } - - for (y=iy0; y < iy1; ++y) { - for (x=ix0; x < ix1; ++x) { - float val; - float min_dist = 999999.0f; - float sx = (float) x + 0.5f; - float sy = (float) y + 0.5f; - float x_gspace = (sx / scale_x); - float y_gspace = (sy / scale_y); - - int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path - - for (i=0; i < num_verts; ++i) { - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - - if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { - float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; - - float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); - - // coarse culling against bbox - //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && - // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) - dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; - STBTT_assert(i != 0); - if (dist < min_dist) { - // check position along line - // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) - // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) - float dx = x1-x0, dy = y1-y0; - float px = x0-sx, py = y0-sy; - // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy - // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve - float t = -(px*dx + py*dy) / (dx*dx + dy*dy); - if (t >= 0.0f && t <= 1.0f) - min_dist = dist; - } - } else if (verts[i].type == STBTT_vcurve) { - float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; - float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; - float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); - float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); - float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); - float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); - // coarse culling against bbox to avoid computing cubic unnecessarily - if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { - int num=0; - float ax = x1-x0, ay = y1-y0; - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; - float mx = x0 - sx, my = y0 - sy; - float res[3] = {0.f,0.f,0.f}; - float px,py,t,it,dist2; - float a_inv = precompute[i]; - if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula - float a = 3*(ax*bx + ay*by); - float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); - float c = mx*ax+my*ay; - if (a == 0.0) { // if a is 0, it's linear - if (b != 0.0) { - res[num++] = -c/b; - } - } else { - float discriminant = b*b - 4*a*c; - if (discriminant < 0) - num = 0; - else { - float root = (float) STBTT_sqrt(discriminant); - res[0] = (-b - root)/(2*a); - res[1] = (-b + root)/(2*a); - num = 2; // don't bother distinguishing 1-solution case, as code below will still work - } - } - } else { - float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point - float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; - float d = (mx*ax+my*ay) * a_inv; - num = stbtt__solve_cubic(b, c, d, res); - } - dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); - - if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { - t = res[0], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { - t = res[1], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { - t = res[2], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); +static int stbtt__solve_cubic(float a, float b, float c, float *r) { + float s = -a / 3; + float p = b - a * a / 3; + float q = a * (2 * a * a - 9 * b) / 27 + c; + float p3 = p * p * p; + float d = q * q + 4 * p3 / 27; + if (d >= 0) { + float z = (float)STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float)STBTT_sqrt(-p / 3); + float v = (float)STBTT_acos(-STBTT_sqrt(-27 / p3) * q / 2) / 3; // p3 must be negative, since d is negative + float m = (float)STBTT_cos(v); + float n = (float)STBTT_cos(v - 3.141592 / 2) * 1.732050808f; + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); + + // STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, + // though they're in bezier t parameter units so maybe? STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < + // 0.05f); STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); + return 3; + } +} + +STBTT_DEF unsigned char *stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, + unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, + int *xoff, int *yoff) { + float scale_x = scale, scale_y = scale; + int ix0, iy0, ix1, iy1; + int w, h; + unsigned char *data; + + if (scale == 0) + return NULL; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f, 0.0f, &ix0, &iy0, &ix1, &iy1); + + // if empty, return NULL + if (ix0 == ix1 || iy0 == iy1) + return NULL; + + ix0 -= padding; + iy0 -= padding; + ix1 += padding; + iy1 += padding; + + w = (ix1 - ix0); + h = (iy1 - iy0); + + if (width) + *width = w; + if (height) + *height = h; + if (xoff) + *xoff = ix0; + if (yoff) + *yoff = iy0; + + // invert for y-downwards bitmaps + scale_y = -scale_y; + + { + int x, y, i, j; + float *precompute; + stbtt_vertex *verts; + int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); + data = (unsigned char *)STBTT_malloc(w * h, info->userdata); + precompute = (float *)STBTT_malloc(num_verts * sizeof(float), info->userdata); + + for (i = 0, j = num_verts - 1; i < num_verts; j = i++) { + if (verts[i].type == STBTT_vline) { + float x0 = verts[i].x * scale_x, y0 = verts[i].y * scale_y; + float x1 = verts[j].x * scale_x, y1 = verts[j].y * scale_y; + float dist = (float)STBTT_sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); + precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[j].x * scale_x, y2 = verts[j].y * scale_y; + float x1 = verts[i].cx * scale_x, y1 = verts[i].cy * scale_y; + float x0 = verts[i].x * scale_x, y0 = verts[i].y * scale_y; + float bx = x0 - 2 * x1 + x2, by = y0 - 2 * y1 + y2; + float len2 = bx * bx + by * by; + if (len2 != 0.0f) + precompute[i] = 1.0f / (bx * bx + by * by); + else + precompute[i] = 0.0f; + } else + precompute[i] = 0.0f; + } + + for (y = iy0; y < iy1; ++y) { + for (x = ix0; x < ix1; ++x) { + float val; + float min_dist = 999999.0f; + float sx = (float)x + 0.5f; + float sy = (float)y + 0.5f; + float x_gspace = (sx / scale_x); + float y_gspace = (sy / scale_y); + + int winding = stbtt__compute_crossings_x( + x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs + // to be line vs. non-tesselated curves so a new path + + for (i = 0; i < num_verts; ++i) { + float x0 = verts[i].x * scale_x, y0 = verts[i].y * scale_y; + + if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { + float x1 = verts[i - 1].x * scale_x, y1 = verts[i - 1].y * scale_y; + + float dist, dist2 = (x0 - sx) * (x0 - sx) + (y0 - sy) * (y0 - sy); if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - } - } + min_dist = (float)STBTT_sqrt(dist2); + + // coarse culling against bbox + // if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && + // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) + dist = (float)STBTT_fabs((x1 - x0) * (y0 - sy) - (y1 - y0) * (x0 - sx)) * precompute[i]; + STBTT_assert(i != 0); + if (dist < min_dist) { + // check position along line + // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) + // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) + float dx = x1 - x0, dy = y1 - y0; + float px = x0 - sx, py = y0 - sy; + // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + + // t^2*dy*dy derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve + float t = -(px * dx + py * dy) / (dx * dx + dy * dy); + if (t >= 0.0f && t <= 1.0f) + min_dist = dist; + } + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[i - 1].x * scale_x, y2 = verts[i - 1].y * scale_y; + float x1 = verts[i].cx * scale_x, y1 = verts[i].cy * scale_y; + float box_x0 = STBTT_min(STBTT_min(x0, x1), x2); + float box_y0 = STBTT_min(STBTT_min(y0, y1), y2); + float box_x1 = STBTT_max(STBTT_max(x0, x1), x2); + float box_y1 = STBTT_max(STBTT_max(y0, y1), y2); + // coarse culling against bbox to avoid computing cubic unnecessarily + if (sx > box_x0 - min_dist && sx < box_x1 + min_dist && sy > box_y0 - min_dist && + sy < box_y1 + min_dist) { + int num = 0; + float ax = x1 - x0, ay = y1 - y0; + float bx = x0 - 2 * x1 + x2, by = y0 - 2 * y1 + y2; + float mx = x0 - sx, my = y0 - sy; + float res[3] = {0.f, 0.f, 0.f}; + float px, py, t, it, dist2; + float a_inv = precompute[i]; + if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula + float a = 3 * (ax * bx + ay * by); + float b = 2 * (ax * ax + ay * ay) + (mx * bx + my * by); + float c = mx * ax + my * ay; + if (a == 0.0) { // if a is 0, it's linear + if (b != 0.0) { + res[num++] = -c / b; + } + } else { + float discriminant = b * b - 4 * a * c; + if (discriminant < 0) + num = 0; + else { + float root = (float)STBTT_sqrt(discriminant); + res[0] = (-b - root) / (2 * a); + res[1] = (-b + root) / (2 * a); + num = 2; // don't bother distinguishing 1-solution case, as code below will + // still work + } + } + } else { + float b = 3 * (ax * bx + ay * by) * + a_inv; // could precompute this as it doesn't depend on sample point + float c = (2 * (ax * ax + ay * ay) + (mx * bx + my * by)) * a_inv; + float d = (mx * ax + my * ay) * a_inv; + num = stbtt__solve_cubic(b, c, d, res); + } + dist2 = (x0 - sx) * (x0 - sx) + (y0 - sy) * (y0 - sy); + if (dist2 < min_dist * min_dist) + min_dist = (float)STBTT_sqrt(dist2); + + if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { + t = res[0], it = 1.0f - t; + px = it * it * x0 + 2 * t * it * x1 + t * t * x2; + py = it * it * y0 + 2 * t * it * y1 + t * t * y2; + dist2 = (px - sx) * (px - sx) + (py - sy) * (py - sy); + if (dist2 < min_dist * min_dist) + min_dist = (float)STBTT_sqrt(dist2); + } + if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { + t = res[1], it = 1.0f - t; + px = it * it * x0 + 2 * t * it * x1 + t * t * x2; + py = it * it * y0 + 2 * t * it * y1 + t * t * y2; + dist2 = (px - sx) * (px - sx) + (py - sy) * (py - sy); + if (dist2 < min_dist * min_dist) + min_dist = (float)STBTT_sqrt(dist2); + } + if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { + t = res[2], it = 1.0f - t; + px = it * it * x0 + 2 * t * it * x1 + t * t * x2; + py = it * it * y0 + 2 * t * it * y1 + t * t * y2; + dist2 = (px - sx) * (px - sx) + (py - sy) * (py - sy); + if (dist2 < min_dist * min_dist) + min_dist = (float)STBTT_sqrt(dist2); + } + } + } + } + if (winding == 0) + min_dist = -min_dist; // if outside the shape, value is negative + val = onedge_value + pixel_dist_scale * min_dist; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + data[(y - iy0) * w + (x - ix0)] = (unsigned char)val; } - if (winding == 0) - min_dist = -min_dist; // if outside the shape, value is negative - val = onedge_value + pixel_dist_scale * min_dist; - if (val < 0) - val = 0; - else if (val > 255) - val = 255; - data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; - } - } - STBTT_free(precompute, info->userdata); - STBTT_free(verts, info->userdata); - } - return data; + } + STBTT_free(precompute, info->userdata); + STBTT_free(verts, info->userdata); + } + return data; } -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); +STBTT_DEF unsigned char *stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, + unsigned char onedge_value, float pixel_dist_scale, int *width, + int *height, int *xoff, int *yoff) { + return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, + pixel_dist_scale, width, height, xoff, yoff); } -STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); -} +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) { STBTT_free(bitmap, userdata); } ////////////////////////////////////////////////////////////////////////////// // @@ -4773,158 +4867,185 @@ STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) // // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) -{ - stbtt_int32 i=0; - - // convert utf16 to utf8 and compare the results while converting - while (len2) { - stbtt_uint16 ch = s2[0]*256 + s2[1]; - if (ch < 0x80) { - if (i >= len1) return -1; - if (s1[i++] != ch) return -1; - } else if (ch < 0x800) { - if (i+1 >= len1) return -1; - if (s1[i++] != 0xc0 + (ch >> 6)) return -1; - if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; - } else if (ch >= 0xd800 && ch < 0xdc00) { - stbtt_uint32 c; - stbtt_uint16 ch2 = s2[2]*256 + s2[3]; - if (i+3 >= len1) return -1; - c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; - if (s1[i++] != 0xf0 + (c >> 18)) return -1; - if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; - s2 += 2; // plus another 2 below - len2 -= 2; - } else if (ch >= 0xdc00 && ch < 0xe000) { - return -1; - } else { - if (i+2 >= len1) return -1; - if (s1[i++] != 0xe0 + (ch >> 12)) return -1; - if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; - } - s2 += 2; - len2 -= 2; - } - return i; -} - -static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) -{ - return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, + stbtt_int32 len2) { + stbtt_int32 i = 0; + + // convert utf16 to utf8 and compare the results while converting + while (len2) { + stbtt_uint16 ch = s2[0] * 256 + s2[1]; + if (ch < 0x80) { + if (i >= len1) + return -1; + if (s1[i++] != ch) + return -1; + } else if (ch < 0x800) { + if (i + 1 >= len1) + return -1; + if (s1[i++] != 0xc0 + (ch >> 6)) + return -1; + if (s1[i++] != 0x80 + (ch & 0x3f)) + return -1; + } else if (ch >= 0xd800 && ch < 0xdc00) { + stbtt_uint32 c; + stbtt_uint16 ch2 = s2[2] * 256 + s2[3]; + if (i + 3 >= len1) + return -1; + c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; + if (s1[i++] != 0xf0 + (c >> 18)) + return -1; + if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) + return -1; + if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) + return -1; + if (s1[i++] != 0x80 + ((c)&0x3f)) + return -1; + s2 += 2; // plus another 2 below + len2 -= 2; + } else if (ch >= 0xdc00 && ch < 0xe000) { + return -1; + } else { + if (i + 2 >= len1) + return -1; + if (s1[i++] != 0xe0 + (ch >> 12)) + return -1; + if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) + return -1; + if (s1[i++] != 0x80 + ((ch)&0x3f)) + return -1; + } + s2 += 2; + len2 -= 2; + } + return i; +} + +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) { + return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8 *)s1, len1, (stbtt_uint8 *)s2, len2); } // returns results in whatever encoding you request... but note that 2-byte encodings // will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) -{ - stbtt_int32 i,count,stringOffset; - stbtt_uint8 *fc = font->data; - stbtt_uint32 offset = font->fontstart; - stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return NULL; - - count = ttUSHORT(fc+nm+2); - stringOffset = nm + ttUSHORT(fc+nm+4); - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) - && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { - *length = ttUSHORT(fc+loc+8); - return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); - } - } - return NULL; -} - -static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) -{ - stbtt_int32 i; - stbtt_int32 count = ttUSHORT(fc+nm+2); - stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); - - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - stbtt_int32 id = ttUSHORT(fc+loc+6); - if (id == target_id) { - // find the encoding - stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); - - // is this a Unicode encoding? - if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { - stbtt_int32 slen = ttUSHORT(fc+loc+8); - stbtt_int32 off = ttUSHORT(fc+loc+10); - - // check if there's a prefix match - stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); - if (matchlen >= 0) { - // check for target_id+1 immediately following, with same encoding & language - if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { - slen = ttUSHORT(fc+loc+12+8); - off = ttUSHORT(fc+loc+12+10); - if (slen == 0) { - if (matchlen == nlen) - return 1; - } else if (matchlen < nlen && name[matchlen] == ' ') { - ++matchlen; - if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) - return 1; - } - } else { - // if nothing immediately following - if (matchlen == nlen) - return 1; - } +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, + int languageID, int nameID) { + stbtt_int32 i, count, stringOffset; + stbtt_uint8 *fc = font->data; + stbtt_uint32 offset = font->fontstart; + stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); + if (!nm) + return NULL; + + count = ttUSHORT(fc + nm + 2); + stringOffset = nm + ttUSHORT(fc + nm + 4); + for (i = 0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + if (platformID == ttUSHORT(fc + loc + 0) && encodingID == ttUSHORT(fc + loc + 2) && + languageID == ttUSHORT(fc + loc + 4) && nameID == ttUSHORT(fc + loc + 6)) { + *length = ttUSHORT(fc + loc + 8); + return (const char *)(fc + stringOffset + ttUSHORT(fc + loc + 10)); + } + } + return NULL; +} + +static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, + stbtt_int32 target_id, stbtt_int32 next_id) { + stbtt_int32 i; + stbtt_int32 count = ttUSHORT(fc + nm + 2); + stbtt_int32 stringOffset = nm + ttUSHORT(fc + nm + 4); + + for (i = 0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + stbtt_int32 id = ttUSHORT(fc + loc + 6); + if (id == target_id) { + // find the encoding + stbtt_int32 platform = ttUSHORT(fc + loc + 0), encoding = ttUSHORT(fc + loc + 2), + language = ttUSHORT(fc + loc + 4); + + // is this a Unicode encoding? + if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { + stbtt_int32 slen = ttUSHORT(fc + loc + 8); + stbtt_int32 off = ttUSHORT(fc + loc + 10); + + // check if there's a prefix match + stbtt_int32 matchlen = + stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc + stringOffset + off, slen); + if (matchlen >= 0) { + // check for target_id+1 immediately following, with same encoding & language + if (i + 1 < count && ttUSHORT(fc + loc + 12 + 6) == next_id && + ttUSHORT(fc + loc + 12) == platform && ttUSHORT(fc + loc + 12 + 2) == encoding && + ttUSHORT(fc + loc + 12 + 4) == language) { + slen = ttUSHORT(fc + loc + 12 + 8); + off = ttUSHORT(fc + loc + 12 + 10); + if (slen == 0) { + if (matchlen == nlen) + return 1; + } else if (matchlen < nlen && name[matchlen] == ' ') { + ++matchlen; + if (stbtt_CompareUTF8toUTF16_bigendian_internal((char *)(name + matchlen), nlen - matchlen, + (char *)(fc + stringOffset + off), slen)) + return 1; + } + } else { + // if nothing immediately following + if (matchlen == nlen) + return 1; + } + } } - } - // @TODO handle other encodings - } - } - return 0; + // @TODO handle other encodings + } + } + return 0; } -static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) -{ - stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); - stbtt_uint32 nm,hd; - if (!stbtt__isfont(fc+offset)) return 0; - - // check italics/bold/underline flags in macStyle... - if (flags) { - hd = stbtt__find_table(fc, offset, "head"); - if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; - } - - nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return 0; - - if (flags) { - // if we checked the macStyle flags, then just check the family and ignore the subfamily - if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } else { - if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } +static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) { + stbtt_int32 nlen = (stbtt_int32)STBTT_strlen((char *)name); + stbtt_uint32 nm, hd; + if (!stbtt__isfont(fc + offset)) + return 0; - return 0; -} - -static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) -{ - stbtt_int32 i; - for (i=0;;++i) { - stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); - if (off < 0) return off; - if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) - return off; - } + // check italics/bold/underline flags in macStyle... + if (flags) { + hd = stbtt__find_table(fc, offset, "head"); + if ((ttUSHORT(fc + hd + 44) & 7) != (flags & 7)) + return 0; + } + + nm = stbtt__find_table(fc, offset, "name"); + if (!nm) + return 0; + + if (flags) { + // if we checked the macStyle flags, then just check the family and ignore the subfamily + if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) + return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) + return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) + return 1; + } else { + if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) + return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) + return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) + return 1; + } + + return 0; +} + +static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) { + stbtt_int32 i; + for (i = 0;; ++i) { + stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); + if (off < 0) + return off; + if (stbtt__matches((stbtt_uint8 *)font_collection, off, (stbtt_uint8 *)name_utf8, flags)) + return off; + } } #if defined(__GNUC__) || defined(__clang__) @@ -4932,36 +5053,30 @@ static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char #pragma GCC diagnostic ignored "-Wcast-qual" #endif -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, - float pixel_height, unsigned char *pixels, int pw, int ph, - int first_char, int num_chars, stbtt_bakedchar *chardata) -{ - return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, float pixel_height, unsigned char *pixels, + int pw, int ph, int first_char, int num_chars, stbtt_bakedchar *chardata) { + return stbtt_BakeFontBitmap_internal((unsigned char *)data, offset, pixel_height, pixels, pw, ph, first_char, + num_chars, chardata); } -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) -{ - return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) { + return stbtt_GetFontOffsetForIndex_internal((unsigned char *)data, index); } -STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) -{ - return stbtt_GetNumberOfFonts_internal((unsigned char *) data); +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) { + return stbtt_GetNumberOfFonts_internal((unsigned char *)data); } -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) -{ - return stbtt_InitFont_internal(info, (unsigned char *) data, offset); +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) { + return stbtt_InitFont_internal(info, (unsigned char *)data, offset); } -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) -{ - return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) { + return stbtt_FindMatchingFont_internal((unsigned char *)fontdata, (char *)name, flags); } -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) -{ - return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) { + return stbtt_CompareUTF8toUTF16_bigendian_internal((char *)s1, len1, (char *)s2, len2); } #if defined(__GNUC__) || defined(__clang__) @@ -4970,7 +5085,6 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const #endif // STB_TRUETYPE_IMPLEMENTATION - // FULL VERSION HISTORY // // 1.25 (2021-07-11) many fixes diff --git a/src/vectors.h b/src/vectors.h index 090dfab..88800c6 100644 --- a/src/vectors.h +++ b/src/vectors.h @@ -25,192 +25,143 @@ #include "vkvg_internal.h" typedef struct { - float x; - float y; -}vec2; + float x; + float y; +} vec2; -static const vec2 vec2_unit_x = {1.f,0}; -static const vec2 vec2_unit_y = {0,1.f}; +static const vec2 vec2_unit_x = {1.f, 0}; +static const vec2 vec2_unit_y = {0, 1.f}; typedef struct { - double x; - double y; -}vec2d; + double x; + double y; +} vec2d; /*const vec2d vec2d_unit_x = {1.0,0}; const vec2d vec2d_unit_y = {0,1.0};*/ typedef struct { - float x; - float y; - float z; -}vec3; + float x; + float y; + float z; +} vec3; typedef struct { - union { - float x; - float r; - float xMin; - }; - union { - float y; - float g; - float yMin; - }; - union { - float z; - float width; - float b; - float xMax; - }; - union { - float w; - float height; - float a; - float yMax; - }; - -}vec4; + union { + float x; + float r; + float xMin; + }; + union { + float y; + float g; + float yMin; + }; + union { + float z; + float width; + float b; + float xMax; + }; + union { + float w; + float height; + float a; + float yMax; + }; + +} vec4; typedef struct { - uint16_t x; - uint16_t y; - uint16_t z; - uint16_t w; -}vec4i16; + uint16_t x; + uint16_t y; + uint16_t z; + uint16_t w; +} vec4i16; typedef struct { - int16_t x; - int16_t y; -}vec2i16; + int16_t x; + int16_t y; +} vec2i16; typedef struct { - vec2 row0; - vec2 row1; -}mat2; + vec2 row0; + vec2 row1; +} mat2; // compute length of float vector 2d -vkvg_inline float vec2_length(vec2 v){ - return sqrtf (v.x*v.x + v.y*v.y); -} +vkvg_inline float vec2_length(vec2 v) { return sqrtf(v.x * v.x + v.y * v.y); } // compute normal direction vector from line defined by 2 points in double precision -vkvg_inline vec2d vec2d_line_norm(vec2d a, vec2d b) -{ - vec2d d = {b.x - a.x, b.y - a.y}; - double md = sqrt (d.x*d.x + d.y*d.y); - d.x/=md; - d.y/=md; - return d; +vkvg_inline vec2d vec2d_line_norm(vec2d a, vec2d b) { + vec2d d = {b.x - a.x, b.y - a.y}; + double md = sqrt(d.x * d.x + d.y * d.y); + d.x /= md; + d.y /= md; + return d; } // compute normal direction vector from line defined by 2 points -vkvg_inline vec2 vec2_line_norm(vec2 a, vec2 b) -{ - vec2 d = {b.x - a.x, b.y - a.y}; - float md = sqrtf (d.x*d.x + d.y*d.y); - d.x/=md; - d.y/=md; - return d; +vkvg_inline vec2 vec2_line_norm(vec2 a, vec2 b) { + vec2 d = {b.x - a.x, b.y - a.y}; + float md = sqrtf(d.x * d.x + d.y * d.y); + d.x /= md; + d.y /= md; + return d; } // compute sum of two double precision vectors -vkvg_inline vec2d vec2d_add (vec2d a, vec2d b){ - return (vec2d){a.x + b.x, a.y + b.y}; -} +vkvg_inline vec2d vec2d_add(vec2d a, vec2d b) { return (vec2d){a.x + b.x, a.y + b.y}; } // compute subbstraction of two double precision vectors -vkvg_inline vec2d vec2d_sub (vec2d a, vec2d b){ - return (vec2d){a.x - b.x, a.y - b.y}; -} +vkvg_inline vec2d vec2d_sub(vec2d a, vec2d b) { return (vec2d){a.x - b.x, a.y - b.y}; } // multiply 2d vector by scalar -vkvg_inline vec2d vec2d_mult_s(vec2d a, double m){ - return (vec2d){a.x*m,a.y*m}; -} -vkvg_inline vec2d vec2d_div_s(vec2d a, double m){ - return (vec2d){a.x/m,a.y/m}; -} +vkvg_inline vec2d vec2d_mult_s(vec2d a, double m) { return (vec2d){a.x * m, a.y * m}; } +vkvg_inline vec2d vec2d_div_s(vec2d a, double m) { return (vec2d){a.x / m, a.y / m}; } // compute length of double vector 2d -vkvg_inline double vec2d_length(vec2d v){ - return sqrt (v.x*v.x + v.y*v.y); -} +vkvg_inline double vec2d_length(vec2d v) { return sqrt(v.x * v.x + v.y * v.y); } // normalize double vector -vkvg_inline vec2d vec2d_norm(vec2d a) -{ - double m = sqrt (a.x*a.x + a.y*a.y); - return (vec2d){a.x/m, a.y/m}; +vkvg_inline vec2d vec2d_norm(vec2d a) { + double m = sqrt(a.x * a.x + a.y * a.y); + return (vec2d){a.x / m, a.y / m}; } // compute perpendicular vector -vkvg_inline vec2d vec2d_perp (vec2d a){ - return (vec2d){a.y, -a.x}; -} -vkvg_inline bool vec2d_isnan (vec2d v){ - return (bool)(isnan (v.x) || isnan (v.y)); -} - +vkvg_inline vec2d vec2d_perp(vec2d a) { return (vec2d){a.y, -a.x}; } +vkvg_inline bool vec2d_isnan(vec2d v) { return (bool)(isnan(v.x) || isnan(v.y)); } // test equality of two single precision vectors -vkvg_inline bool vec2_equ (vec2 a, vec2 b){ - return (EQUF(a.x,b.x)&EQUF(a.y,b.y)); -} +vkvg_inline bool vec2_equ(vec2 a, vec2 b) { return (EQUF(a.x, b.x) & EQUF(a.y, b.y)); } // compute sum of two single precision vectors -vkvg_inline vec2 vec2_add (vec2 a, vec2 b){ - return (vec2){a.x + b.x, a.y + b.y}; -} +vkvg_inline vec2 vec2_add(vec2 a, vec2 b) { return (vec2){a.x + b.x, a.y + b.y}; } // compute subbstraction of two single precision vectors -vkvg_inline vec2 vec2_sub (vec2 a, vec2 b){ - return (vec2){a.x - b.x, a.y - b.y}; -} +vkvg_inline vec2 vec2_sub(vec2 a, vec2 b) { return (vec2){a.x - b.x, a.y - b.y}; } // multiply 2d vector by scalar -vkvg_inline vec2 vec2_mult_s(vec2 a, float m){ - return (vec2){a.x*m,a.y*m}; -} +vkvg_inline vec2 vec2_mult_s(vec2 a, float m) { return (vec2){a.x * m, a.y * m}; } // devide 2d vector by scalar -vkvg_inline vec2 vec2_div_s(vec2 a, float m){ - return (vec2){a.x/m,a.y/m}; -} +vkvg_inline vec2 vec2_div_s(vec2 a, float m) { return (vec2){a.x / m, a.y / m}; } // normalize float vector -vkvg_inline vec2 vec2_norm(vec2 a) -{ - float m = sqrtf (a.x*a.x + a.y*a.y); - return (vec2){a.x/m, a.y/m}; +vkvg_inline vec2 vec2_norm(vec2 a) { + float m = sqrtf(a.x * a.x + a.y * a.y); + return (vec2){a.x / m, a.y / m}; } // compute perpendicular vector -vkvg_inline vec2 vec2_perp (vec2 a){ - return (vec2){a.y, -a.x}; -} +vkvg_inline vec2 vec2_perp(vec2 a) { return (vec2){a.y, -a.x}; } // compute opposite of single precision vector -vkvg_inline void vec2_inv (vec2* v){ - v->x = -v->x; - v->y = -v->y; +vkvg_inline void vec2_inv(vec2 *v) { + v->x = -v->x; + v->y = -v->y; } // test if one component of float vector is nan -vkvg_inline bool vec2_isnan (vec2 v){ - return (bool)(isnan (v.x) || isnan (v.y)); -} +vkvg_inline bool vec2_isnan(vec2 v) { return (bool)(isnan(v.x) || isnan(v.y)); } // test if one component of double vector is nan -vkvg_inline float vec2_dot (vec2 a, vec2 b) { - return (a.x * b.x) + (a.y * b.y); -} -vkvg_inline float vec2_det (vec2 a, vec2 b) { - return a.x * b.y - a.y * b.x; -} -vkvg_inline float vec2_slope (vec2 a, vec2 b) { - return (b.y - a.y) / (b.x - a.x); -} - +vkvg_inline float vec2_dot(vec2 a, vec2 b) { return (a.x * b.x) + (a.y * b.y); } +vkvg_inline float vec2_det(vec2 a, vec2 b) { return a.x * b.y - a.y * b.x; } +vkvg_inline float vec2_slope(vec2 a, vec2 b) { return (b.y - a.y) / (b.x - a.x); } // convert double precision vector to single precision -vkvg_inline vec2 vec2d_to_vec2(vec2d vd){ - return (vec2){(float)vd.x,(float)vd.y}; -} -vkvg_inline bool vec4_equ (vec4 a, vec4 b){ - return (EQUF(a.x,b.x)&EQUF(a.y,b.y)&EQUF(a.z,b.z)&EQUF(a.w,b.w)); -} -vkvg_inline vec2 mat2_mult_vec2 (mat2 m, vec2 v) { - return (vec2){ - (m.row0.x * v.x) + (m.row0.y * v.y), - (m.row1.x * v.x) + (m.row1.y * v.y) - }; +vkvg_inline vec2 vec2d_to_vec2(vec2d vd) { return (vec2){(float)vd.x, (float)vd.y}; } +vkvg_inline bool vec4_equ(vec4 a, vec4 b) { + return (EQUF(a.x, b.x) & EQUF(a.y, b.y) & EQUF(a.z, b.z) & EQUF(a.w, b.w)); } -vkvg_inline float mat2_det (mat2* m) { - return (m->row0.x * m->row1.y) - (m->row0.y * m->row1.y); +vkvg_inline vec2 mat2_mult_vec2(mat2 m, vec2 v) { + return (vec2){(m.row0.x * v.x) + (m.row0.y * v.y), (m.row1.x * v.x) + (m.row1.y * v.y)}; } +vkvg_inline float mat2_det(mat2 *m) { return (m->row0.x * m->row1.y) - (m->row0.y * m->row1.y); } #endif diff --git a/src/vkvg_context.c b/src/vkvg_context.c index cfbabe8..877afb8 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -9,1681 +9,1674 @@ #include "vkh_queue.h" #ifdef DEBUG - static vec2 debugLinePoints[1000]; - static uint32_t dlpCount = 0; - #if defined (VKVG_DBG_UTILS) - const float DBG_LAB_COLOR_SAV[4] = {1,0,1,1}; - const float DBG_LAB_COLOR_CLIP[4] = {0,1,1,1}; - #endif +static vec2 debugLinePoints[1000]; +static uint32_t dlpCount = 0; +#if defined(VKVG_DBG_UTILS) +const float DBG_LAB_COLOR_SAV[4] = {1, 0, 1, 1}; +const float DBG_LAB_COLOR_CLIP[4] = {0, 1, 1, 1}; +#endif #endif -//todo:this could be used to define a default background +// todo:this could be used to define a default background static VkClearValue clearValues[3] = { - { .color.float32 = {0,0,0,0} }, - { .depthStencil = {1.0f, 0} }, - { .color.float32 = {0,0,0,0} } -}; - -void _init_ctx (VkvgContext ctx) { - ctx->lineWidth = 1; - ctx->miterLimit = 10; - ctx->curOperator = VKVG_OPERATOR_OVER; - ctx->curFillRule = VKVG_FILL_RULE_NON_ZERO; - ctx->bounds = (VkRect2D) {{0,0},{ctx->pSurf->width,ctx->pSurf->height}}; - ctx->pushConsts = (push_constants) { - {.a = 1}, - {(float)ctx->pSurf->width,(float)ctx->pSurf->height}, - VKVG_PATTERN_TYPE_SOLID, - 1.0f, - VKVG_IDENTITY_MATRIX, - VKVG_IDENTITY_MATRIX - }; - ctx->clearRect = (VkClearRect) {{{0},{ctx->pSurf->width, ctx->pSurf->height}},0,1}; - ctx->renderPassBeginInfo.framebuffer = ctx->pSurf->fb; - ctx->renderPassBeginInfo.renderArea.extent.width = ctx->pSurf->width; - ctx->renderPassBeginInfo.renderArea.extent.height = ctx->pSurf->height; - ctx->renderPassBeginInfo.pClearValues = clearValues; - - LOCK_SURFACE (ctx->pSurf) - - if (ctx->pSurf->newSurf) - ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearAll; - else - ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearStencil; - ctx->pSurf->newSurf = false; - - UNLOCK_SURFACE (ctx->pSurf); - - vkvg_surface_reference (ctx->pSurf); - - if (ctx->dev->samples == VK_SAMPLE_COUNT_1_BIT) - ctx->renderPassBeginInfo.clearValueCount = 2; - else - ctx->renderPassBeginInfo.clearValueCount = 3; - - ctx->selectedCharSize = 10 << 6; - ctx->currentFont = NULL; - ctx->selectedFontName[0]= 0; - ctx->pattern = NULL; - ctx->curColor = 0xff000000;//opaque black - ctx->cmdStarted = false; - ctx->curClipState = vkvg_clip_state_none; - ctx->vertCount = ctx->indCount = 0; + {.color.float32 = {0, 0, 0, 0}}, {.depthStencil = {1.0f, 0}}, {.color.float32 = {0, 0, 0, 0}}}; + +void _init_ctx(VkvgContext ctx) { + ctx->lineWidth = 1; + ctx->miterLimit = 10; + ctx->curOperator = VKVG_OPERATOR_OVER; + ctx->curFillRule = VKVG_FILL_RULE_NON_ZERO; + ctx->bounds = (VkRect2D){{0, 0}, {ctx->pSurf->width, ctx->pSurf->height}}; + ctx->pushConsts = (push_constants){{.a = 1}, + {(float)ctx->pSurf->width, (float)ctx->pSurf->height}, + VKVG_PATTERN_TYPE_SOLID, + 1.0f, + VKVG_IDENTITY_MATRIX, + VKVG_IDENTITY_MATRIX}; + ctx->clearRect = (VkClearRect){{{0}, {ctx->pSurf->width, ctx->pSurf->height}}, 0, 1}; + ctx->renderPassBeginInfo.framebuffer = ctx->pSurf->fb; + ctx->renderPassBeginInfo.renderArea.extent.width = ctx->pSurf->width; + ctx->renderPassBeginInfo.renderArea.extent.height = ctx->pSurf->height; + ctx->renderPassBeginInfo.pClearValues = clearValues; + + LOCK_SURFACE(ctx->pSurf) + + if (ctx->pSurf->newSurf) + ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearAll; + else + ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearStencil; + ctx->pSurf->newSurf = false; + + UNLOCK_SURFACE(ctx->pSurf); + + vkvg_surface_reference(ctx->pSurf); + + if (ctx->dev->samples == VK_SAMPLE_COUNT_1_BIT) + ctx->renderPassBeginInfo.clearValueCount = 2; + else + ctx->renderPassBeginInfo.clearValueCount = 3; + + ctx->selectedCharSize = 10 << 6; + ctx->currentFont = NULL; + ctx->selectedFontName[0] = 0; + ctx->pattern = NULL; + ctx->curColor = 0xff000000; // opaque black + ctx->cmdStarted = false; + ctx->curClipState = vkvg_clip_state_none; + ctx->vertCount = ctx->indCount = 0; #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - ctx->timelineStep = 0; + ctx->timelineStep = 0; #endif } -VkvgContext vkvg_create(VkvgSurface surf) -{ - VkvgDevice dev = surf->dev; - VkvgContext ctx = NULL; +VkvgContext vkvg_create(VkvgSurface surf) { + VkvgDevice dev = surf->dev; + VkvgContext ctx = NULL; - if (_device_try_get_cached_context (dev, &ctx) ) { - ctx->pSurf = surf; + if (_device_try_get_cached_context(dev, &ctx)) { + ctx->pSurf = surf; - if (!surf || surf->status) { - ctx->status = VKVG_STATUS_INVALID_SURFACE; - return ctx; - } + if (!surf || surf->status) { + ctx->status = VKVG_STATUS_INVALID_SURFACE; + return ctx; + } - _init_ctx (ctx); - _update_descriptor_set (ctx, surf->dev->emptyImg, ctx->dsSrc); - _clear_path (ctx); - ctx->cmd = ctx->cmdBuffers[0];//current recording buffer - ctx->status = VKVG_STATUS_SUCCESS; - return ctx; - } - ctx = (vkvg_context*)calloc(1, sizeof(vkvg_context)); + _init_ctx(ctx); + _update_descriptor_set(ctx, surf->dev->emptyImg, ctx->dsSrc); + _clear_path(ctx); + ctx->cmd = ctx->cmdBuffers[0]; // current recording buffer + ctx->status = VKVG_STATUS_SUCCESS; + return ctx; + } + ctx = (vkvg_context *)calloc(1, sizeof(vkvg_context)); - LOG(VKVG_LOG_INFO, "CREATE Context: ctx = %p; surf = %p\n", ctx, surf); + LOG(VKVG_LOG_INFO, "CREATE Context: ctx = %p; surf = %p\n", ctx, surf); - if (!ctx) - return (VkvgContext)&_no_mem_status; + if (!ctx) + return (VkvgContext)&_no_mem_status; - ctx->pSurf = surf; + ctx->pSurf = surf; - if (!surf || surf->status) { - ctx->status = VKVG_STATUS_INVALID_SURFACE; - return ctx; - } + if (!surf || surf->status) { + ctx->status = VKVG_STATUS_INVALID_SURFACE; + return ctx; + } - ctx->sizePoints = VKVG_PTS_SIZE; - ctx->sizeVertices = ctx->sizeVBO = VKVG_VBO_SIZE; - ctx->sizeIndices = ctx->sizeIBO = VKVG_IBO_SIZE; - ctx->sizePathes = VKVG_PATHES_SIZE; - ctx->renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + ctx->sizePoints = VKVG_PTS_SIZE; + ctx->sizeVertices = ctx->sizeVBO = VKVG_VBO_SIZE; + ctx->sizeIndices = ctx->sizeIBO = VKVG_IBO_SIZE; + ctx->sizePathes = VKVG_PATHES_SIZE; + ctx->renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - ctx->dev = surf->dev; + ctx->dev = surf->dev; - _init_ctx (ctx); + _init_ctx(ctx); - ctx->points = (vec2*)malloc (VKVG_VBO_SIZE * sizeof(vec2)); - ctx->pathes = (uint32_t*)malloc (VKVG_PATHES_SIZE * sizeof(uint32_t)); - ctx->vertexCache = (Vertex*)malloc (ctx->sizeVertices * sizeof(Vertex)); - ctx->indexCache = (VKVG_IBO_INDEX_TYPE*)malloc (ctx->sizeIndices * sizeof(VKVG_IBO_INDEX_TYPE)); + ctx->points = (vec2 *)malloc(VKVG_VBO_SIZE * sizeof(vec2)); + ctx->pathes = (uint32_t *)malloc(VKVG_PATHES_SIZE * sizeof(uint32_t)); + ctx->vertexCache = (Vertex *)malloc(ctx->sizeVertices * sizeof(Vertex)); + ctx->indexCache = (VKVG_IBO_INDEX_TYPE *)malloc(ctx->sizeIndices * sizeof(VKVG_IBO_INDEX_TYPE)); - if (!ctx->points || !ctx->pathes || !ctx->vertexCache || !ctx->indexCache) { - dev->status = VKVG_STATUS_NO_MEMORY; - if (ctx->points) - free(ctx->points); - if (ctx->pathes) - free(ctx->pathes); - if (ctx->vertexCache) - free(ctx->vertexCache); - if (ctx->indexCache) - free(ctx->indexCache); - return NULL; - } + if (!ctx->points || !ctx->pathes || !ctx->vertexCache || !ctx->indexCache) { + dev->status = VKVG_STATUS_NO_MEMORY; + if (ctx->points) + free(ctx->points); + if (ctx->pathes) + free(ctx->pathes); + if (ctx->vertexCache) + free(ctx->vertexCache); + if (ctx->indexCache) + free(ctx->indexCache); + return NULL; + } - //for context to be thread safe, command pool and descriptor pool have to be created in the thread of the context. - ctx->cmdPool = vkh_cmd_pool_create ((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + // for context to be thread safe, command pool and descriptor pool have to be created in the thread of the context. + ctx->cmdPool = + vkh_cmd_pool_create((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); #ifndef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - ctx->flushFence = vkh_fence_create_signaled ((VkhDevice)ctx->dev); + ctx->flushFence = vkh_fence_create_signaled((VkhDevice)ctx->dev); #endif - _create_vertices_buff (ctx); - _create_gradient_buff (ctx); - _create_cmd_buff (ctx); - _createDescriptorPool (ctx); - _init_descriptor_sets (ctx); - _font_cache_update_context_descset (ctx); - _update_descriptor_set (ctx, surf->dev->emptyImg, ctx->dsSrc); - _update_gradient_desc_set(ctx); + _create_vertices_buff(ctx); + _create_gradient_buff(ctx); + _create_cmd_buff(ctx); + _createDescriptorPool(ctx); + _init_descriptor_sets(ctx); + _font_cache_update_context_descset(ctx); + _update_descriptor_set(ctx, surf->dev->emptyImg, ctx->dsSrc); + _update_gradient_desc_set(ctx); - _clear_path (ctx); + _clear_path(ctx); - ctx->cmd = ctx->cmdBuffers[0];//current recording buffer + ctx->cmd = ctx->cmdBuffers[0]; // current recording buffer - ctx->references = 1; - ctx->status = VKVG_STATUS_SUCCESS; + ctx->references = 1; + ctx->status = VKVG_STATUS_SUCCESS; - LOG(VKVG_LOG_DBG_ARRAYS, "INIT\tctx = %p; pathes:%ju pts:%ju vch:%d vbo:%d ich:%d ibo:%d\n", ctx, (uint64_t)ctx->sizePathes, (uint64_t)ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, ctx->sizeIBO); + LOG(VKVG_LOG_DBG_ARRAYS, "INIT\tctx = %p; pathes:%ju pts:%ju vch:%d vbo:%d ich:%d ibo:%d\n", ctx, + (uint64_t)ctx->sizePathes, (uint64_t)ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, + ctx->sizeIBO); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)ctx->cmdPool, "CTX Cmd Pool"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)ctx->cmdBuffers[0], "CTX Cmd Buff A"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)ctx->cmdBuffers[1], "CTX Cmd Buff B"); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)ctx->cmdPool, "CTX Cmd Pool"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)ctx->cmdBuffers[0], + "CTX Cmd Buff A"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)ctx->cmdBuffers[1], + "CTX Cmd Buff B"); #ifndef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)ctx->flushFence, "CTX Flush Fence"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)ctx->flushFence, "CTX Flush Fence"); #endif - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t)ctx->descriptorPool, "CTX Descriptor Pool"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsSrc, "CTX DescSet SOURCE"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsFont, "CTX DescSet FONT"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsGrad, "CTX DescSet GRADIENT"); - - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_BUFFER, (uint64_t)ctx->indices.buffer, "CTX Index Buff"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_BUFFER, (uint64_t)ctx->vertices.buffer, "CTX Vertex Buff"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t)ctx->descriptorPool, + "CTX Descriptor Pool"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsSrc, + "CTX DescSet SOURCE"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsFont, + "CTX DescSet FONT"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsGrad, + "CTX DescSet GRADIENT"); + + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_BUFFER, (uint64_t)ctx->indices.buffer, "CTX Index Buff"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_BUFFER, (uint64_t)ctx->vertices.buffer, + "CTX Vertex Buff"); #endif - return ctx; -} -void vkvg_flush (VkvgContext ctx){ - if (ctx->status) - return; - _flush_cmd_buff (ctx); - _wait_ctx_flush_end (ctx); -/* -#ifdef DEBUG - - vec4 red = {0,0,1,1}; - vec4 green = {0,1,0,1}; - vec4 white = {1,1,1,1}; - - int j = 0; - while (j < dlpCount) { - add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],green); - j+=2; - add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],red); - j+=2; - add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],white); - j+=2; - } - dlpCount = 0; - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineLineList); - CmdDrawIndexed(ctx->cmd, ctx->indCount-ctx->curIndStart, 1, ctx->curIndStart, 0, 1); - _flush_cmd_buff(ctx); -#endif -*/ -} - -void _clear_context (VkvgContext ctx) { - //free saved context stack elmt - vkvg_context_save_t* next = ctx->pSavedCtxs; - ctx->pSavedCtxs = NULL; - while (next != NULL) { - vkvg_context_save_t* cur = next; - next = cur->pNext; - _free_ctx_save (cur); - } - //free additional stencil use in save/restore process - if (ctx->savedStencils) { - uint8_t curSaveStencil = ctx->curSavBit / 6; - for (int i=curSaveStencil;i>0;i--) - vkh_image_destroy(ctx->savedStencils[i-1]); - free(ctx->savedStencils); - ctx->savedStencils = NULL; - ctx->curSavBit = 0; - } - - //remove context from double linked list of context in device - /*if (ctx->dev->lastCtx == ctx){ - ctx->dev->lastCtx = ctx->pPrev; - if (ctx->pPrev != NULL) - ctx->pPrev->pNext = NULL; - }else if (ctx->pPrev == NULL){ - //first elmt, and it's not last one so pnext is not null - ctx->pNext->pPrev = NULL; - }else{ - ctx->pPrev->pNext = ctx->pNext; - ctx->pNext->pPrev = ctx->pPrev; - }*/ - if (ctx->dashCount > 0) { - free(ctx->dashes); - ctx->dashCount = 0; - } -} - -void vkvg_destroy (VkvgContext ctx) -{ - if (ctx->status) - return; - - ctx->references--; - if (ctx->references > 0) - return; - - LOG(VKVG_LOG_INFO, "DESTROY Context: ctx = %p (status:%d); surf = %p\n", ctx, ctx->status, ctx->pSurf); - - vkvg_flush (ctx); - - LOG(VKVG_LOG_DBG_ARRAYS, "END\tctx = %p; pathes:%d pts:%d vch:%d vbo:%d ich:%d ibo:%d\n", ctx, ctx->sizePathes, ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, ctx->sizeIBO); + return ctx; +} +void vkvg_flush(VkvgContext ctx) { + if (ctx->status) + return; + _flush_cmd_buff(ctx); + _wait_ctx_flush_end(ctx); + /* + #ifdef DEBUG + + vec4 red = {0,0,1,1}; + vec4 green = {0,1,0,1}; + vec4 white = {1,1,1,1}; + + int j = 0; + while (j < dlpCount) { + add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],green); + j+=2; + add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],red); + j+=2; + add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],white); + j+=2; + } + dlpCount = 0; + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineLineList); + CmdDrawIndexed(ctx->cmd, ctx->indCount-ctx->curIndStart, 1, ctx->curIndStart, 0, 1); + _flush_cmd_buff(ctx); + #endif + */ +} + +void _clear_context(VkvgContext ctx) { + // free saved context stack elmt + vkvg_context_save_t *next = ctx->pSavedCtxs; + ctx->pSavedCtxs = NULL; + while (next != NULL) { + vkvg_context_save_t *cur = next; + next = cur->pNext; + _free_ctx_save(cur); + } + // free additional stencil use in save/restore process + if (ctx->savedStencils) { + uint8_t curSaveStencil = ctx->curSavBit / 6; + for (int i = curSaveStencil; i > 0; i--) + vkh_image_destroy(ctx->savedStencils[i - 1]); + free(ctx->savedStencils); + ctx->savedStencils = NULL; + ctx->curSavBit = 0; + } + + // remove context from double linked list of context in device + /*if (ctx->dev->lastCtx == ctx){ + ctx->dev->lastCtx = ctx->pPrev; + if (ctx->pPrev != NULL) + ctx->pPrev->pNext = NULL; + }else if (ctx->pPrev == NULL){ + //first elmt, and it's not last one so pnext is not null + ctx->pNext->pPrev = NULL; + }else{ + ctx->pPrev->pNext = ctx->pNext; + ctx->pNext->pPrev = ctx->pPrev; + }*/ + if (ctx->dashCount > 0) { + free(ctx->dashes); + ctx->dashCount = 0; + } +} + +void vkvg_destroy(VkvgContext ctx) { + if (ctx->status) + return; + + ctx->references--; + if (ctx->references > 0) + return; + + LOG(VKVG_LOG_INFO, "DESTROY Context: ctx = %p (status:%d); surf = %p\n", ctx, ctx->status, ctx->pSurf); + + vkvg_flush(ctx); + + LOG(VKVG_LOG_DBG_ARRAYS, "END\tctx = %p; pathes:%d pts:%d vch:%d vbo:%d ich:%d ibo:%d\n", ctx, ctx->sizePathes, + ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, ctx->sizeIBO); #if VKVG_RECORDING - if (ctx->recording) - _destroy_recording(ctx->recording); + if (ctx->recording) + _destroy_recording(ctx->recording); #endif - if (ctx->pattern) - vkvg_pattern_destroy (ctx->pattern); + if (ctx->pattern) + vkvg_pattern_destroy(ctx->pattern); - _clear_context (ctx); + _clear_context(ctx); #if VKVG_DBG_STATS - if (ctx->dev->threadAware) - mtx_lock (&ctx->dev->mutex); - - vkvg_debug_stats_t* dbgstats = &ctx->dev->debug_stats; - if (dbgstats->sizePoints < ctx->sizePoints) - dbgstats->sizePoints = ctx->sizePoints; - if (dbgstats->sizePathes < ctx->sizePathes) - dbgstats->sizePathes = ctx->sizePathes; - if (dbgstats->sizeVertices < ctx->sizeVertices) - dbgstats->sizeVertices = ctx->sizeVertices; - if (dbgstats->sizeIndices < ctx->sizeIndices) - dbgstats->sizeIndices = ctx->sizeIndices; - if (dbgstats->sizeVBO < ctx->sizeVBO) - dbgstats->sizeVBO = ctx->sizeVBO; - if (dbgstats->sizeIBO < ctx->sizeIBO) - dbgstats->sizeIBO = ctx->sizeIBO; - - if (ctx->dev->threadAware) - mtx_unlock (&ctx->dev->mutex); + if (ctx->dev->threadAware) + mtx_lock(&ctx->dev->mutex); + + vkvg_debug_stats_t *dbgstats = &ctx->dev->debug_stats; + if (dbgstats->sizePoints < ctx->sizePoints) + dbgstats->sizePoints = ctx->sizePoints; + if (dbgstats->sizePathes < ctx->sizePathes) + dbgstats->sizePathes = ctx->sizePathes; + if (dbgstats->sizeVertices < ctx->sizeVertices) + dbgstats->sizeVertices = ctx->sizeVertices; + if (dbgstats->sizeIndices < ctx->sizeIndices) + dbgstats->sizeIndices = ctx->sizeIndices; + if (dbgstats->sizeVBO < ctx->sizeVBO) + dbgstats->sizeVBO = ctx->sizeVBO; + if (dbgstats->sizeIBO < ctx->sizeIBO) + dbgstats->sizeIBO = ctx->sizeIBO; + + if (ctx->dev->threadAware) + mtx_unlock(&ctx->dev->mutex); #endif - vkvg_surface_destroy(ctx->pSurf); + vkvg_surface_destroy(ctx->pSurf); - if (!ctx->status && ctx->dev->cachedContextCount < VKVG_MAX_CACHED_CONTEXT_COUNT) { - _device_store_context (ctx); - return; - } + if (!ctx->status && ctx->dev->cachedContextCount < VKVG_MAX_CACHED_CONTEXT_COUNT) { + _device_store_context(ctx); + return; + } - _release_context_ressources (ctx); + _release_context_ressources(ctx); } -void vkvg_set_opacity (VkvgContext ctx, float opacity) { - if (ctx->status) - return; +void vkvg_set_opacity(VkvgContext ctx, float opacity) { + if (ctx->status) + return; - if (EQUF(ctx->pushConsts.opacity, opacity)) - return; + if (EQUF(ctx->pushConsts.opacity, opacity)) + return; - _emit_draw_cmd_undrawn_vertices (ctx); - ctx->pushConsts.opacity = opacity; - ctx->pushCstDirty = true; -} -float vkvg_get_opacity (VkvgContext ctx) { - if (ctx->status) - return 0; - return ctx->pushConsts.opacity; + _emit_draw_cmd_undrawn_vertices(ctx); + ctx->pushConsts.opacity = opacity; + ctx->pushCstDirty = true; } -vkvg_status_t vkvg_status (VkvgContext ctx) { - return ctx->status; +float vkvg_get_opacity(VkvgContext ctx) { + if (ctx->status) + return 0; + return ctx->pushConsts.opacity; } -VkvgContext vkvg_reference (VkvgContext ctx) { - if (!ctx->status) - ctx->references++; - return ctx; +vkvg_status_t vkvg_status(VkvgContext ctx) { return ctx->status; } +VkvgContext vkvg_reference(VkvgContext ctx) { + if (!ctx->status) + ctx->references++; + return ctx; } -uint32_t vkvg_get_reference_count (VkvgContext ctx) { - if (ctx->status) - return 0; - return ctx->references; +uint32_t vkvg_get_reference_count(VkvgContext ctx) { + if (ctx->status) + return 0; + return ctx->references; } -void vkvg_new_sub_path (VkvgContext ctx){ - if (ctx->status) - return; +void vkvg_new_sub_path(VkvgContext ctx) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_NEW_SUB_PATH); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: new_sub_path:\n"); + RECORD(ctx, VKVG_CMD_NEW_SUB_PATH); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: new_sub_path:\n"); - _finish_path(ctx); + _finish_path(ctx); } -void vkvg_new_path (VkvgContext ctx){ - if (ctx->status) - return; +void vkvg_new_path(VkvgContext ctx) { + if (ctx->status) + return; - LOG(VKVG_LOG_INFO_CMD, "\tCMD: new_path:\n"); - - _clear_path(ctx); - RECORD(ctx, VKVG_CMD_NEW_PATH); -} -void vkvg_close_path (VkvgContext ctx){ - if (ctx->status) - return; - - RECORD(ctx, VKVG_CMD_CLOSE_PATH); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: close_path:\n"); - - if (ctx->pathes[ctx->pathPtr] & PATH_CLOSED_BIT) //already closed - return; - //check if at least 3 points are present - if (ctx->pathes[ctx->pathPtr] < 3) - return; - - //prevent closing on the same point - if (vec2_equ(ctx->points[ctx->pointCount-1], - ctx->points[ctx->pointCount - ctx->pathes[ctx->pathPtr]])) { - if (ctx->pathes[ctx->pathPtr] < 4)//ensure enough points left for closing - return; - _remove_last_point(ctx); - } - - ctx->pathes[ctx->pathPtr] |= PATH_CLOSED_BIT; - - _finish_path(ctx); -} -void vkvg_rel_line_to (VkvgContext ctx, float dx, float dy){ - if (ctx->status) - return; - - RECORD(ctx, VKVG_CMD_REL_LINE_TO, dx, dy); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_line_to: %f, %f\n", dx, dy); - - if (_current_path_is_empty(ctx)) - _add_point(ctx, 0, 0); - vec2 cp = _get_current_position(ctx); - _line_to(ctx, cp.x + dx, cp.y + dy); -} -void vkvg_line_to (VkvgContext ctx, float x, float y) -{ - if (ctx->status) - return; - - RECORD(ctx, VKVG_CMD_LINE_TO, x, y); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: line_to: %f, %f\n", x, y); - _line_to(ctx, x, y); -} -void vkvg_arc (VkvgContext ctx, float xc, float yc, float radius, float a1, float a2){ - if (ctx->status) - return; - - RECORD(ctx, VKVG_CMD_ARC, xc, yc, radius, a1, a2); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: arc: %f,%f %f %f %f\n", xc, yc, radius, a1, a2); - - while (a2 < a1)//positive arc must have a1 2.f * M_PIF) //limit arc to 2PI - a2 = a1 + 2.f * M_PIF; - - vec2 v = {cosf(a1)*radius + xc, sinf(a1)*radius + yc}; - - float step = _get_arc_step(ctx, radius); - float a = a1; - - if (_current_path_is_empty(ctx)){ - _set_curve_start (ctx); - _add_point (ctx, v.x, v.y); - if (!ctx->pathPtr) - ctx->simpleConvex = true; - else - ctx->simpleConvex = false; - }else{ - _line_to(ctx, v.x, v.y); - _set_curve_start (ctx); - ctx->simpleConvex = false; - } - - a+=step; - - if (EQUF(a2, a1)) - return; - - while(a < a2){ - v.x = cosf(a)*radius + xc; - v.y = sinf(a)*radius + yc; - _add_point (ctx, v.x, v.y); - a+=step; - } - - if (EQUF(a2-a1,M_PIF*2.f)){//if arc is complete circle, last point is the same as the first one - _set_curve_end(ctx); - vkvg_close_path(ctx); - return; - } - a = a2; - //vec2 lastP = v; - v.x = cosf(a)*radius + xc; - v.y = sinf(a)*radius + yc; - //if (!vec2_equ (v,lastP))//this test should not be required - _add_point (ctx, v.x, v.y); - _set_curve_end(ctx); -} -void vkvg_arc_negative (VkvgContext ctx, float xc, float yc, float radius, float a1, float a2) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_ARC_NEG, xc, yc, radius, a1, a2); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: %f,%f %f %f %f\n", xc, yc, radius, a1, a2); - while (a2 > a1) - a2 -= 2.f*M_PIF; - if (a1 - a2 > a1 + 2.f * M_PIF) //limit arc to 2PI - a2 = a1 - 2.f * M_PIF; - - vec2 v = {cosf(a1)*radius + xc, sinf(a1)*radius + yc}; - - float step = _get_arc_step(ctx, radius); - float a = a1; - - if (_current_path_is_empty(ctx)){ - _set_curve_start (ctx); - _add_point (ctx, v.x, v.y); - if (!ctx->pathPtr) - ctx->simpleConvex = true; - else - ctx->simpleConvex = false; - }else{ - _line_to(ctx, v.x, v.y); - _set_curve_start (ctx); - ctx->simpleConvex = false; - } - - a-=step; - - if (EQUF(a2, a1)) - return; - - while(a > a2){ - v.x = cosf(a)*radius + xc; - v.y = sinf(a)*radius + yc; - _add_point (ctx,v.x,v.y); - a-=step; - } - - if (EQUF(a1-a2,M_PIF*2.f)){//if arc is complete circle, last point is the same as the first one - _set_curve_end(ctx); - vkvg_close_path(ctx); - return; - } - - a = a2; - //vec2 lastP = v; - v.x = cosf(a)*radius + xc; - v.y = sinf(a)*radius + yc; - //if (!vec2_equ (v,lastP)) - _add_point (ctx, v.x, v.y); - _set_curve_end(ctx); -} -void vkvg_rel_move_to (VkvgContext ctx, float x, float y) -{ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_REL_MOVE_TO, x, y); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_mote_to: %f, %f\n", x, y); - if (_current_path_is_empty(ctx)) - _add_point(ctx, 0, 0); - vec2 cp = _get_current_position(ctx); - _finish_path(ctx); - _add_point (ctx, cp.x + x, cp.y + y); -} -void vkvg_move_to (VkvgContext ctx, float x, float y) -{ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_MOVE_TO, x, y); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: move_to: %f,%f\n", x, y); - _finish_path(ctx); - _add_point (ctx, x, y); -} -bool vkvg_has_current_point (VkvgContext ctx) { - if (ctx->status) - return false; - return !_current_path_is_empty(ctx); -} -void vkvg_get_current_point (VkvgContext ctx, float* x, float* y) { - if (ctx->status || _current_path_is_empty(ctx)) { - *x = *y = 0; - return; - } - vec2 cp = _get_current_position(ctx); - *x = cp.x; - *y = cp.y; -} -void _curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { - //prevent running _recursive_bezier when all 4 curve points are equal - if (EQUF(x1,x2) && EQUF(x2,x3) && EQUF(y1,y2) && EQUF(y2,y3)) { - if (_current_path_is_empty(ctx) || (EQUF(_get_current_position(ctx).x,x1) && EQUF(_get_current_position(ctx).y,y1))) - return; - } - ctx->simpleConvex = false; - _set_curve_start (ctx); - if (_current_path_is_empty(ctx)) - _add_point(ctx, x1, y1); - - vec2 cp = _get_current_position(ctx); - - //compute dyn distanceTolerance depending on current scale - float sx = 1, sy = 1; - vkvg_matrix_get_scale (&ctx->pushConsts.mat, &sx, &sy); - float distanceTolerance = fabs(0.25f / fmaxf(sx,sy)); - - _recursive_bezier (ctx, distanceTolerance, cp.x, cp.y, x1, y1, x2, y2, x3, y3, 0); - /*cp.x = x3; - cp.y = y3; - if (!vec2_equ(ctx->points[ctx->pointCount-1],cp))*/ - _add_point(ctx,x3,y3); - _set_curve_end (ctx); -} -const double quadraticFact = 2.0/3.0; -void _quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2) { - float x0, y0; - if (_current_path_is_empty(ctx)) { - x0 = x1; - y0 = y1; - } else - vkvg_get_current_point (ctx, &x0, &y0); - _curve_to (ctx, - x0 + (x1 - x0) * quadraticFact, - y0 + (y1 - y0) * quadraticFact, - x2 + (x1 - x2) * quadraticFact, - y2 + (y1 - y2) * quadraticFact, - x2, y2); -} -void vkvg_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_QUADRATIC_TO, x1, y1, x2, y2); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: quadratic_to: %f, %f, %f, %f\n", x1, y1, x2, y2); - _quadratic_to(ctx, x1, y1, x2, y2); -} -void vkvg_rel_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_REL_QUADRATIC_TO, x1, y1, x2, y2); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_quadratic_to: %f, %f, %f, %f\n", x1, y1, x2, y2); - vec2 cp = _get_current_position(ctx); - _quadratic_to (ctx, cp.x + x1, cp.y + y1, cp.x + x2, cp.y + y2); -} -void vkvg_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_CURVE_TO, x1, y1, x2, y2, x3, y3); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: curve_to %f,%f %f,%f %f,%f:\n", x1, y1, x2, y2, x3, y3); - _curve_to (ctx, x1, y1, x2, y2, x3, y3); -} -void vkvg_rel_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { - if (ctx->status) - return; - if (_current_path_is_empty(ctx)) { - ctx->status = VKVG_STATUS_NO_CURRENT_POINT; - return; - } - RECORD(ctx, (uint32_t)VKVG_CMD_REL_CURVE_TO, x1, y1, x2, y2, x3, y3); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel curve_to %f,%f %f,%f %f,%f:\n", x1, y1, x2, y2, x3, y3); - vec2 cp = _get_current_position(ctx); - _curve_to (ctx, cp.x + x1, cp.y + y1, cp.x + x2, cp.y + y2, cp.x + x3, cp.y + y3); -} -void vkvg_fill_rectangle (VkvgContext ctx, float x, float y, float w, float h){ - if (ctx->status) - return; - LOG(VKVG_LOG_INFO_CMD, "\tCMD: fill_rectangle:\n"); - _vao_add_rectangle (ctx,x,y,w,h); - //_record_draw_cmd(ctx); -} - -vkvg_status_t vkvg_rectangle (VkvgContext ctx, float x, float y, float w, float h){ - if (ctx->status) - return ctx->status; - RECORD2(ctx, VKVG_CMD_RECTANGLE, x, y, w, h); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rectangle: %f,%f,%f,%f\n", x, y, w, h); - _finish_path (ctx); - - if (w <= 0 || h <= 0) - return VKVG_STATUS_INVALID_RECT; - - _add_point (ctx, x, y); - _add_point (ctx, x + w, y); - _add_point (ctx, x + w, y + h); - _add_point (ctx, x, y + h); - - ctx->pathes[ctx->pathPtr] |= (PATH_CLOSED_BIT|PATH_IS_CONVEX_BIT); - - _finish_path(ctx); - return VKVG_STATUS_SUCCESS; -} -vkvg_status_t vkvg_rounded_rectangle (VkvgContext ctx, float x, float y, float w, float h, float radius){ - if (ctx->status) - return ctx->status; - LOG(VKVG_LOG_INFO_CMD, "CMD: rounded_rectangle:\n"); - _finish_path (ctx); - - if (w <= 0 || h <= 0) - return VKVG_STATUS_INVALID_RECT; - - if ((radius > w / 2.0f) || (radius > h / 2.0f)) - radius = fmin (w / 2.0f, h / 2.0f); - - vkvg_move_to(ctx, x, y + radius); - vkvg_arc(ctx, x + radius, y + radius, radius, M_PIF, -M_PIF_2); - vkvg_line_to(ctx, x + w - radius, y); - vkvg_arc(ctx, x + w - radius, y + radius, radius, -M_PIF_2, 0); - vkvg_line_to(ctx, x + w, y + h - radius); - vkvg_arc(ctx, x + w - radius, y + h - radius, radius, 0, M_PIF_2); - vkvg_line_to(ctx, x + radius, y + h); - vkvg_arc(ctx, x + radius, y + h - radius, radius, M_PIF_2, M_PIF); - vkvg_line_to(ctx, x, y + radius); - vkvg_close_path(ctx); - - return VKVG_STATUS_SUCCESS; -} -void vkvg_rounded_rectangle2 (VkvgContext ctx, float x, float y, float w, float h, float rx, float ry){ - if (ctx->status) - return; - LOG(VKVG_LOG_INFO_CMD, "CMD: rounded_rectangle2:\n"); - vkvg_move_to (ctx, x+rx, y); - vkvg_line_to (ctx, x+w-rx, y); - vkvg_elliptic_arc_to(ctx, x+w, y+ry, false, true, rx, ry, 0); - - vkvg_line_to (ctx, x+w, y+h-ry); - vkvg_elliptic_arc_to(ctx, x+w-rx, y+h, false, true, rx, ry, 0); - - vkvg_line_to (ctx, x+rx, y+h); - vkvg_elliptic_arc_to(ctx, x, y+h-ry , false, true, rx, ry, 0); - - vkvg_line_to (ctx, x, y+ry); - vkvg_elliptic_arc_to(ctx, x+rx, y , false, true, rx, ry, 0); - - vkvg_close_path(ctx); -} -void vkvg_path_extents (VkvgContext ctx, float *x1, float *y1, float *x2, float *y2) { - if (ctx->status) - return; - - _finish_path(ctx); - - if (!ctx->pathPtr) {//no path - *x1 = *x2 = *y1 = *y2 = 0; - return; - } - - _vkvg_path_extents(ctx, false, x1, y1, x2, y2); -} - -vkvg_clip_state_t _get_previous_clip_state (VkvgContext ctx) { - if (!ctx->pSavedCtxs)//no clip saved => clear - return vkvg_clip_state_clear; - return ctx->pSavedCtxs->clippingState; -} -static const VkClearAttachment clearStencil = {VK_IMAGE_ASPECT_STENCIL_BIT, 1, {{{0}}}}; -static const VkClearAttachment clearColorAttach = {VK_IMAGE_ASPECT_COLOR_BIT, 0, {{{0}}}}; + LOG(VKVG_LOG_INFO_CMD, "\tCMD: new_path:\n"); + + _clear_path(ctx); + RECORD(ctx, VKVG_CMD_NEW_PATH); +} +void vkvg_close_path(VkvgContext ctx) { + if (ctx->status) + return; + + RECORD(ctx, VKVG_CMD_CLOSE_PATH); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: close_path:\n"); + + if (ctx->pathes[ctx->pathPtr] & PATH_CLOSED_BIT) // already closed + return; + // check if at least 3 points are present + if (ctx->pathes[ctx->pathPtr] < 3) + return; + + // prevent closing on the same point + if (vec2_equ(ctx->points[ctx->pointCount - 1], ctx->points[ctx->pointCount - ctx->pathes[ctx->pathPtr]])) { + if (ctx->pathes[ctx->pathPtr] < 4) // ensure enough points left for closing + return; + _remove_last_point(ctx); + } + + ctx->pathes[ctx->pathPtr] |= PATH_CLOSED_BIT; + + _finish_path(ctx); +} +void vkvg_rel_line_to(VkvgContext ctx, float dx, float dy) { + if (ctx->status) + return; + + RECORD(ctx, VKVG_CMD_REL_LINE_TO, dx, dy); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_line_to: %f, %f\n", dx, dy); + + if (_current_path_is_empty(ctx)) + _add_point(ctx, 0, 0); + vec2 cp = _get_current_position(ctx); + _line_to(ctx, cp.x + dx, cp.y + dy); +} +void vkvg_line_to(VkvgContext ctx, float x, float y) { + if (ctx->status) + return; + + RECORD(ctx, VKVG_CMD_LINE_TO, x, y); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: line_to: %f, %f\n", x, y); + _line_to(ctx, x, y); +} +void vkvg_arc(VkvgContext ctx, float xc, float yc, float radius, float a1, float a2) { + if (ctx->status) + return; + + RECORD(ctx, VKVG_CMD_ARC, xc, yc, radius, a1, a2); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: arc: %f,%f %f %f %f\n", xc, yc, radius, a1, a2); + + while (a2 < a1) // positive arc must have a1 2.f * M_PIF) // limit arc to 2PI + a2 = a1 + 2.f * M_PIF; + + vec2 v = {cosf(a1) * radius + xc, sinf(a1) * radius + yc}; + + float step = _get_arc_step(ctx, radius); + float a = a1; + + if (_current_path_is_empty(ctx)) { + _set_curve_start(ctx); + _add_point(ctx, v.x, v.y); + if (!ctx->pathPtr) + ctx->simpleConvex = true; + else + ctx->simpleConvex = false; + } else { + _line_to(ctx, v.x, v.y); + _set_curve_start(ctx); + ctx->simpleConvex = false; + } + + a += step; + + if (EQUF(a2, a1)) + return; + + while (a < a2) { + v.x = cosf(a) * radius + xc; + v.y = sinf(a) * radius + yc; + _add_point(ctx, v.x, v.y); + a += step; + } + + if (EQUF(a2 - a1, M_PIF * 2.f)) { // if arc is complete circle, last point is the same as the first one + _set_curve_end(ctx); + vkvg_close_path(ctx); + return; + } + a = a2; + // vec2 lastP = v; + v.x = cosf(a) * radius + xc; + v.y = sinf(a) * radius + yc; + // if (!vec2_equ (v,lastP))//this test should not be required + _add_point(ctx, v.x, v.y); + _set_curve_end(ctx); +} +void vkvg_arc_negative(VkvgContext ctx, float xc, float yc, float radius, float a1, float a2) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_ARC_NEG, xc, yc, radius, a1, a2); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: %f,%f %f %f %f\n", xc, yc, radius, a1, a2); + while (a2 > a1) + a2 -= 2.f * M_PIF; + if (a1 - a2 > a1 + 2.f * M_PIF) // limit arc to 2PI + a2 = a1 - 2.f * M_PIF; + + vec2 v = {cosf(a1) * radius + xc, sinf(a1) * radius + yc}; + + float step = _get_arc_step(ctx, radius); + float a = a1; + + if (_current_path_is_empty(ctx)) { + _set_curve_start(ctx); + _add_point(ctx, v.x, v.y); + if (!ctx->pathPtr) + ctx->simpleConvex = true; + else + ctx->simpleConvex = false; + } else { + _line_to(ctx, v.x, v.y); + _set_curve_start(ctx); + ctx->simpleConvex = false; + } + + a -= step; + + if (EQUF(a2, a1)) + return; + + while (a > a2) { + v.x = cosf(a) * radius + xc; + v.y = sinf(a) * radius + yc; + _add_point(ctx, v.x, v.y); + a -= step; + } + + if (EQUF(a1 - a2, M_PIF * 2.f)) { // if arc is complete circle, last point is the same as the first one + _set_curve_end(ctx); + vkvg_close_path(ctx); + return; + } + + a = a2; + // vec2 lastP = v; + v.x = cosf(a) * radius + xc; + v.y = sinf(a) * radius + yc; + // if (!vec2_equ (v,lastP)) + _add_point(ctx, v.x, v.y); + _set_curve_end(ctx); +} +void vkvg_rel_move_to(VkvgContext ctx, float x, float y) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_REL_MOVE_TO, x, y); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_mote_to: %f, %f\n", x, y); + if (_current_path_is_empty(ctx)) + _add_point(ctx, 0, 0); + vec2 cp = _get_current_position(ctx); + _finish_path(ctx); + _add_point(ctx, cp.x + x, cp.y + y); +} +void vkvg_move_to(VkvgContext ctx, float x, float y) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_MOVE_TO, x, y); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: move_to: %f,%f\n", x, y); + _finish_path(ctx); + _add_point(ctx, x, y); +} +bool vkvg_has_current_point(VkvgContext ctx) { + if (ctx->status) + return false; + return !_current_path_is_empty(ctx); +} +void vkvg_get_current_point(VkvgContext ctx, float *x, float *y) { + if (ctx->status || _current_path_is_empty(ctx)) { + *x = *y = 0; + return; + } + vec2 cp = _get_current_position(ctx); + *x = cp.x; + *y = cp.y; +} +void _curve_to(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { + // prevent running _recursive_bezier when all 4 curve points are equal + if (EQUF(x1, x2) && EQUF(x2, x3) && EQUF(y1, y2) && EQUF(y2, y3)) { + if (_current_path_is_empty(ctx) || + (EQUF(_get_current_position(ctx).x, x1) && EQUF(_get_current_position(ctx).y, y1))) + return; + } + ctx->simpleConvex = false; + _set_curve_start(ctx); + if (_current_path_is_empty(ctx)) + _add_point(ctx, x1, y1); + + vec2 cp = _get_current_position(ctx); + + // compute dyn distanceTolerance depending on current scale + float sx = 1, sy = 1; + vkvg_matrix_get_scale(&ctx->pushConsts.mat, &sx, &sy); + float distanceTolerance = fabs(0.25f / fmaxf(sx, sy)); + + _recursive_bezier(ctx, distanceTolerance, cp.x, cp.y, x1, y1, x2, y2, x3, y3, 0); + /*cp.x = x3; + cp.y = y3; + if (!vec2_equ(ctx->points[ctx->pointCount-1],cp))*/ + _add_point(ctx, x3, y3); + _set_curve_end(ctx); +} +const double quadraticFact = 2.0 / 3.0; +void _quadratic_to(VkvgContext ctx, float x1, float y1, float x2, float y2) { + float x0, y0; + if (_current_path_is_empty(ctx)) { + x0 = x1; + y0 = y1; + } else + vkvg_get_current_point(ctx, &x0, &y0); + _curve_to(ctx, x0 + (x1 - x0) * quadraticFact, y0 + (y1 - y0) * quadraticFact, x2 + (x1 - x2) * quadraticFact, + y2 + (y1 - y2) * quadraticFact, x2, y2); +} +void vkvg_quadratic_to(VkvgContext ctx, float x1, float y1, float x2, float y2) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_QUADRATIC_TO, x1, y1, x2, y2); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: quadratic_to: %f, %f, %f, %f\n", x1, y1, x2, y2); + _quadratic_to(ctx, x1, y1, x2, y2); +} +void vkvg_rel_quadratic_to(VkvgContext ctx, float x1, float y1, float x2, float y2) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_REL_QUADRATIC_TO, x1, y1, x2, y2); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_quadratic_to: %f, %f, %f, %f\n", x1, y1, x2, y2); + vec2 cp = _get_current_position(ctx); + _quadratic_to(ctx, cp.x + x1, cp.y + y1, cp.x + x2, cp.y + y2); +} +void vkvg_curve_to(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_CURVE_TO, x1, y1, x2, y2, x3, y3); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: curve_to %f,%f %f,%f %f,%f:\n", x1, y1, x2, y2, x3, y3); + _curve_to(ctx, x1, y1, x2, y2, x3, y3); +} +void vkvg_rel_curve_to(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { + if (ctx->status) + return; + if (_current_path_is_empty(ctx)) { + ctx->status = VKVG_STATUS_NO_CURRENT_POINT; + return; + } + RECORD(ctx, (uint32_t)VKVG_CMD_REL_CURVE_TO, x1, y1, x2, y2, x3, y3); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel curve_to %f,%f %f,%f %f,%f:\n", x1, y1, x2, y2, x3, y3); + vec2 cp = _get_current_position(ctx); + _curve_to(ctx, cp.x + x1, cp.y + y1, cp.x + x2, cp.y + y2, cp.x + x3, cp.y + y3); +} +void vkvg_fill_rectangle(VkvgContext ctx, float x, float y, float w, float h) { + if (ctx->status) + return; + LOG(VKVG_LOG_INFO_CMD, "\tCMD: fill_rectangle:\n"); + _vao_add_rectangle(ctx, x, y, w, h); + //_record_draw_cmd(ctx); +} + +vkvg_status_t vkvg_rectangle(VkvgContext ctx, float x, float y, float w, float h) { + if (ctx->status) + return ctx->status; + RECORD2(ctx, VKVG_CMD_RECTANGLE, x, y, w, h); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: rectangle: %f,%f,%f,%f\n", x, y, w, h); + _finish_path(ctx); + + if (w <= 0 || h <= 0) + return VKVG_STATUS_INVALID_RECT; + + _add_point(ctx, x, y); + _add_point(ctx, x + w, y); + _add_point(ctx, x + w, y + h); + _add_point(ctx, x, y + h); + + ctx->pathes[ctx->pathPtr] |= (PATH_CLOSED_BIT | PATH_IS_CONVEX_BIT); + + _finish_path(ctx); + return VKVG_STATUS_SUCCESS; +} +vkvg_status_t vkvg_rounded_rectangle(VkvgContext ctx, float x, float y, float w, float h, float radius) { + if (ctx->status) + return ctx->status; + LOG(VKVG_LOG_INFO_CMD, "CMD: rounded_rectangle:\n"); + _finish_path(ctx); + + if (w <= 0 || h <= 0) + return VKVG_STATUS_INVALID_RECT; + + if ((radius > w / 2.0f) || (radius > h / 2.0f)) + radius = fmin(w / 2.0f, h / 2.0f); + + vkvg_move_to(ctx, x, y + radius); + vkvg_arc(ctx, x + radius, y + radius, radius, M_PIF, -M_PIF_2); + vkvg_line_to(ctx, x + w - radius, y); + vkvg_arc(ctx, x + w - radius, y + radius, radius, -M_PIF_2, 0); + vkvg_line_to(ctx, x + w, y + h - radius); + vkvg_arc(ctx, x + w - radius, y + h - radius, radius, 0, M_PIF_2); + vkvg_line_to(ctx, x + radius, y + h); + vkvg_arc(ctx, x + radius, y + h - radius, radius, M_PIF_2, M_PIF); + vkvg_line_to(ctx, x, y + radius); + vkvg_close_path(ctx); + + return VKVG_STATUS_SUCCESS; +} +void vkvg_rounded_rectangle2(VkvgContext ctx, float x, float y, float w, float h, float rx, float ry) { + if (ctx->status) + return; + LOG(VKVG_LOG_INFO_CMD, "CMD: rounded_rectangle2:\n"); + vkvg_move_to(ctx, x + rx, y); + vkvg_line_to(ctx, x + w - rx, y); + vkvg_elliptic_arc_to(ctx, x + w, y + ry, false, true, rx, ry, 0); + + vkvg_line_to(ctx, x + w, y + h - ry); + vkvg_elliptic_arc_to(ctx, x + w - rx, y + h, false, true, rx, ry, 0); + + vkvg_line_to(ctx, x + rx, y + h); + vkvg_elliptic_arc_to(ctx, x, y + h - ry, false, true, rx, ry, 0); + + vkvg_line_to(ctx, x, y + ry); + vkvg_elliptic_arc_to(ctx, x + rx, y, false, true, rx, ry, 0); + + vkvg_close_path(ctx); +} +void vkvg_path_extents(VkvgContext ctx, float *x1, float *y1, float *x2, float *y2) { + if (ctx->status) + return; + + _finish_path(ctx); + + if (!ctx->pathPtr) { // no path + *x1 = *x2 = *y1 = *y2 = 0; + return; + } + + _vkvg_path_extents(ctx, false, x1, y1, x2, y2); +} + +vkvg_clip_state_t _get_previous_clip_state(VkvgContext ctx) { + if (!ctx->pSavedCtxs) // no clip saved => clear + return vkvg_clip_state_clear; + return ctx->pSavedCtxs->clippingState; +} +static const VkClearAttachment clearStencil = {VK_IMAGE_ASPECT_STENCIL_BIT, 1, {{{0}}}}; +static const VkClearAttachment clearColorAttach = {VK_IMAGE_ASPECT_COLOR_BIT, 0, {{{0}}}}; -void _reset_clip (VkvgContext ctx) { - _emit_draw_cmd_undrawn_vertices(ctx); - if (!ctx->cmdStarted) { - //if command buffer is not already started and in a renderpass, we use the renderpass - //with the loadop clear for stencil - ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearStencil; - //force run of one renderpass (even empty) to perform clear load op - _start_cmd_for_render_pass(ctx); - return; - } - vkCmdClearAttachments(ctx->cmd, 1, &clearStencil, 1, &ctx->clearRect); +void _reset_clip(VkvgContext ctx) { + _emit_draw_cmd_undrawn_vertices(ctx); + if (!ctx->cmdStarted) { + // if command buffer is not already started and in a renderpass, we use the renderpass + // with the loadop clear for stencil + ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearStencil; + // force run of one renderpass (even empty) to perform clear load op + _start_cmd_for_render_pass(ctx); + return; + } + vkCmdClearAttachments(ctx->cmd, 1, &clearStencil, 1, &ctx->clearRect); } -void vkvg_reset_clip (VkvgContext ctx){ - if (ctx->status) - return; +void vkvg_reset_clip(VkvgContext ctx) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_RESET_CLIP); + RECORD(ctx, VKVG_CMD_RESET_CLIP); - if (ctx->curClipState == vkvg_clip_state_clear) - return; - if (_get_previous_clip_state(ctx) == vkvg_clip_state_clear) - ctx->curClipState = vkvg_clip_state_none; - else - ctx->curClipState = vkvg_clip_state_clear; + if (ctx->curClipState == vkvg_clip_state_clear) + return; + if (_get_previous_clip_state(ctx) == vkvg_clip_state_clear) + ctx->curClipState = vkvg_clip_state_none; + else + ctx->curClipState = vkvg_clip_state_clear; - _reset_clip (ctx); + _reset_clip(ctx); } -void vkvg_clear (VkvgContext ctx){ - if (ctx->status) - return; +void vkvg_clear(VkvgContext ctx) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_CLEAR); + RECORD(ctx, VKVG_CMD_CLEAR); - if (_get_previous_clip_state(ctx) == vkvg_clip_state_clear) - ctx->curClipState = vkvg_clip_state_none; - else - ctx->curClipState = vkvg_clip_state_clear; + if (_get_previous_clip_state(ctx) == vkvg_clip_state_clear) + ctx->curClipState = vkvg_clip_state_none; + else + ctx->curClipState = vkvg_clip_state_clear; - _emit_draw_cmd_undrawn_vertices(ctx); - if (!ctx->cmdStarted) { - ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearAll; - _start_cmd_for_render_pass(ctx); - return; - } - VkClearAttachment ca[2] = {clearColorAttach, clearStencil}; - vkCmdClearAttachments(ctx->cmd, 2, ca, 1, &ctx->clearRect); + _emit_draw_cmd_undrawn_vertices(ctx); + if (!ctx->cmdStarted) { + ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearAll; + _start_cmd_for_render_pass(ctx); + return; + } + VkClearAttachment ca[2] = {clearColorAttach, clearStencil}; + vkCmdClearAttachments(ctx->cmd, 2, ca, 1, &ctx->clearRect); } -void _clip_preserve (VkvgContext ctx){ - _finish_path(ctx); +void _clip_preserve(VkvgContext ctx) { + _finish_path(ctx); - if (!ctx->pathPtr)//nothing to clip - return; + if (!ctx->pathPtr) // nothing to clip + return; - _emit_draw_cmd_undrawn_vertices(ctx); + _emit_draw_cmd_undrawn_vertices(ctx); - LOG(VKVG_LOG_INFO, "CLIP: ctx = %p; path cpt = %d;\n", ctx, ctx->pathPtr / 2); + LOG(VKVG_LOG_INFO, "CLIP: ctx = %p; path cpt = %d;\n", ctx, ctx->pathPtr / 2); - _ensure_renderpass_is_started(ctx); + _ensure_renderpass_is_started(ctx); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "clip", DBG_LAB_COLOR_CLIP); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "clip", DBG_LAB_COLOR_CLIP); #endif - if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD){ - _poly_fill (ctx, NULL); - CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); - }else{ - CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); - CmdSetStencilReference (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - CmdSetStencilWriteMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); - _fill_non_zero(ctx); - _emit_draw_cmd_undrawn_vertices(ctx); - } - CmdSetStencilReference (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); - CmdSetStencilWriteMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_ALL_BIT); - - _draw_full_screen_quad (ctx, NULL); - - _bind_draw_pipeline (ctx); - CmdSetStencilCompareMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); + if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD) { + _poly_fill(ctx, NULL); + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); + } else { + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); + CmdSetStencilReference(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); + _fill_non_zero(ctx); + _emit_draw_cmd_undrawn_vertices(ctx); + } + CmdSetStencilReference(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); + CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_ALL_BIT); + + _draw_full_screen_quad(ctx, NULL); + + _bind_draw_pipeline(ctx); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); #endif - ctx->curClipState = vkvg_clip_state_clip; -} -void _fill_preserve (VkvgContext ctx){ - _finish_path(ctx); - - if (!ctx->pathPtr)//nothing to fill - return; - - LOG(VKVG_LOG_INFO, "FILL: ctx = %p; path cpt = %d;\n", ctx, ctx->subpathCount); - - if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD){ - _emit_draw_cmd_undrawn_vertices(ctx); - vec4 bounds = {FLT_MAX,FLT_MAX,FLT_MIN,FLT_MIN}; - _poly_fill (ctx, &bounds); - _bind_draw_pipeline (ctx); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); - _draw_full_screen_quad (ctx, &bounds); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - return; - } - - if (ctx->vertCount - ctx->curVertOffset + ctx->pointCount > VKVG_IBO_MAX) - _emit_draw_cmd_undrawn_vertices(ctx);//limit draw call to addressable vx with choosen index type - - if (ctx->pattern)//if not solid color, source img or gradient has to be bound - _ensure_renderpass_is_started(ctx); - _fill_non_zero(ctx); -} -void _stroke_preserve (VkvgContext ctx) -{ - _finish_path(ctx); - - if (!ctx->pathPtr)//nothing to stroke - return; - - LOG(VKVG_LOG_INFO, "STROKE: ctx = %p; path ptr = %d;\n", ctx, ctx->pathPtr); - - stroke_context_t str = {0}; - str.hw = ctx->lineWidth * 0.5f; - str.lhMax = ctx->miterLimit * ctx->lineWidth; - uint32_t ptrPath = 0; - - while (ptrPath < ctx->pathPtr){ - uint32_t ptrSegment = 0, lastSegmentPointIdx = 0; - uint32_t firstPathPointIdx = str.cp; - uint32_t pathPointCount = ctx->pathes[ptrPath]&PATH_ELT_MASK; - uint32_t lastPathPointIdx = str.cp + pathPointCount - 1; - - dash_context_t dc = {0}; - - if (_path_has_curves (ctx,ptrPath)) { - ptrSegment = 1; - lastSegmentPointIdx = str.cp + (ctx->pathes[ptrPath+ptrSegment]&PATH_ELT_MASK)-1; - } - - str.firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - - //LOG(VKVG_LOG_INFO_PATH, "\tPATH: points count=%10d end point idx=%10d", ctx->pathes[ptrPath]&PATH_ELT_MASK, lastPathPointIdx); - - if (ctx->dashCount > 0) { - //init dash stroke - dc.dashOn = true; - dc.curDash = 0; //current dash index - dc.totDashLength = 0;//limit offset to total length of dashes - for (uint32_t i=0;idashCount;i++) - dc.totDashLength += ctx->dashes[i]; - if (dc.totDashLength == 0){ - ctx->status = VKVG_STATUS_INVALID_DASH; - return; - } - dc.curDashOffset = fmodf(ctx->dashOffset, dc.totDashLength); //cur dash offset between defined path point and last dash segment(on/off) start - str.iL = lastPathPointIdx; - } else if (_path_is_closed(ctx,ptrPath)){ - str.iL = lastPathPointIdx; - }else{ - _draw_stoke_cap(ctx, &str, ctx->points[str.cp], vec2_line_norm(ctx->points[str.cp], ctx->points[str.cp+1]), true); - str.iL = str.cp++; - } - - if (_path_has_curves (ctx,ptrPath)) { - while (str.cp < lastPathPointIdx){ - - bool curved = ctx->pathes [ptrPath + ptrSegment] & PATH_HAS_CURVES_BIT; - if (lastSegmentPointIdx == lastPathPointIdx)//last segment of path, dont draw end point here - lastSegmentPointIdx--; - while (str.cp <= lastSegmentPointIdx) - _draw_segment(ctx, &str, &dc, curved); - - ptrSegment ++; - uint32_t cptSegPts = ctx->pathes [ptrPath + ptrSegment]&PATH_ELT_MASK; - lastSegmentPointIdx = str.cp + cptSegPts - 1; - if (lastSegmentPointIdx == lastPathPointIdx && cptSegPts == 1) { - //single point last segment - ptrSegment++; - break; - } - } - }else while (str.cp < lastPathPointIdx) - _draw_segment(ctx, &str, &dc, false); - - if (ctx->dashCount > 0) { - if (_path_is_closed(ctx,ptrPath)){ - str.iR = firstPathPointIdx; - - _draw_dashed_segment(ctx, &str, &dc, false); - - str.iL++; - str.cp++; - } - if (!dc.dashOn){ - //finishing last dash that is already started, draw end caps but not too close to start - //the default gap is the next void - int32_t prevDash = (int32_t)dc.curDash-1; - if (prevDash < 0) - dc.curDash = ctx->dashCount-1; - float m = fminf (ctx->dashes[prevDash] - dc.curDashOffset, ctx->dashes[dc.curDash]); - vec2 p = vec2_sub(ctx->points[str.iR], vec2_mult_s(dc.normal, m)); - _draw_stoke_cap (ctx, &str, p, dc.normal, false); - } - } else if (_path_is_closed(ctx,ptrPath)){ - str.iR = firstPathPointIdx; - bool inverse = _build_vb_step (ctx, &str, false); - - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache [ctx->indCount-6]; - VKVG_IBO_INDEX_TYPE ii = str.firstIdx; - if (inverse){ - inds[1] = ii+1; - inds[4] = ii+1; - inds[5] = ii; - }else{ - inds[1] = ii; - inds[4] = ii; - inds[5] = ii+1; - } - str.cp++; - }else - _draw_stoke_cap (ctx, &str, ctx->points[str.cp], vec2_line_norm(ctx->points[str.cp-1], ctx->points[str.cp]), false); - - str.cp = firstPathPointIdx + pathPointCount; - - if (ptrSegment > 0) - ptrPath += ptrSegment; - else - ptrPath++; - - //limit batch size here to 1/3 of the ibo index type ability - if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) - _emit_draw_cmd_undrawn_vertices (ctx); - } - -} - -void vkvg_clip (VkvgContext ctx){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_CLIP); - _clip_preserve(ctx); - _clear_path(ctx); -} -void vkvg_stroke (VkvgContext ctx) -{ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_STROKE); - _stroke_preserve(ctx); - _clear_path(ctx); -} -void vkvg_fill (VkvgContext ctx){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_FILL); - _fill_preserve(ctx); - _clear_path(ctx); -} -void vkvg_clip_preserve (VkvgContext ctx) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_CLIP_PRESERVE); - _clip_preserve (ctx); -} -void vkvg_fill_preserve (VkvgContext ctx) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_FILL_PRESERVE); - _fill_preserve (ctx); -} -void vkvg_stroke_preserve (VkvgContext ctx) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_STROKE_PRESERVE); - _stroke_preserve (ctx); -} - -void vkvg_paint (VkvgContext ctx){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_PAINT); - _finish_path (ctx); - - if (ctx->pathPtr) { - vkvg_fill(ctx); - return; - } - - _ensure_renderpass_is_started (ctx); - _draw_full_screen_quad (ctx, NULL); -} -void vkvg_set_source_color (VkvgContext ctx, uint32_t c) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_SOURCE_COLOR, c); - ctx->curColor = c; - _update_cur_pattern (ctx, NULL); -} -void vkvg_set_source_rgb (VkvgContext ctx, float r, float g, float b) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_SOURCE_RGB, r, g, b); - ctx->curColor = CreateRgbaf(r,g,b,1); - _update_cur_pattern (ctx, NULL); -} -void vkvg_set_source_rgba (VkvgContext ctx, float r, float g, float b, float a) -{ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_SOURCE_RGBA, r, g, b, a); - ctx->curColor = CreateRgbaf(r,g,b,a); - _update_cur_pattern (ctx, NULL); -} -void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y){ - if (ctx->status || surf->status) - return; - RECORD(ctx, VKVG_CMD_SET_SOURCE_SURFACE, x, y, surf); - ctx->pushConsts.source.x = x; - ctx->pushConsts.source.y = y; - _update_cur_pattern (ctx, vkvg_pattern_create_for_surface(surf)); - ctx->pushCstDirty = true; -} -void vkvg_set_source (VkvgContext ctx, VkvgPattern pat){ - if (ctx->status || pat->status) - return; - RECORD(ctx, VKVG_CMD_SET_SOURCE, pat); - _update_cur_pattern (ctx, pat); - vkvg_pattern_reference (pat); -} -void vkvg_set_line_width (VkvgContext ctx, float width){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, width); - ctx->lineWidth = width; -} -void vkvg_set_miter_limit (VkvgContext ctx, float limit){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, limit); - ctx->miterLimit = limit; -} -void vkvg_set_line_cap (VkvgContext ctx, vkvg_line_cap_t cap){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_LINE_CAP, cap); - ctx->lineCap = cap; -} -void vkvg_set_line_join (VkvgContext ctx, vkvg_line_join_t join){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_LINE_JOIN, join); - ctx->lineJoin = join; -} -void vkvg_set_operator (VkvgContext ctx, vkvg_operator_t op){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_OPERATOR, op); - if (op == ctx->curOperator) - return; - - _emit_draw_cmd_undrawn_vertices(ctx);//draw call with different ops cant be combined, so emit draw cmd for previous vertices. - - ctx->curOperator = op; - - if (ctx->cmdStarted) - _bind_draw_pipeline (ctx); -} -void vkvg_set_fill_rule (VkvgContext ctx, vkvg_fill_rule_t fr){ - if (ctx->status) - return; + ctx->curClipState = vkvg_clip_state_clip; +} +void _fill_preserve(VkvgContext ctx) { + _finish_path(ctx); + + if (!ctx->pathPtr) // nothing to fill + return; + + LOG(VKVG_LOG_INFO, "FILL: ctx = %p; path cpt = %d;\n", ctx, ctx->subpathCount); + + if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD) { + _emit_draw_cmd_undrawn_vertices(ctx); + vec4 bounds = {FLT_MAX, FLT_MAX, FLT_MIN, FLT_MIN}; + _poly_fill(ctx, &bounds); + _bind_draw_pipeline(ctx); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); + _draw_full_screen_quad(ctx, &bounds); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + return; + } + + if (ctx->vertCount - ctx->curVertOffset + ctx->pointCount > VKVG_IBO_MAX) + _emit_draw_cmd_undrawn_vertices(ctx); // limit draw call to addressable vx with choosen index type + + if (ctx->pattern) // if not solid color, source img or gradient has to be bound + _ensure_renderpass_is_started(ctx); + _fill_non_zero(ctx); +} +void _stroke_preserve(VkvgContext ctx) { + _finish_path(ctx); + + if (!ctx->pathPtr) // nothing to stroke + return; + + LOG(VKVG_LOG_INFO, "STROKE: ctx = %p; path ptr = %d;\n", ctx, ctx->pathPtr); + + stroke_context_t str = {0}; + str.hw = ctx->lineWidth * 0.5f; + str.lhMax = ctx->miterLimit * ctx->lineWidth; + uint32_t ptrPath = 0; + + while (ptrPath < ctx->pathPtr) { + uint32_t ptrSegment = 0, lastSegmentPointIdx = 0; + uint32_t firstPathPointIdx = str.cp; + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + uint32_t lastPathPointIdx = str.cp + pathPointCount - 1; + + dash_context_t dc = {0}; + + if (_path_has_curves(ctx, ptrPath)) { + ptrSegment = 1; + lastSegmentPointIdx = str.cp + (ctx->pathes[ptrPath + ptrSegment] & PATH_ELT_MASK) - 1; + } + + str.firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + + // LOG(VKVG_LOG_INFO_PATH, "\tPATH: points count=%10d end point idx=%10d", ctx->pathes[ptrPath]&PATH_ELT_MASK, + // lastPathPointIdx); + + if (ctx->dashCount > 0) { + // init dash stroke + dc.dashOn = true; + dc.curDash = 0; // current dash index + dc.totDashLength = 0; // limit offset to total length of dashes + for (uint32_t i = 0; i < ctx->dashCount; i++) + dc.totDashLength += ctx->dashes[i]; + if (dc.totDashLength == 0) { + ctx->status = VKVG_STATUS_INVALID_DASH; + return; + } + dc.curDashOffset = fmodf( + ctx->dashOffset, + dc.totDashLength); // cur dash offset between defined path point and last dash segment(on/off) start + str.iL = lastPathPointIdx; + } else if (_path_is_closed(ctx, ptrPath)) { + str.iL = lastPathPointIdx; + } else { + _draw_stoke_cap(ctx, &str, ctx->points[str.cp], + vec2_line_norm(ctx->points[str.cp], ctx->points[str.cp + 1]), true); + str.iL = str.cp++; + } + + if (_path_has_curves(ctx, ptrPath)) { + while (str.cp < lastPathPointIdx) { + + bool curved = ctx->pathes[ptrPath + ptrSegment] & PATH_HAS_CURVES_BIT; + if (lastSegmentPointIdx == lastPathPointIdx) // last segment of path, dont draw end point here + lastSegmentPointIdx--; + while (str.cp <= lastSegmentPointIdx) + _draw_segment(ctx, &str, &dc, curved); + + ptrSegment++; + uint32_t cptSegPts = ctx->pathes[ptrPath + ptrSegment] & PATH_ELT_MASK; + lastSegmentPointIdx = str.cp + cptSegPts - 1; + if (lastSegmentPointIdx == lastPathPointIdx && cptSegPts == 1) { + // single point last segment + ptrSegment++; + break; + } + } + } else + while (str.cp < lastPathPointIdx) + _draw_segment(ctx, &str, &dc, false); + + if (ctx->dashCount > 0) { + if (_path_is_closed(ctx, ptrPath)) { + str.iR = firstPathPointIdx; + + _draw_dashed_segment(ctx, &str, &dc, false); + + str.iL++; + str.cp++; + } + if (!dc.dashOn) { + // finishing last dash that is already started, draw end caps but not too close to start + // the default gap is the next void + int32_t prevDash = (int32_t)dc.curDash - 1; + if (prevDash < 0) + dc.curDash = ctx->dashCount - 1; + float m = fminf(ctx->dashes[prevDash] - dc.curDashOffset, ctx->dashes[dc.curDash]); + vec2 p = vec2_sub(ctx->points[str.iR], vec2_mult_s(dc.normal, m)); + _draw_stoke_cap(ctx, &str, p, dc.normal, false); + } + } else if (_path_is_closed(ctx, ptrPath)) { + str.iR = firstPathPointIdx; + bool inverse = _build_vb_step(ctx, &str, false); + + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount - 6]; + VKVG_IBO_INDEX_TYPE ii = str.firstIdx; + if (inverse) { + inds[1] = ii + 1; + inds[4] = ii + 1; + inds[5] = ii; + } else { + inds[1] = ii; + inds[4] = ii; + inds[5] = ii + 1; + } + str.cp++; + } else + _draw_stoke_cap(ctx, &str, ctx->points[str.cp], + vec2_line_norm(ctx->points[str.cp - 1], ctx->points[str.cp]), false); + + str.cp = firstPathPointIdx + pathPointCount; + + if (ptrSegment > 0) + ptrPath += ptrSegment; + else + ptrPath++; + + // limit batch size here to 1/3 of the ibo index type ability + if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) + _emit_draw_cmd_undrawn_vertices(ctx); + } +} + +void vkvg_clip(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_CLIP); + _clip_preserve(ctx); + _clear_path(ctx); +} +void vkvg_stroke(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_STROKE); + _stroke_preserve(ctx); + _clear_path(ctx); +} +void vkvg_fill(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_FILL); + _fill_preserve(ctx); + _clear_path(ctx); +} +void vkvg_clip_preserve(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_CLIP_PRESERVE); + _clip_preserve(ctx); +} +void vkvg_fill_preserve(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_FILL_PRESERVE); + _fill_preserve(ctx); +} +void vkvg_stroke_preserve(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_STROKE_PRESERVE); + _stroke_preserve(ctx); +} + +void vkvg_paint(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_PAINT); + _finish_path(ctx); + + if (ctx->pathPtr) { + vkvg_fill(ctx); + return; + } + + _ensure_renderpass_is_started(ctx); + _draw_full_screen_quad(ctx, NULL); +} +void vkvg_set_source_color(VkvgContext ctx, uint32_t c) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_SOURCE_COLOR, c); + ctx->curColor = c; + _update_cur_pattern(ctx, NULL); +} +void vkvg_set_source_rgb(VkvgContext ctx, float r, float g, float b) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_SOURCE_RGB, r, g, b); + ctx->curColor = CreateRgbaf(r, g, b, 1); + _update_cur_pattern(ctx, NULL); +} +void vkvg_set_source_rgba(VkvgContext ctx, float r, float g, float b, float a) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_SOURCE_RGBA, r, g, b, a); + ctx->curColor = CreateRgbaf(r, g, b, a); + _update_cur_pattern(ctx, NULL); +} +void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y) { + if (ctx->status || surf->status) + return; + RECORD(ctx, VKVG_CMD_SET_SOURCE_SURFACE, x, y, surf); + ctx->pushConsts.source.x = x; + ctx->pushConsts.source.y = y; + _update_cur_pattern(ctx, vkvg_pattern_create_for_surface(surf)); + ctx->pushCstDirty = true; +} +void vkvg_set_source(VkvgContext ctx, VkvgPattern pat) { + if (ctx->status || pat->status) + return; + RECORD(ctx, VKVG_CMD_SET_SOURCE, pat); + _update_cur_pattern(ctx, pat); + vkvg_pattern_reference(pat); +} +void vkvg_set_line_width(VkvgContext ctx, float width) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, width); + ctx->lineWidth = width; +} +void vkvg_set_miter_limit(VkvgContext ctx, float limit) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, limit); + ctx->miterLimit = limit; +} +void vkvg_set_line_cap(VkvgContext ctx, vkvg_line_cap_t cap) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_LINE_CAP, cap); + ctx->lineCap = cap; +} +void vkvg_set_line_join(VkvgContext ctx, vkvg_line_join_t join) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_LINE_JOIN, join); + ctx->lineJoin = join; +} +void vkvg_set_operator(VkvgContext ctx, vkvg_operator_t op) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_OPERATOR, op); + if (op == ctx->curOperator) + return; + + _emit_draw_cmd_undrawn_vertices( + ctx); // draw call with different ops cant be combined, so emit draw cmd for previous vertices. + + ctx->curOperator = op; + + if (ctx->cmdStarted) + _bind_draw_pipeline(ctx); +} +void vkvg_set_fill_rule(VkvgContext ctx, vkvg_fill_rule_t fr) { + if (ctx->status) + return; #ifndef __APPLE__ - RECORD(ctx, VKVG_CMD_SET_FILL_RULE, fr); - ctx->curFillRule = fr; + RECORD(ctx, VKVG_CMD_SET_FILL_RULE, fr); + ctx->curFillRule = fr; #endif } -vkvg_fill_rule_t vkvg_get_fill_rule (VkvgContext ctx){ - if (ctx->status) - return VKVG_FILL_RULE_NON_ZERO; - return ctx->curFillRule; -} -float vkvg_get_line_width (VkvgContext ctx){ - if (ctx->status) - return 0; - return ctx->lineWidth; -} -void vkvg_set_dash (VkvgContext ctx, const float* dashes, uint32_t num_dashes, float offset){ - if (ctx->status) - return; - if (ctx->dashCount > 0) - free (ctx->dashes); - RECORD(ctx, VKVG_CMD_SET_DASH, num_dashes, offset, dashes); - ctx->dashCount = num_dashes; - ctx->dashOffset = offset; - if (ctx->dashCount == 0) - return; - ctx->dashes = (float*)malloc (sizeof(float) * ctx->dashCount); - memcpy (ctx->dashes, dashes, sizeof(float) * ctx->dashCount); -} -void vkvg_get_dash (VkvgContext ctx, const float* dashes, uint32_t* num_dashes, float* offset){ - if (ctx->status) - return; - *num_dashes = ctx->dashCount; - *offset = ctx->dashOffset; - if (ctx->dashCount == 0 || dashes == NULL) - return; - memcpy ((float*)dashes, ctx->dashes, sizeof(float) * ctx->dashCount); -} - - -vkvg_line_cap_t vkvg_get_line_cap (VkvgContext ctx){ - if (ctx->status) - return (vkvg_line_cap_t)0; - return ctx->lineCap; -} -vkvg_line_join_t vkvg_get_line_join (VkvgContext ctx){ - if (ctx->status) - return (vkvg_line_join_t)0; - return ctx->lineJoin; -} -vkvg_operator_t vkvg_get_operator (VkvgContext ctx){ - if (ctx->status) - return (vkvg_operator_t)0; - return ctx->curOperator; -} -VkvgPattern vkvg_get_source (VkvgContext ctx){ - if (ctx->status) - return NULL; - vkvg_pattern_reference (ctx->pattern); - return ctx->pattern; -} - -void vkvg_select_font_face (VkvgContext ctx, const char* name){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_FONT_FACE, name); - _select_font_face (ctx, name); -} -void vkvg_load_font_from_path (VkvgContext ctx, const char* path, const char* name){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_FONT_PATH, name); - _vkvg_font_identity_t* fid = _font_cache_add_font_identity(ctx, path, name); - if (!_font_cache_load_font_file_in_memory (fid)) { - ctx->status = VKVG_STATUS_FILE_NOT_FOUND; - return; - } - _select_font_face (ctx, name); -} -void vkvg_load_font_from_memory (VkvgContext ctx, unsigned char* fontBuffer, long fontBufferByteSize, const char* name) { - if (ctx->status) - return; - //RECORD(ctx, VKVG_CMD_SET_FONT_PATH, name); - _vkvg_font_identity_t* fid = _font_cache_add_font_identity (ctx, NULL, name); - fid->fontBuffer = fontBuffer; - fid->fontBufSize = fontBufferByteSize; - - _select_font_face (ctx, name); -} -void vkvg_set_font_size (VkvgContext ctx, uint32_t size){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_FONT_SIZE, size); +vkvg_fill_rule_t vkvg_get_fill_rule(VkvgContext ctx) { + if (ctx->status) + return VKVG_FILL_RULE_NON_ZERO; + return ctx->curFillRule; +} +float vkvg_get_line_width(VkvgContext ctx) { + if (ctx->status) + return 0; + return ctx->lineWidth; +} +void vkvg_set_dash(VkvgContext ctx, const float *dashes, uint32_t num_dashes, float offset) { + if (ctx->status) + return; + if (ctx->dashCount > 0) + free(ctx->dashes); + RECORD(ctx, VKVG_CMD_SET_DASH, num_dashes, offset, dashes); + ctx->dashCount = num_dashes; + ctx->dashOffset = offset; + if (ctx->dashCount == 0) + return; + ctx->dashes = (float *)malloc(sizeof(float) * ctx->dashCount); + memcpy(ctx->dashes, dashes, sizeof(float) * ctx->dashCount); +} +void vkvg_get_dash(VkvgContext ctx, const float *dashes, uint32_t *num_dashes, float *offset) { + if (ctx->status) + return; + *num_dashes = ctx->dashCount; + *offset = ctx->dashOffset; + if (ctx->dashCount == 0 || dashes == NULL) + return; + memcpy((float *)dashes, ctx->dashes, sizeof(float) * ctx->dashCount); +} + +vkvg_line_cap_t vkvg_get_line_cap(VkvgContext ctx) { + if (ctx->status) + return (vkvg_line_cap_t)0; + return ctx->lineCap; +} +vkvg_line_join_t vkvg_get_line_join(VkvgContext ctx) { + if (ctx->status) + return (vkvg_line_join_t)0; + return ctx->lineJoin; +} +vkvg_operator_t vkvg_get_operator(VkvgContext ctx) { + if (ctx->status) + return (vkvg_operator_t)0; + return ctx->curOperator; +} +VkvgPattern vkvg_get_source(VkvgContext ctx) { + if (ctx->status) + return NULL; + vkvg_pattern_reference(ctx->pattern); + return ctx->pattern; +} + +void vkvg_select_font_face(VkvgContext ctx, const char *name) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_FONT_FACE, name); + _select_font_face(ctx, name); +} +void vkvg_load_font_from_path(VkvgContext ctx, const char *path, const char *name) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_FONT_PATH, name); + _vkvg_font_identity_t *fid = _font_cache_add_font_identity(ctx, path, name); + if (!_font_cache_load_font_file_in_memory(fid)) { + ctx->status = VKVG_STATUS_FILE_NOT_FOUND; + return; + } + _select_font_face(ctx, name); +} +void vkvg_load_font_from_memory(VkvgContext ctx, unsigned char *fontBuffer, long fontBufferByteSize, const char *name) { + if (ctx->status) + return; + // RECORD(ctx, VKVG_CMD_SET_FONT_PATH, name); + _vkvg_font_identity_t *fid = _font_cache_add_font_identity(ctx, NULL, name); + fid->fontBuffer = fontBuffer; + fid->fontBufSize = fontBufferByteSize; + + _select_font_face(ctx, name); +} +void vkvg_set_font_size(VkvgContext ctx, uint32_t size) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_FONT_SIZE, size); #ifdef VKVG_USE_FREETYPE - long newSize = size << 6; + long newSize = size << 6; #else - long newSize = size; + long newSize = size; #endif - if (ctx->selectedCharSize == newSize) - return; - ctx->selectedCharSize = newSize; - ctx->currentFont = NULL; - ctx->currentFontSize = NULL; -} - -void vkvg_set_text_direction (vkvg_context* ctx, vkvg_direction_t direction){ - -} - -void vkvg_show_text (VkvgContext ctx, const char* text){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SHOW_TEXT, text); - LOG(VKVG_LOG_INFO_CMD, "CMD: show_text:\n"); - //_ensure_renderpass_is_started(ctx); - _font_cache_show_text (ctx, text); - //_flush_undrawn_vertices (ctx); -} - -VkvgText vkvg_text_run_create (VkvgContext ctx, const char* text) { - if (ctx->status) - return NULL; - VkvgText tr = (vkvg_text_run_t*)calloc(1, sizeof(vkvg_text_run_t)); - _font_cache_create_text_run(ctx, text, -1, tr); - return tr; -} -VkvgText vkvg_text_run_create_with_length (VkvgContext ctx, const char* text, uint32_t length) { - if (ctx->status) - return NULL; - VkvgText tr = (vkvg_text_run_t*)calloc(1, sizeof(vkvg_text_run_t)); - _font_cache_create_text_run(ctx, text, length, tr); - return tr; -} -uint32_t vkvg_text_run_get_glyph_count (VkvgText textRun) { - return textRun->glyph_count; -} -void vkvg_text_run_get_glyph_position (VkvgText textRun, - uint32_t index, - vkvg_glyph_info_t* pGlyphInfo) { - if (index >= textRun->glyph_count) { - *pGlyphInfo = (vkvg_glyph_info_t){0}; - return; - } + if (ctx->selectedCharSize == newSize) + return; + ctx->selectedCharSize = newSize; + ctx->currentFont = NULL; + ctx->currentFontSize = NULL; +} + +void vkvg_set_text_direction(vkvg_context *ctx, vkvg_direction_t direction) {} + +void vkvg_show_text(VkvgContext ctx, const char *text) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SHOW_TEXT, text); + LOG(VKVG_LOG_INFO_CMD, "CMD: show_text:\n"); + //_ensure_renderpass_is_started(ctx); + _font_cache_show_text(ctx, text); + //_flush_undrawn_vertices (ctx); +} + +VkvgText vkvg_text_run_create(VkvgContext ctx, const char *text) { + if (ctx->status) + return NULL; + VkvgText tr = (vkvg_text_run_t *)calloc(1, sizeof(vkvg_text_run_t)); + _font_cache_create_text_run(ctx, text, -1, tr); + return tr; +} +VkvgText vkvg_text_run_create_with_length(VkvgContext ctx, const char *text, uint32_t length) { + if (ctx->status) + return NULL; + VkvgText tr = (vkvg_text_run_t *)calloc(1, sizeof(vkvg_text_run_t)); + _font_cache_create_text_run(ctx, text, length, tr); + return tr; +} +uint32_t vkvg_text_run_get_glyph_count(VkvgText textRun) { return textRun->glyph_count; } +void vkvg_text_run_get_glyph_position(VkvgText textRun, uint32_t index, vkvg_glyph_info_t *pGlyphInfo) { + if (index >= textRun->glyph_count) { + *pGlyphInfo = (vkvg_glyph_info_t){0}; + return; + } #if VKVG_USE_HARFBUZZ - memcpy (pGlyphInfo, &textRun->glyphs[index], sizeof(vkvg_glyph_info_t)); + memcpy(pGlyphInfo, &textRun->glyphs[index], sizeof(vkvg_glyph_info_t)); #else - *pGlyphInfo = textRun->glyphs[index]; + *pGlyphInfo = textRun->glyphs[index]; #endif } -void vkvg_text_run_destroy (VkvgText textRun) { - _font_cache_destroy_text_run (textRun); - free (textRun); -} -void vkvg_show_text_run (VkvgContext ctx, VkvgText textRun) { - if (ctx->status) - return; - _font_cache_show_text_run(ctx, textRun); -} -void vkvg_text_run_get_extents (VkvgText textRun, vkvg_text_extents_t* extents) { - *extents = textRun->extents; -} - -void vkvg_text_extents (VkvgContext ctx, const char* text, vkvg_text_extents_t* extents) { - if (ctx->status) - return; - _font_cache_text_extents(ctx, text, -1, extents); -} -void vkvg_font_extents (VkvgContext ctx, vkvg_font_extents_t* extents) { - if (ctx->status) - return; - _font_cache_font_extents(ctx, extents); -} - -void vkvg_save (VkvgContext ctx){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SAVE); - LOG(VKVG_LOG_INFO, "SAVE CONTEXT: ctx = %p\n", ctx); - - VkvgDevice dev = ctx->dev; - vkvg_context_save_t* sav = (vkvg_context_save_t*)calloc(1,sizeof(vkvg_context_save_t)); - - _flush_cmd_buff (ctx); - if (!_wait_ctx_flush_end (ctx)) { - free (sav); - return; - } - - if (ctx->curClipState == vkvg_clip_state_clip) { - sav->clippingState = vkvg_clip_state_clip_saved; - - uint8_t curSaveStencil = ctx->curSavBit / 6; - - if (ctx->curSavBit > 0 && ctx->curSavBit % 6 == 0){//new save/restore stencil image have to be created - VkhImage* savedStencilsPtr = NULL; - if (savedStencilsPtr) - savedStencilsPtr = (VkhImage*)realloc(ctx->savedStencils, curSaveStencil * sizeof(VkhImage)); - else - savedStencilsPtr = (VkhImage*)malloc(curSaveStencil * sizeof(VkhImage)); - if (savedStencilsPtr == NULL) { - free(sav); - ctx->status = VKVG_STATUS_NO_MEMORY; - return; - } - ctx->savedStencils = savedStencilsPtr; - VkhImage savStencil = vkh_image_ms_create ((VkhDevice)dev, dev->stencilFormat, dev->samples, ctx->pSurf->width, ctx->pSurf->height, - VKH_MEMORY_USAGE_GPU_ONLY, VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - ctx->savedStencils[curSaveStencil-1] = savStencil; - - vkh_cmd_begin (ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - ctx->cmdStarted = true; - - #if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "new save/restore stencil", DBG_LAB_COLOR_SAV); - #endif - - vkh_image_set_layout (ctx->cmd, ctx->pSurf->stencil, dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (ctx->cmd, savStencil, dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkImageCopy cregion = { .srcSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, - .dstSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, - .extent = {ctx->pSurf->width,ctx->pSurf->height,1}}; - vkCmdCopyImage(ctx->cmd, - vkh_image_get_vkimage (ctx->pSurf->stencil),VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (savStencil), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &cregion); - - vkh_image_set_layout (ctx->cmd, ctx->pSurf->stencil, dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); - - #if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); - #endif - - VK_CHECK_RESULT(vkEndCommandBuffer(ctx->cmd)); - _wait_and_submit_cmd(ctx); - } - - uint8_t curSaveBit = 1 << (ctx->curSavBit % 6 + 2); - - _start_cmd_for_render_pass (ctx); - - #if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "save rp", DBG_LAB_COLOR_SAV); - #endif - - CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); - - CmdSetStencilReference (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT|curSaveBit); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - CmdSetStencilWriteMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, curSaveBit); - - _draw_full_screen_quad (ctx, NULL); - - _bind_draw_pipeline (ctx); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - - #if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); - #endif - ctx->curSavBit++; - } else if (ctx->curClipState == vkvg_clip_state_none) - sav->clippingState = (_get_previous_clip_state(ctx) & 0x03); - else - sav->clippingState = vkvg_clip_state_clear; - - sav->dashOffset = ctx->dashOffset; - sav->dashCount = ctx->dashCount; - if (ctx->dashCount > 0) { - sav->dashes = (float*)malloc (sizeof(float) * ctx->dashCount); - memcpy (sav->dashes, ctx->dashes, sizeof(float) * ctx->dashCount); - } - sav->lineWidth = ctx->lineWidth; - sav->miterLimit = ctx->miterLimit; - sav->curOperator= ctx->curOperator; - sav->lineCap = ctx->lineCap; - sav->lineWidth = ctx->lineWidth; - sav->curFillRule= ctx->curFillRule; - - sav->selectedCharSize = ctx->selectedCharSize; - strcpy (sav->selectedFontName, ctx->selectedFontName); - - sav->currentFont = ctx->currentFont; - sav->textDirection= ctx->textDirection; - sav->pushConsts = ctx->pushConsts; - if (ctx->pattern) { - sav->pattern = ctx->pattern;//TODO:pattern sav must be imutable (copy?) - vkvg_pattern_reference (ctx->pattern); - } else - sav->curColor = ctx->curColor; - - sav->pNext = ctx->pSavedCtxs; - ctx->pSavedCtxs = sav; - -} -void vkvg_restore (VkvgContext ctx){ - if (ctx->status) - return; - - RECORD(ctx, VKVG_CMD_RESTORE); - - if (ctx->pSavedCtxs == NULL){ - ctx->status = VKVG_STATUS_INVALID_RESTORE; - return; - } - - LOG(VKVG_LOG_INFO, "RESTORE CONTEXT: ctx = %p\n", ctx); - - vkvg_context_save_t* sav = ctx->pSavedCtxs; - ctx->pSavedCtxs = sav->pNext; - - _flush_cmd_buff (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; +void vkvg_text_run_destroy(VkvgText textRun) { + _font_cache_destroy_text_run(textRun); + free(textRun); +} +void vkvg_show_text_run(VkvgContext ctx, VkvgText textRun) { + if (ctx->status) + return; + _font_cache_show_text_run(ctx, textRun); +} +void vkvg_text_run_get_extents(VkvgText textRun, vkvg_text_extents_t *extents) { *extents = textRun->extents; } + +void vkvg_text_extents(VkvgContext ctx, const char *text, vkvg_text_extents_t *extents) { + if (ctx->status) + return; + _font_cache_text_extents(ctx, text, -1, extents); +} +void vkvg_font_extents(VkvgContext ctx, vkvg_font_extents_t *extents) { + if (ctx->status) + return; + _font_cache_font_extents(ctx, extents); +} + +void vkvg_save(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SAVE); + LOG(VKVG_LOG_INFO, "SAVE CONTEXT: ctx = %p\n", ctx); + + VkvgDevice dev = ctx->dev; + vkvg_context_save_t *sav = (vkvg_context_save_t *)calloc(1, sizeof(vkvg_context_save_t)); + + _flush_cmd_buff(ctx); + if (!_wait_ctx_flush_end(ctx)) { + free(sav); + return; + } + + if (ctx->curClipState == vkvg_clip_state_clip) { + sav->clippingState = vkvg_clip_state_clip_saved; + + uint8_t curSaveStencil = ctx->curSavBit / 6; + + if (ctx->curSavBit > 0 && ctx->curSavBit % 6 == 0) { // new save/restore stencil image have to be created + VkhImage *savedStencilsPtr = NULL; + if (savedStencilsPtr) + savedStencilsPtr = (VkhImage *)realloc(ctx->savedStencils, curSaveStencil * sizeof(VkhImage)); + else + savedStencilsPtr = (VkhImage *)malloc(curSaveStencil * sizeof(VkhImage)); + if (savedStencilsPtr == NULL) { + free(sav); + ctx->status = VKVG_STATUS_NO_MEMORY; + return; + } + ctx->savedStencils = savedStencilsPtr; + VkhImage savStencil = vkh_image_ms_create( + (VkhDevice)dev, dev->stencilFormat, dev->samples, ctx->pSurf->width, ctx->pSurf->height, + VKH_MEMORY_USAGE_GPU_ONLY, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + ctx->savedStencils[curSaveStencil - 1] = savStencil; + + vkh_cmd_begin(ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + ctx->cmdStarted = true; + +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "new save/restore stencil", DBG_LAB_COLOR_SAV); +#endif - ctx->pushConsts = sav->pushConsts; - ctx->pushCstDirty = true; + vkh_image_set_layout(ctx->cmd, ctx->pSurf->stencil, dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(ctx->cmd, savStencil, dev->stencilAspectFlag, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkImageCopy cregion = {.srcSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, + .dstSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, + .extent = {ctx->pSurf->width, ctx->pSurf->height, 1}}; + vkCmdCopyImage(ctx->cmd, vkh_image_get_vkimage(ctx->pSurf->stencil), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(savStencil), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); + + vkh_image_set_layout(ctx->cmd, ctx->pSurf->stencil, dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); +#endif - if (ctx->curClipState) {//!=none - if (ctx->curClipState == vkvg_clip_state_clip && sav->clippingState == vkvg_clip_state_clear) { - _reset_clip (ctx); - } else { + VK_CHECK_RESULT(vkEndCommandBuffer(ctx->cmd)); + _wait_and_submit_cmd(ctx); + } - uint8_t curSaveBit = 1 << ((ctx->curSavBit-1) % 6 + 2); + uint8_t curSaveBit = 1 << (ctx->curSavBit % 6 + 2); - _start_cmd_for_render_pass (ctx); + _start_cmd_for_render_pass(ctx); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "restore rp", DBG_LAB_COLOR_SAV); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "save rp", DBG_LAB_COLOR_SAV); #endif - CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); - CmdSetStencilReference (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT|curSaveBit); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, curSaveBit); - CmdSetStencilWriteMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + CmdSetStencilReference(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT | curSaveBit); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, curSaveBit); - _draw_full_screen_quad (ctx, NULL); + _draw_full_screen_quad(ctx, NULL); - _bind_draw_pipeline (ctx); - CmdSetStencilCompareMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + _bind_draw_pipeline(ctx); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); #endif + ctx->curSavBit++; + } else if (ctx->curClipState == vkvg_clip_state_none) + sav->clippingState = (_get_previous_clip_state(ctx) & 0x03); + else + sav->clippingState = vkvg_clip_state_clear; + + sav->dashOffset = ctx->dashOffset; + sav->dashCount = ctx->dashCount; + if (ctx->dashCount > 0) { + sav->dashes = (float *)malloc(sizeof(float) * ctx->dashCount); + memcpy(sav->dashes, ctx->dashes, sizeof(float) * ctx->dashCount); + } + sav->lineWidth = ctx->lineWidth; + sav->miterLimit = ctx->miterLimit; + sav->curOperator = ctx->curOperator; + sav->lineCap = ctx->lineCap; + sav->lineWidth = ctx->lineWidth; + sav->curFillRule = ctx->curFillRule; + + sav->selectedCharSize = ctx->selectedCharSize; + strcpy(sav->selectedFontName, ctx->selectedFontName); + + sav->currentFont = ctx->currentFont; + sav->textDirection = ctx->textDirection; + sav->pushConsts = ctx->pushConsts; + if (ctx->pattern) { + sav->pattern = ctx->pattern; // TODO:pattern sav must be imutable (copy?) + vkvg_pattern_reference(ctx->pattern); + } else + sav->curColor = ctx->curColor; + + sav->pNext = ctx->pSavedCtxs; + ctx->pSavedCtxs = sav; +} +void vkvg_restore(VkvgContext ctx) { + if (ctx->status) + return; + + RECORD(ctx, VKVG_CMD_RESTORE); + + if (ctx->pSavedCtxs == NULL) { + ctx->status = VKVG_STATUS_INVALID_RESTORE; + return; + } + + LOG(VKVG_LOG_INFO, "RESTORE CONTEXT: ctx = %p\n", ctx); + + vkvg_context_save_t *sav = ctx->pSavedCtxs; + ctx->pSavedCtxs = sav->pNext; + + _flush_cmd_buff(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; + + ctx->pushConsts = sav->pushConsts; + ctx->pushCstDirty = true; + + if (ctx->curClipState) { //!=none + if (ctx->curClipState == vkvg_clip_state_clip && sav->clippingState == vkvg_clip_state_clear) { + _reset_clip(ctx); + } else { + + uint8_t curSaveBit = 1 << ((ctx->curSavBit - 1) % 6 + 2); + + _start_cmd_for_render_pass(ctx); + +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "restore rp", DBG_LAB_COLOR_SAV); +#endif + + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); - _flush_cmd_buff (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; - } - } - if (sav->clippingState == vkvg_clip_state_clip_saved) { - ctx->curSavBit--; + CmdSetStencilReference(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT | curSaveBit); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, curSaveBit); + CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - uint8_t curSaveStencil = ctx->curSavBit / 6; - if (ctx->curSavBit > 0 && ctx->curSavBit % 6 == 0){//addtional save/restore stencil image have to be copied back to surf stencil first - VkhImage savStencil = ctx->savedStencils[curSaveStencil-1]; + _draw_full_screen_quad(ctx, NULL); - vkh_cmd_begin (ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - ctx->cmdStarted = true; + _bind_draw_pipeline(ctx); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); +#endif -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "additional stencil copy while restoring", DBG_LAB_COLOR_SAV); + _flush_cmd_buff(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; + } + } + if (sav->clippingState == vkvg_clip_state_clip_saved) { + ctx->curSavBit--; + + uint8_t curSaveStencil = ctx->curSavBit / 6; + if (ctx->curSavBit > 0 && + ctx->curSavBit % 6 == + 0) { // addtional save/restore stencil image have to be copied back to surf stencil first + VkhImage savStencil = ctx->savedStencils[curSaveStencil - 1]; + + vkh_cmd_begin(ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + ctx->cmdStarted = true; + +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "additional stencil copy while restoring", DBG_LAB_COLOR_SAV); #endif - vkh_image_set_layout (ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (ctx->cmd, savStencil, ctx->dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkImageCopy cregion = { .srcSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, - .dstSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, - .extent = {ctx->pSurf->width,ctx->pSurf->height,1}}; - vkCmdCopyImage(ctx->cmd, - vkh_image_get_vkimage (savStencil), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (ctx->pSurf->stencil),VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &cregion); - vkh_image_set_layout (ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); - -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); + vkh_image_set_layout(ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(ctx->cmd, savStencil, ctx->dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkImageCopy cregion = {.srcSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, + .dstSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, + .extent = {ctx->pSurf->width, ctx->pSurf->height, 1}}; + vkCmdCopyImage(ctx->cmd, vkh_image_get_vkimage(savStencil), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(ctx->pSurf->stencil), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, + &cregion); + vkh_image_set_layout(ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); #endif - VK_CHECK_RESULT(vkEndCommandBuffer(ctx->cmd)); - _wait_and_submit_cmd (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; - vkh_image_destroy (savStencil); - } - } - - ctx->curClipState = vkvg_clip_state_none; - - ctx->dashOffset = sav->dashOffset; - if (ctx->dashCount > 0) - free (ctx->dashes); - ctx->dashCount = sav->dashCount; - if (ctx->dashCount > 0) { - ctx->dashes = (float*)malloc (sizeof(float) * ctx->dashCount); - memcpy (ctx->dashes, sav->dashes, sizeof(float) * ctx->dashCount); - } - - ctx->lineWidth = sav->lineWidth; - ctx->miterLimit = sav->miterLimit; - ctx->curOperator= sav->curOperator; - ctx->lineCap = sav->lineCap; - ctx->lineJoin = sav->lineJoint; - ctx->curFillRule= sav->curFillRule; - - ctx->selectedCharSize = sav->selectedCharSize; - strcpy (ctx->selectedFontName, sav->selectedFontName); - - ctx->currentFont = sav->currentFont; - ctx->textDirection= sav->textDirection; - - if (sav->pattern) { - if (sav->pattern != ctx->pattern) - _update_cur_pattern (ctx, sav->pattern); - else - vkvg_pattern_destroy(sav->pattern); - } else { - ctx->curColor = sav->curColor; - _update_cur_pattern (ctx, NULL); - } - - _free_ctx_save(sav); -} - -void vkvg_translate (VkvgContext ctx, float dx, float dy){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_TRANSLATE, dx, dy); - LOG(VKVG_LOG_INFO_CMD, "CMD: translate: %f, %f\n", dx, dy); - _emit_draw_cmd_undrawn_vertices(ctx); - vkvg_matrix_translate (&ctx->pushConsts.mat, dx, dy); - _set_mat_inv_and_vkCmdPush (ctx); -} -void vkvg_scale (VkvgContext ctx, float sx, float sy){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SCALE, sx, sy); - LOG(VKVG_LOG_INFO_CMD, "CMD: scale: %f, %f\n", sx, sy); - _emit_draw_cmd_undrawn_vertices(ctx); - vkvg_matrix_scale (&ctx->pushConsts.mat, sx, sy); - _set_mat_inv_and_vkCmdPush (ctx); -} -void vkvg_rotate (VkvgContext ctx, float radians){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_ROTATE, radians); - LOG(VKVG_LOG_INFO_CMD, "CMD: rotate: %f\n", radians); - _emit_draw_cmd_undrawn_vertices(ctx); - vkvg_matrix_rotate (&ctx->pushConsts.mat, radians); - _set_mat_inv_and_vkCmdPush (ctx); -} -void vkvg_transform (VkvgContext ctx, const vkvg_matrix_t* matrix) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_TRANSFORM, matrix); - LOG(VKVG_LOG_INFO_CMD, "CMD: transform: %f, %f, %f, %f, %f, %f\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, matrix->x0, matrix->y0); - _emit_draw_cmd_undrawn_vertices(ctx); - vkvg_matrix_t res; - vkvg_matrix_multiply (&res, &ctx->pushConsts.mat, matrix); - ctx->pushConsts.mat = res; - _set_mat_inv_and_vkCmdPush (ctx); -} -void vkvg_identity_matrix (VkvgContext ctx) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_IDENTITY_MATRIX); - LOG(VKVG_LOG_INFO_CMD, "CMD: identity_matrix:\n"); - _emit_draw_cmd_undrawn_vertices(ctx); - vkvg_matrix_t im = VKVG_IDENTITY_MATRIX; - ctx->pushConsts.mat = im; - _set_mat_inv_and_vkCmdPush (ctx); -} -void vkvg_set_matrix (VkvgContext ctx, const vkvg_matrix_t* matrix){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_MATRIX, matrix); - LOG(VKVG_LOG_INFO_CMD, "CMD: set_matrix: %f, %f, %f, %f, %f, %f\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, matrix->x0, matrix->y0); - _emit_draw_cmd_undrawn_vertices(ctx); - ctx->pushConsts.mat = (*matrix); - _set_mat_inv_and_vkCmdPush (ctx); -} -void vkvg_get_matrix (VkvgContext ctx, vkvg_matrix_t* const matrix){ - *matrix = ctx->pushConsts.mat; -} - -void vkvg_elliptic_arc_to (VkvgContext ctx, float x2, float y2, bool largeArc, bool sweepFlag, float rx, float ry, float phi) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_ELLIPTICAL_ARC_TO, x2, y2, rx, ry, phi, largeArc, sweepFlag); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: elliptic_arc_to: x2:%10.5f y2:%10.5f large:%d sweep:%d rx:%10.5f ry:%10.5f phi:%10.5f \n", x2,y2,largeArc,sweepFlag,rx,ry,phi); - float x1, y1; - vkvg_get_current_point(ctx, &x1, &y1); - _elliptic_arc(ctx, x1, y1, x2, y2, largeArc, sweepFlag, rx, ry, phi); -} -void vkvg_rel_elliptic_arc_to (VkvgContext ctx, float x2, float y2, bool largeArc, bool sweepFlag, float rx, float ry, float phi) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_REL_ELLIPTICAL_ARC_TO, x2, y2, rx, ry, phi, largeArc, sweepFlag); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_elliptic_arc_to: x2:%10.5f y2:%10.5f large:%d sweep:%d rx:%10.5f ry:%10.5f phi:%10.5f \n", x2,y2,largeArc,sweepFlag,rx,ry,phi); - - float x1, y1; - vkvg_get_current_point(ctx, &x1, &y1); - _elliptic_arc(ctx, x1, y1, x2+x1, y2+y1, largeArc, sweepFlag, rx, ry, phi); -} - -void vkvg_ellipse (VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle) { - if (ctx->status) - return; - LOG(VKVG_LOG_INFO_CMD, "CMD: ellipse:\n"); - - float width_two_thirds = radiusX * 4 / 3; - - float dx1 = sinf(rotationAngle) * radiusY; - float dy1 = cosf(rotationAngle) * radiusY; - float dx2 = cosf(rotationAngle) * width_two_thirds; - float dy2 = sinf(rotationAngle) * width_two_thirds; - - float topCenterX = x - dx1; - float topCenterY = y + dy1; - float topRightX = topCenterX + dx2; - float topRightY = topCenterY + dy2; - float topLeftX = topCenterX - dx2; - float topLeftY = topCenterY - dy2; - - float bottomCenterX = x + dx1; - float bottomCenterY = y - dy1; - float bottomRightX = bottomCenterX + dx2; - float bottomRightY = bottomCenterY + dy2; - float bottomLeftX = bottomCenterX - dx2; - float bottomLeftY = bottomCenterY - dy2; - - _finish_path(ctx); - _add_point (ctx, bottomCenterX, bottomCenterY); - - _curve_to (ctx, bottomRightX, bottomRightY, topRightX, topRightY, topCenterX, topCenterY); - _curve_to (ctx, topLeftX, topLeftY, bottomLeftX, bottomLeftY, bottomCenterX, bottomCenterY); - - ctx->pathes[ctx->pathPtr] |= PATH_CLOSED_BIT; - _finish_path(ctx); -} - -VkvgSurface vkvg_get_target (VkvgContext ctx) { - if (ctx->status) - return NULL; - return ctx->pSurf; -} - -const char * -vkvg_status_to_string (vkvg_status_t status) { - switch (status) { - case VKVG_STATUS_SUCCESS: - return "no error has occurred"; - case VKVG_STATUS_NO_MEMORY: - return "out of memory"; - case VKVG_STATUS_INVALID_RESTORE: - return "vkvg_restore() without matching vkvg_save()"; - case VKVG_STATUS_NO_CURRENT_POINT: - return "no current point defined"; - case VKVG_STATUS_INVALID_MATRIX: - return "invalid matrix (not invertible)"; - case VKVG_STATUS_INVALID_STATUS: - return "invalid value for an input vkvg_status_t"; - case VKVG_STATUS_INVALID_INDEX: - return "invalid index passed to getter"; - case VKVG_STATUS_NULL_POINTER: - return "NULL pointer"; - case VKVG_STATUS_WRITE_ERROR: - return "error while writing to output stream"; - case VKVG_STATUS_PATTERN_TYPE_MISMATCH: - return "the pattern type is not appropriate for the operation"; - case VKVG_STATUS_PATTERN_INVALID_GRADIENT: - return "the stops count is zero"; - case VKVG_STATUS_INVALID_FORMAT: - return "invalid value for an input vkvg_format_t"; - case VKVG_STATUS_FILE_NOT_FOUND: - return "file not found"; - case VKVG_STATUS_INVALID_DASH: - return "invalid value for a dash setting"; - case VKVG_STATUS_INVALID_RECT: - return "a rectangle has the height or width equal to 0"; - case VKVG_STATUS_TIMEOUT: - return "waiting for a Vulkan operation to finish resulted in a fence timeout (5 seconds)"; - case VKVG_STATUS_DEVICE_ERROR: - return "the initialization of the device resulted in an error"; - case VKVG_STATUS_INVALID_IMAGE: - return "invalid image"; - case VKVG_STATUS_INVALID_SURFACE: - return "invalid surface"; - case VKVG_STATUS_INVALID_FONT: - return "unresolved font name"; - default: - return ""; - } + VK_CHECK_RESULT(vkEndCommandBuffer(ctx->cmd)); + _wait_and_submit_cmd(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; + vkh_image_destroy(savStencil); + } + } + + ctx->curClipState = vkvg_clip_state_none; + + ctx->dashOffset = sav->dashOffset; + if (ctx->dashCount > 0) + free(ctx->dashes); + ctx->dashCount = sav->dashCount; + if (ctx->dashCount > 0) { + ctx->dashes = (float *)malloc(sizeof(float) * ctx->dashCount); + memcpy(ctx->dashes, sav->dashes, sizeof(float) * ctx->dashCount); + } + + ctx->lineWidth = sav->lineWidth; + ctx->miterLimit = sav->miterLimit; + ctx->curOperator = sav->curOperator; + ctx->lineCap = sav->lineCap; + ctx->lineJoin = sav->lineJoint; + ctx->curFillRule = sav->curFillRule; + + ctx->selectedCharSize = sav->selectedCharSize; + strcpy(ctx->selectedFontName, sav->selectedFontName); + + ctx->currentFont = sav->currentFont; + ctx->textDirection = sav->textDirection; + + if (sav->pattern) { + if (sav->pattern != ctx->pattern) + _update_cur_pattern(ctx, sav->pattern); + else + vkvg_pattern_destroy(sav->pattern); + } else { + ctx->curColor = sav->curColor; + _update_cur_pattern(ctx, NULL); + } + + _free_ctx_save(sav); +} + +void vkvg_translate(VkvgContext ctx, float dx, float dy) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_TRANSLATE, dx, dy); + LOG(VKVG_LOG_INFO_CMD, "CMD: translate: %f, %f\n", dx, dy); + _emit_draw_cmd_undrawn_vertices(ctx); + vkvg_matrix_translate(&ctx->pushConsts.mat, dx, dy); + _set_mat_inv_and_vkCmdPush(ctx); +} +void vkvg_scale(VkvgContext ctx, float sx, float sy) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SCALE, sx, sy); + LOG(VKVG_LOG_INFO_CMD, "CMD: scale: %f, %f\n", sx, sy); + _emit_draw_cmd_undrawn_vertices(ctx); + vkvg_matrix_scale(&ctx->pushConsts.mat, sx, sy); + _set_mat_inv_and_vkCmdPush(ctx); +} +void vkvg_rotate(VkvgContext ctx, float radians) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_ROTATE, radians); + LOG(VKVG_LOG_INFO_CMD, "CMD: rotate: %f\n", radians); + _emit_draw_cmd_undrawn_vertices(ctx); + vkvg_matrix_rotate(&ctx->pushConsts.mat, radians); + _set_mat_inv_and_vkCmdPush(ctx); +} +void vkvg_transform(VkvgContext ctx, const vkvg_matrix_t *matrix) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_TRANSFORM, matrix); + LOG(VKVG_LOG_INFO_CMD, "CMD: transform: %f, %f, %f, %f, %f, %f\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + _emit_draw_cmd_undrawn_vertices(ctx); + vkvg_matrix_t res; + vkvg_matrix_multiply(&res, &ctx->pushConsts.mat, matrix); + ctx->pushConsts.mat = res; + _set_mat_inv_and_vkCmdPush(ctx); +} +void vkvg_identity_matrix(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_IDENTITY_MATRIX); + LOG(VKVG_LOG_INFO_CMD, "CMD: identity_matrix:\n"); + _emit_draw_cmd_undrawn_vertices(ctx); + vkvg_matrix_t im = VKVG_IDENTITY_MATRIX; + ctx->pushConsts.mat = im; + _set_mat_inv_and_vkCmdPush(ctx); +} +void vkvg_set_matrix(VkvgContext ctx, const vkvg_matrix_t *matrix) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_MATRIX, matrix); + LOG(VKVG_LOG_INFO_CMD, "CMD: set_matrix: %f, %f, %f, %f, %f, %f\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + _emit_draw_cmd_undrawn_vertices(ctx); + ctx->pushConsts.mat = (*matrix); + _set_mat_inv_and_vkCmdPush(ctx); +} +void vkvg_get_matrix(VkvgContext ctx, vkvg_matrix_t *const matrix) { *matrix = ctx->pushConsts.mat; } + +void vkvg_elliptic_arc_to(VkvgContext ctx, float x2, float y2, bool largeArc, bool sweepFlag, float rx, float ry, + float phi) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_ELLIPTICAL_ARC_TO, x2, y2, rx, ry, phi, largeArc, sweepFlag); + LOG(VKVG_LOG_INFO_CMD, + "\tCMD: elliptic_arc_to: x2:%10.5f y2:%10.5f large:%d sweep:%d rx:%10.5f ry:%10.5f phi:%10.5f \n", x2, y2, + largeArc, sweepFlag, rx, ry, phi); + float x1, y1; + vkvg_get_current_point(ctx, &x1, &y1); + _elliptic_arc(ctx, x1, y1, x2, y2, largeArc, sweepFlag, rx, ry, phi); +} +void vkvg_rel_elliptic_arc_to(VkvgContext ctx, float x2, float y2, bool largeArc, bool sweepFlag, float rx, float ry, + float phi) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_REL_ELLIPTICAL_ARC_TO, x2, y2, rx, ry, phi, largeArc, sweepFlag); + LOG(VKVG_LOG_INFO_CMD, + "\tCMD: rel_elliptic_arc_to: x2:%10.5f y2:%10.5f large:%d sweep:%d rx:%10.5f ry:%10.5f phi:%10.5f \n", x2, y2, + largeArc, sweepFlag, rx, ry, phi); + + float x1, y1; + vkvg_get_current_point(ctx, &x1, &y1); + _elliptic_arc(ctx, x1, y1, x2 + x1, y2 + y1, largeArc, sweepFlag, rx, ry, phi); +} + +void vkvg_ellipse(VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle) { + if (ctx->status) + return; + LOG(VKVG_LOG_INFO_CMD, "CMD: ellipse:\n"); + + float width_two_thirds = radiusX * 4 / 3; + + float dx1 = sinf(rotationAngle) * radiusY; + float dy1 = cosf(rotationAngle) * radiusY; + float dx2 = cosf(rotationAngle) * width_two_thirds; + float dy2 = sinf(rotationAngle) * width_two_thirds; + + float topCenterX = x - dx1; + float topCenterY = y + dy1; + float topRightX = topCenterX + dx2; + float topRightY = topCenterY + dy2; + float topLeftX = topCenterX - dx2; + float topLeftY = topCenterY - dy2; + + float bottomCenterX = x + dx1; + float bottomCenterY = y - dy1; + float bottomRightX = bottomCenterX + dx2; + float bottomRightY = bottomCenterY + dy2; + float bottomLeftX = bottomCenterX - dx2; + float bottomLeftY = bottomCenterY - dy2; + + _finish_path(ctx); + _add_point(ctx, bottomCenterX, bottomCenterY); + + _curve_to(ctx, bottomRightX, bottomRightY, topRightX, topRightY, topCenterX, topCenterY); + _curve_to(ctx, topLeftX, topLeftY, bottomLeftX, bottomLeftY, bottomCenterX, bottomCenterY); + + ctx->pathes[ctx->pathPtr] |= PATH_CLOSED_BIT; + _finish_path(ctx); +} + +VkvgSurface vkvg_get_target(VkvgContext ctx) { + if (ctx->status) + return NULL; + return ctx->pSurf; +} + +const char *vkvg_status_to_string(vkvg_status_t status) { + switch (status) { + case VKVG_STATUS_SUCCESS: + return "no error has occurred"; + case VKVG_STATUS_NO_MEMORY: + return "out of memory"; + case VKVG_STATUS_INVALID_RESTORE: + return "vkvg_restore() without matching vkvg_save()"; + case VKVG_STATUS_NO_CURRENT_POINT: + return "no current point defined"; + case VKVG_STATUS_INVALID_MATRIX: + return "invalid matrix (not invertible)"; + case VKVG_STATUS_INVALID_STATUS: + return "invalid value for an input vkvg_status_t"; + case VKVG_STATUS_INVALID_INDEX: + return "invalid index passed to getter"; + case VKVG_STATUS_NULL_POINTER: + return "NULL pointer"; + case VKVG_STATUS_WRITE_ERROR: + return "error while writing to output stream"; + case VKVG_STATUS_PATTERN_TYPE_MISMATCH: + return "the pattern type is not appropriate for the operation"; + case VKVG_STATUS_PATTERN_INVALID_GRADIENT: + return "the stops count is zero"; + case VKVG_STATUS_INVALID_FORMAT: + return "invalid value for an input vkvg_format_t"; + case VKVG_STATUS_FILE_NOT_FOUND: + return "file not found"; + case VKVG_STATUS_INVALID_DASH: + return "invalid value for a dash setting"; + case VKVG_STATUS_INVALID_RECT: + return "a rectangle has the height or width equal to 0"; + case VKVG_STATUS_TIMEOUT: + return "waiting for a Vulkan operation to finish resulted in a fence timeout (5 seconds)"; + case VKVG_STATUS_DEVICE_ERROR: + return "the initialization of the device resulted in an error"; + case VKVG_STATUS_INVALID_IMAGE: + return "invalid image"; + case VKVG_STATUS_INVALID_SURFACE: + return "invalid surface"; + case VKVG_STATUS_INVALID_FONT: + return "unresolved font name"; + default: + return ""; + } } diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index b6a9068..ce68947 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -//credits for bezier algorithms to: +// credits for bezier algorithms to: // Anti-Grain Geometry (AGG) - Version 2.5 // A high quality rendering engine for C++ // Copyright (C) 2002-2006 Maxim Shemanarev @@ -28,7 +28,6 @@ // mcseemagg@yahoo.com // http://antigrain.com - #include "vkvg_surface_internal.h" #include "vkvg_context_internal.h" #include "vkvg_device_internal.h" @@ -40,1978 +39,1915 @@ #include "glutess.h" #endif -void _resize_vertex_cache (VkvgContext ctx, uint32_t newSize) { - Vertex* tmp = (Vertex*) realloc (ctx->vertexCache, (size_t)newSize * sizeof(Vertex)); - LOG(VKVG_LOG_DBG_ARRAYS, "resize vertex cache (vx count=%u): old size: %u -> new size: %u size(byte): %zu Ptr: %p -> %p\n", - ctx->vertCount, ctx->sizeVertices, newSize, (size_t)newSize * sizeof(Vertex), ctx->vertexCache, tmp); - if (tmp == NULL){ - ctx->status = VKVG_STATUS_NO_MEMORY; - LOG(VKVG_LOG_ERR, "resize vertex cache failed: vert count: %u byte size: %zu\n", newSize, newSize * sizeof(Vertex)); - return; - } - ctx->vertexCache = tmp; - ctx->sizeVertices = newSize; -} -void _resize_index_cache (VkvgContext ctx, uint32_t newSize) { - VKVG_IBO_INDEX_TYPE* tmp = (VKVG_IBO_INDEX_TYPE*) realloc (ctx->indexCache, (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE)); - LOG(VKVG_LOG_DBG_ARRAYS, "resize IBO: new size: %lu Ptr: %p -> %p\n", (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE), ctx->indexCache, tmp); - if (tmp == NULL){ - ctx->status = VKVG_STATUS_NO_MEMORY; - LOG(VKVG_LOG_ERR, "resize IBO failed: idx count: %u size(byte): %zu\n", newSize, (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE)); - return; - } - ctx->indexCache = tmp; - ctx->sizeIndices = newSize; -} -void _ensure_vertex_cache_size (VkvgContext ctx, uint32_t addedVerticesCount) { - if (ctx->sizeVertices - ctx->vertCount > VKVG_ARRAY_THRESHOLD + addedVerticesCount) - return; - uint32_t newSize = ctx->sizeVertices + addedVerticesCount; - uint32_t modulo = addedVerticesCount % VKVG_VBO_SIZE; - if (modulo > 0) - newSize += VKVG_VBO_SIZE - modulo; - _resize_vertex_cache (ctx, newSize); -} -void _check_vertex_cache_size (VkvgContext ctx) { - assert(ctx->sizeVertices > ctx->vertCount); - if (ctx->sizeVertices - VKVG_ARRAY_THRESHOLD > ctx->vertCount) - return; - _resize_vertex_cache (ctx, ctx->sizeVertices + VKVG_VBO_SIZE); -} -void _ensure_index_cache_size (VkvgContext ctx, uint32_t addedIndicesCount) { - assert(ctx->sizeIndices > ctx->indCount); - if (ctx->sizeIndices - VKVG_ARRAY_THRESHOLD > ctx->indCount + addedIndicesCount) - return; - uint32_t newSize = ctx->sizeIndices + addedIndicesCount; - uint32_t modulo = addedIndicesCount % VKVG_IBO_SIZE; - if (modulo > 0) - newSize += VKVG_IBO_SIZE - modulo; - _resize_index_cache (ctx, newSize); -} -void _check_index_cache_size (VkvgContext ctx) { - if (ctx->sizeIndices - VKVG_ARRAY_THRESHOLD > ctx->indCount) - return; - _resize_index_cache (ctx, ctx->sizeIndices + VKVG_IBO_SIZE); -} -//check host path array size, return true if error. pathPtr is already incremented -bool _check_pathes_array (VkvgContext ctx){ - if (ctx->sizePathes - ctx->pathPtr - ctx->segmentPtr > VKVG_ARRAY_THRESHOLD) - return false; - ctx->sizePathes += VKVG_PATHES_SIZE; - uint32_t* tmp = (uint32_t*) realloc (ctx->pathes, (size_t)ctx->sizePathes * sizeof(uint32_t)); - LOG(VKVG_LOG_DBG_ARRAYS, "resize PATH: new size: %u Ptr: %p -> %p\n", ctx->sizePathes, ctx->pathes, tmp); - if (tmp == NULL){ - ctx->status = VKVG_STATUS_NO_MEMORY; - LOG(VKVG_LOG_ERR, "resize PATH failed: new size(byte): %zu\n", ctx->sizePathes * sizeof(uint32_t)); - _clear_path(ctx); - return true; - } - ctx->pathes = tmp; - return false; -} -//check host point array size, return true if error -bool _check_point_array (VkvgContext ctx){ - if (ctx->sizePoints - VKVG_ARRAY_THRESHOLD > ctx->pointCount) - return false; - ctx->sizePoints += VKVG_PTS_SIZE; - vec2* tmp = (vec2*) realloc (ctx->points, (size_t)ctx->sizePoints * sizeof(vec2)); - LOG(VKVG_LOG_DBG_ARRAYS, "resize Points: new size(point): %u Ptr: %p -> %p\n", ctx->sizePoints, ctx->points, tmp); - if (tmp == NULL){ - ctx->status = VKVG_STATUS_NO_MEMORY; - LOG(VKVG_LOG_ERR, "resize PATH failed: new size(byte): %zu\n", ctx->sizePoints * sizeof(vec2)); - _clear_path (ctx); - return true; - } - ctx->points = tmp; - return false; -} -bool _current_path_is_empty (VkvgContext ctx) { - return ctx->pathes [ctx->pathPtr] == 0; -} -//this function expect that current point exists -vec2 _get_current_position (VkvgContext ctx) { - return ctx->points[ctx->pointCount-1]; -} -//set curve start point and set path has curve bit -void _set_curve_start (VkvgContext ctx) { - if (ctx->segmentPtr > 0) { - //check if current segment has points (straight) - if ((ctx->pathes [ctx->pathPtr + ctx->segmentPtr]&PATH_ELT_MASK) > 0) - ctx->segmentPtr++; - }else{ - //not yet segmented path, first segment length is copied - if (ctx->pathes [ctx->pathPtr] > 0){//create first straight segment first - ctx->pathes [ctx->pathPtr + 1] = ctx->pathes [ctx->pathPtr]; - ctx->segmentPtr = 2; - }else - ctx->segmentPtr = 1; - } - _check_pathes_array(ctx); - ctx->pathes [ctx->pathPtr + ctx->segmentPtr] = 0; -} -//compute segment length and set is curved bit -void _set_curve_end (VkvgContext ctx) { - //ctx->pathes [ctx->pathPtr + ctx->segmentPtr] = ctx->pathes [ctx->pathPtr] - ctx->pathes [ctx->pathPtr + ctx->segmentPtr]; - ctx->pathes [ctx->pathPtr + ctx->segmentPtr] |= PATH_HAS_CURVES_BIT; - ctx->segmentPtr++; - _check_pathes_array(ctx); - ctx->pathes [ctx->pathPtr + ctx->segmentPtr] = 0; -} -//path start pointed at ptrPath has curve bit -bool _path_has_curves (VkvgContext ctx, uint32_t ptrPath) { - return ctx->pathes[ptrPath] & PATH_HAS_CURVES_BIT; -} -void _finish_path (VkvgContext ctx){ - if (ctx->pathes [ctx->pathPtr] == 0)//empty - return; - if ((ctx->pathes [ctx->pathPtr]&PATH_ELT_MASK) < 2){ - //only current pos is in path - ctx->pointCount -= ctx->pathes[ctx->pathPtr];//what about the bounds? - ctx->pathes[ctx->pathPtr] = 0; - ctx->segmentPtr = 0; - return; - } - - LOG(VKVG_LOG_INFO_PATH, "PATH: points count=%10d\n", ctx->pathes[ctx->pathPtr]&PATH_ELT_MASK); - - if (ctx->pathPtr == 0 && ctx->simpleConvex) - ctx->pathes[0] |= PATH_IS_CONVEX_BIT; - - if (ctx->segmentPtr > 0) {//pathes having curves are segmented - ctx->pathes[ctx->pathPtr] |= PATH_HAS_CURVES_BIT; - //curved segment increment segmentPtr on curve end, - //so if last segment is not a curve and point count > 0 - if ((ctx->pathes[ctx->pathPtr+ctx->segmentPtr]&PATH_HAS_CURVES_BIT)==0 && - (ctx->pathes[ctx->pathPtr+ctx->segmentPtr]&PATH_ELT_MASK) > 0) - ctx->segmentPtr++;//current segment has to be included - ctx->pathPtr += ctx->segmentPtr; - }else - ctx->pathPtr ++; - - if (_check_pathes_array(ctx)) - return; - - ctx->pathes[ctx->pathPtr] = 0; - ctx->segmentPtr = 0; - ctx->subpathCount++; - ctx->simpleConvex = false; -} -//clear path datas in context -void _clear_path (VkvgContext ctx){ - ctx->pathPtr = 0; - ctx->pathes [ctx->pathPtr] = 0; - ctx->pointCount = 0; - ctx->segmentPtr = 0; - ctx->subpathCount = 0; - ctx->simpleConvex = false; -} -void _remove_last_point (VkvgContext ctx){ - ctx->pathes[ctx->pathPtr]--; - ctx->pointCount--; - if (ctx->segmentPtr > 0){//if path is segmented - if (!ctx->pathes [ctx->pathPtr + ctx->segmentPtr])//if current segment is empty - ctx->segmentPtr--; - ctx->pathes [ctx->pathPtr + ctx->segmentPtr]--;//decrement last segment point count - if ((ctx->pathes [ctx->pathPtr + ctx->segmentPtr]&PATH_ELT_MASK) == 0)//if no point left (was only one) - ctx->pathes [ctx->pathPtr + ctx->segmentPtr] = 0;//reset current segment - else if (ctx->pathes [ctx->pathPtr + ctx->segmentPtr]&PATH_HAS_CURVES_BIT)//if segment is a curve - ctx->segmentPtr++;//then segPtr has to be forwarded to new segment - } -} -bool _path_is_closed (VkvgContext ctx, uint32_t ptrPath){ - return ctx->pathes[ptrPath] & PATH_CLOSED_BIT; -} -void _add_point (VkvgContext ctx, float x, float y){ - if (_check_point_array(ctx)) - return; - if (isnan(x) || isnan(y)) { - LOG(VKVG_LOG_DEBUG, "_add_point: (%f, %f)\n", x, y); - return; - } - vec2 v = {x,y}; - /*if (!_current_path_is_empty(ctx) && vec2_length(vec2_sub(ctx->points[ctx->pointCount-1], v))<1.f) - return;*/ - LOG(VKVG_LOG_INFO_PTS, "_add_point: (%f, %f)\n", x, y); - - ctx->points[ctx->pointCount] = v; - ctx->pointCount++;//total point count of pathes, (for array bounds check) - ctx->pathes[ctx->pathPtr]++;//total point count in path - if (ctx->segmentPtr > 0) - ctx->pathes[ctx->pathPtr + ctx->segmentPtr]++;//total point count in path's segment -} -float _normalizeAngle(float a) -{ - float res = ROUND_DOWN(fmodf(a, 2.0f * M_PIF), 100); - if (res < 0.0f) - res += 2.0f * M_PIF; - return res; -} -float _get_arc_step (VkvgContext ctx, float radius) { - float sx, sy; - vkvg_matrix_get_scale (&ctx->pushConsts.mat, &sx, &sy); - float r = radius * fabsf(fmaxf(sx,sy)); - if (r < 30.0f) - return fminf(M_PIF / 3.f, M_PIF / r); - return fminf(M_PIF / 3.f,M_PIF / (r * 0.4f)); -} -void _create_gradient_buff (VkvgContext ctx){ - vkh_buffer_init ((VkhDevice)ctx->dev, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VKH_MEMORY_USAGE_CPU_TO_GPU, - sizeof(vkvg_gradient_t), &ctx->uboGrad, true); -} -void _create_vertices_buff (VkvgContext ctx){ - vkh_buffer_init ((VkhDevice)ctx->dev, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VKH_MEMORY_USAGE_CPU_TO_GPU, - ctx->sizeVBO * sizeof(Vertex), &ctx->vertices, true); - vkh_buffer_init ((VkhDevice)ctx->dev, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VKH_MEMORY_USAGE_CPU_TO_GPU, - ctx->sizeIBO * sizeof(VKVG_IBO_INDEX_TYPE), &ctx->indices, true); -} -void _resize_vbo (VkvgContext ctx, uint32_t new_size) { - if (!_wait_ctx_flush_end (ctx))//wait previous cmd if not completed - return; - LOG(VKVG_LOG_DBG_ARRAYS, "resize VBO: %d -> ", ctx->sizeVBO); - ctx->sizeVBO = new_size; - uint32_t mod = ctx->sizeVBO % VKVG_VBO_SIZE; - if (mod > 0) - ctx->sizeVBO += VKVG_VBO_SIZE - mod; - LOG(VKVG_LOG_DBG_ARRAYS, "%d\n", ctx->sizeVBO); - vkh_buffer_resize (&ctx->vertices, ctx->sizeVBO * sizeof(Vertex), true); -} -void _resize_ibo (VkvgContext ctx, size_t new_size) { - if (!_wait_ctx_flush_end (ctx))//wait previous cmd if not completed - return; - ctx->sizeIBO = new_size; - uint32_t mod = ctx->sizeIBO % VKVG_IBO_SIZE; - if (mod > 0) - ctx->sizeIBO += VKVG_IBO_SIZE - mod; - LOG(VKVG_LOG_DBG_ARRAYS, "resize IBO: new size: %d\n", ctx->sizeIBO); - vkh_buffer_resize (&ctx->indices, ctx->sizeIBO * sizeof(VKVG_IBO_INDEX_TYPE), true); -} -void _add_vertexf (VkvgContext ctx, float x, float y){ - Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; - pVert->pos.x = x; - pVert->pos.y = y; - pVert->color = ctx->curColor; - pVert->uv.z = -1; - LOG(VKVG_LOG_INFO_VBO, "Add Vertexf %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", ctx->vertCount, pVert->pos.x, pVert->pos.y, pVert->uv.x, pVert->uv.y, pVert->uv.z, pVert->color); - ctx->vertCount++; - _check_vertex_cache_size(ctx); -} -void _add_vertexf_unchecked (VkvgContext ctx, float x, float y){ - Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; - pVert->pos.x = x; - pVert->pos.y = y; - pVert->color = ctx->curColor; - pVert->uv.z = -1; - LOG(VKVG_LOG_INFO_VBO, "Add Vertexf %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", ctx->vertCount, pVert->pos.x, pVert->pos.y, pVert->uv.x, pVert->uv.y, pVert->uv.z, pVert->color); - ctx->vertCount++; -} -void _add_vertex(VkvgContext ctx, Vertex v){ - ctx->vertexCache[ctx->vertCount] = v; - LOG(VKVG_LOG_INFO_VBO, "Add Vertex %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", ctx->vertCount, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.uv.z, v.color); - ctx->vertCount++; - _check_vertex_cache_size(ctx); -} -void _set_vertex(VkvgContext ctx, uint32_t idx, Vertex v){ - ctx->vertexCache[idx] = v; -} +void _resize_vertex_cache(VkvgContext ctx, uint32_t newSize) { + Vertex *tmp = (Vertex *)realloc(ctx->vertexCache, (size_t)newSize * sizeof(Vertex)); + LOG(VKVG_LOG_DBG_ARRAYS, + "resize vertex cache (vx count=%u): old size: %u -> new size: %u size(byte): %zu Ptr: %p -> %p\n", + ctx->vertCount, ctx->sizeVertices, newSize, (size_t)newSize * sizeof(Vertex), ctx->vertexCache, tmp); + if (tmp == NULL) { + ctx->status = VKVG_STATUS_NO_MEMORY; + LOG(VKVG_LOG_ERR, "resize vertex cache failed: vert count: %u byte size: %zu\n", newSize, + newSize * sizeof(Vertex)); + return; + } + ctx->vertexCache = tmp; + ctx->sizeVertices = newSize; +} +void _resize_index_cache(VkvgContext ctx, uint32_t newSize) { + VKVG_IBO_INDEX_TYPE *tmp = + (VKVG_IBO_INDEX_TYPE *)realloc(ctx->indexCache, (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE)); + LOG(VKVG_LOG_DBG_ARRAYS, "resize IBO: new size: %lu Ptr: %p -> %p\n", (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE), + ctx->indexCache, tmp); + if (tmp == NULL) { + ctx->status = VKVG_STATUS_NO_MEMORY; + LOG(VKVG_LOG_ERR, "resize IBO failed: idx count: %u size(byte): %zu\n", newSize, + (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE)); + return; + } + ctx->indexCache = tmp; + ctx->sizeIndices = newSize; +} +void _ensure_vertex_cache_size(VkvgContext ctx, uint32_t addedVerticesCount) { + if (ctx->sizeVertices - ctx->vertCount > VKVG_ARRAY_THRESHOLD + addedVerticesCount) + return; + uint32_t newSize = ctx->sizeVertices + addedVerticesCount; + uint32_t modulo = addedVerticesCount % VKVG_VBO_SIZE; + if (modulo > 0) + newSize += VKVG_VBO_SIZE - modulo; + _resize_vertex_cache(ctx, newSize); +} +void _check_vertex_cache_size(VkvgContext ctx) { + assert(ctx->sizeVertices > ctx->vertCount); + if (ctx->sizeVertices - VKVG_ARRAY_THRESHOLD > ctx->vertCount) + return; + _resize_vertex_cache(ctx, ctx->sizeVertices + VKVG_VBO_SIZE); +} +void _ensure_index_cache_size(VkvgContext ctx, uint32_t addedIndicesCount) { + assert(ctx->sizeIndices > ctx->indCount); + if (ctx->sizeIndices - VKVG_ARRAY_THRESHOLD > ctx->indCount + addedIndicesCount) + return; + uint32_t newSize = ctx->sizeIndices + addedIndicesCount; + uint32_t modulo = addedIndicesCount % VKVG_IBO_SIZE; + if (modulo > 0) + newSize += VKVG_IBO_SIZE - modulo; + _resize_index_cache(ctx, newSize); +} +void _check_index_cache_size(VkvgContext ctx) { + if (ctx->sizeIndices - VKVG_ARRAY_THRESHOLD > ctx->indCount) + return; + _resize_index_cache(ctx, ctx->sizeIndices + VKVG_IBO_SIZE); +} +// check host path array size, return true if error. pathPtr is already incremented +bool _check_pathes_array(VkvgContext ctx) { + if (ctx->sizePathes - ctx->pathPtr - ctx->segmentPtr > VKVG_ARRAY_THRESHOLD) + return false; + ctx->sizePathes += VKVG_PATHES_SIZE; + uint32_t *tmp = (uint32_t *)realloc(ctx->pathes, (size_t)ctx->sizePathes * sizeof(uint32_t)); + LOG(VKVG_LOG_DBG_ARRAYS, "resize PATH: new size: %u Ptr: %p -> %p\n", ctx->sizePathes, ctx->pathes, tmp); + if (tmp == NULL) { + ctx->status = VKVG_STATUS_NO_MEMORY; + LOG(VKVG_LOG_ERR, "resize PATH failed: new size(byte): %zu\n", ctx->sizePathes * sizeof(uint32_t)); + _clear_path(ctx); + return true; + } + ctx->pathes = tmp; + return false; +} +// check host point array size, return true if error +bool _check_point_array(VkvgContext ctx) { + if (ctx->sizePoints - VKVG_ARRAY_THRESHOLD > ctx->pointCount) + return false; + ctx->sizePoints += VKVG_PTS_SIZE; + vec2 *tmp = (vec2 *)realloc(ctx->points, (size_t)ctx->sizePoints * sizeof(vec2)); + LOG(VKVG_LOG_DBG_ARRAYS, "resize Points: new size(point): %u Ptr: %p -> %p\n", ctx->sizePoints, ctx->points, tmp); + if (tmp == NULL) { + ctx->status = VKVG_STATUS_NO_MEMORY; + LOG(VKVG_LOG_ERR, "resize PATH failed: new size(byte): %zu\n", ctx->sizePoints * sizeof(vec2)); + _clear_path(ctx); + return true; + } + ctx->points = tmp; + return false; +} +bool _current_path_is_empty(VkvgContext ctx) { return ctx->pathes[ctx->pathPtr] == 0; } +// this function expect that current point exists +vec2 _get_current_position(VkvgContext ctx) { return ctx->points[ctx->pointCount - 1]; } +// set curve start point and set path has curve bit +void _set_curve_start(VkvgContext ctx) { + if (ctx->segmentPtr > 0) { + // check if current segment has points (straight) + if ((ctx->pathes[ctx->pathPtr + ctx->segmentPtr] & PATH_ELT_MASK) > 0) + ctx->segmentPtr++; + } else { + // not yet segmented path, first segment length is copied + if (ctx->pathes[ctx->pathPtr] > 0) { // create first straight segment first + ctx->pathes[ctx->pathPtr + 1] = ctx->pathes[ctx->pathPtr]; + ctx->segmentPtr = 2; + } else + ctx->segmentPtr = 1; + } + _check_pathes_array(ctx); + ctx->pathes[ctx->pathPtr + ctx->segmentPtr] = 0; +} +// compute segment length and set is curved bit +void _set_curve_end(VkvgContext ctx) { + // ctx->pathes [ctx->pathPtr + ctx->segmentPtr] = ctx->pathes [ctx->pathPtr] - ctx->pathes [ctx->pathPtr + + // ctx->segmentPtr]; + ctx->pathes[ctx->pathPtr + ctx->segmentPtr] |= PATH_HAS_CURVES_BIT; + ctx->segmentPtr++; + _check_pathes_array(ctx); + ctx->pathes[ctx->pathPtr + ctx->segmentPtr] = 0; +} +// path start pointed at ptrPath has curve bit +bool _path_has_curves(VkvgContext ctx, uint32_t ptrPath) { return ctx->pathes[ptrPath] & PATH_HAS_CURVES_BIT; } +void _finish_path(VkvgContext ctx) { + if (ctx->pathes[ctx->pathPtr] == 0) // empty + return; + if ((ctx->pathes[ctx->pathPtr] & PATH_ELT_MASK) < 2) { + // only current pos is in path + ctx->pointCount -= ctx->pathes[ctx->pathPtr]; // what about the bounds? + ctx->pathes[ctx->pathPtr] = 0; + ctx->segmentPtr = 0; + return; + } + + LOG(VKVG_LOG_INFO_PATH, "PATH: points count=%10d\n", ctx->pathes[ctx->pathPtr] & PATH_ELT_MASK); + + if (ctx->pathPtr == 0 && ctx->simpleConvex) + ctx->pathes[0] |= PATH_IS_CONVEX_BIT; + + if (ctx->segmentPtr > 0) { // pathes having curves are segmented + ctx->pathes[ctx->pathPtr] |= PATH_HAS_CURVES_BIT; + // curved segment increment segmentPtr on curve end, + // so if last segment is not a curve and point count > 0 + if ((ctx->pathes[ctx->pathPtr + ctx->segmentPtr] & PATH_HAS_CURVES_BIT) == 0 && + (ctx->pathes[ctx->pathPtr + ctx->segmentPtr] & PATH_ELT_MASK) > 0) + ctx->segmentPtr++; // current segment has to be included + ctx->pathPtr += ctx->segmentPtr; + } else + ctx->pathPtr++; + + if (_check_pathes_array(ctx)) + return; + + ctx->pathes[ctx->pathPtr] = 0; + ctx->segmentPtr = 0; + ctx->subpathCount++; + ctx->simpleConvex = false; +} +// clear path datas in context +void _clear_path(VkvgContext ctx) { + ctx->pathPtr = 0; + ctx->pathes[ctx->pathPtr] = 0; + ctx->pointCount = 0; + ctx->segmentPtr = 0; + ctx->subpathCount = 0; + ctx->simpleConvex = false; +} +void _remove_last_point(VkvgContext ctx) { + ctx->pathes[ctx->pathPtr]--; + ctx->pointCount--; + if (ctx->segmentPtr > 0) { // if path is segmented + if (!ctx->pathes[ctx->pathPtr + ctx->segmentPtr]) // if current segment is empty + ctx->segmentPtr--; + ctx->pathes[ctx->pathPtr + ctx->segmentPtr]--; // decrement last segment point count + if ((ctx->pathes[ctx->pathPtr + ctx->segmentPtr] & PATH_ELT_MASK) == 0) // if no point left (was only one) + ctx->pathes[ctx->pathPtr + ctx->segmentPtr] = 0; // reset current segment + else if (ctx->pathes[ctx->pathPtr + ctx->segmentPtr] & PATH_HAS_CURVES_BIT) // if segment is a curve + ctx->segmentPtr++; // then segPtr has to be forwarded to new segment + } +} +bool _path_is_closed(VkvgContext ctx, uint32_t ptrPath) { return ctx->pathes[ptrPath] & PATH_CLOSED_BIT; } +void _add_point(VkvgContext ctx, float x, float y) { + if (_check_point_array(ctx)) + return; + if (isnan(x) || isnan(y)) { + LOG(VKVG_LOG_DEBUG, "_add_point: (%f, %f)\n", x, y); + return; + } + vec2 v = {x, y}; + /*if (!_current_path_is_empty(ctx) && vec2_length(vec2_sub(ctx->points[ctx->pointCount-1], v))<1.f) + return;*/ + LOG(VKVG_LOG_INFO_PTS, "_add_point: (%f, %f)\n", x, y); + + ctx->points[ctx->pointCount] = v; + ctx->pointCount++; // total point count of pathes, (for array bounds check) + ctx->pathes[ctx->pathPtr]++; // total point count in path + if (ctx->segmentPtr > 0) + ctx->pathes[ctx->pathPtr + ctx->segmentPtr]++; // total point count in path's segment +} +float _normalizeAngle(float a) { + float res = ROUND_DOWN(fmodf(a, 2.0f * M_PIF), 100); + if (res < 0.0f) + res += 2.0f * M_PIF; + return res; +} +float _get_arc_step(VkvgContext ctx, float radius) { + float sx, sy; + vkvg_matrix_get_scale(&ctx->pushConsts.mat, &sx, &sy); + float r = radius * fabsf(fmaxf(sx, sy)); + if (r < 30.0f) + return fminf(M_PIF / 3.f, M_PIF / r); + return fminf(M_PIF / 3.f, M_PIF / (r * 0.4f)); +} +void _create_gradient_buff(VkvgContext ctx) { + vkh_buffer_init((VkhDevice)ctx->dev, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VKH_MEMORY_USAGE_CPU_TO_GPU, + sizeof(vkvg_gradient_t), &ctx->uboGrad, true); +} +void _create_vertices_buff(VkvgContext ctx) { + vkh_buffer_init((VkhDevice)ctx->dev, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VKH_MEMORY_USAGE_CPU_TO_GPU, + ctx->sizeVBO * sizeof(Vertex), &ctx->vertices, true); + vkh_buffer_init((VkhDevice)ctx->dev, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VKH_MEMORY_USAGE_CPU_TO_GPU, + ctx->sizeIBO * sizeof(VKVG_IBO_INDEX_TYPE), &ctx->indices, true); +} +void _resize_vbo(VkvgContext ctx, uint32_t new_size) { + if (!_wait_ctx_flush_end(ctx)) // wait previous cmd if not completed + return; + LOG(VKVG_LOG_DBG_ARRAYS, "resize VBO: %d -> ", ctx->sizeVBO); + ctx->sizeVBO = new_size; + uint32_t mod = ctx->sizeVBO % VKVG_VBO_SIZE; + if (mod > 0) + ctx->sizeVBO += VKVG_VBO_SIZE - mod; + LOG(VKVG_LOG_DBG_ARRAYS, "%d\n", ctx->sizeVBO); + vkh_buffer_resize(&ctx->vertices, ctx->sizeVBO * sizeof(Vertex), true); +} +void _resize_ibo(VkvgContext ctx, size_t new_size) { + if (!_wait_ctx_flush_end(ctx)) // wait previous cmd if not completed + return; + ctx->sizeIBO = new_size; + uint32_t mod = ctx->sizeIBO % VKVG_IBO_SIZE; + if (mod > 0) + ctx->sizeIBO += VKVG_IBO_SIZE - mod; + LOG(VKVG_LOG_DBG_ARRAYS, "resize IBO: new size: %d\n", ctx->sizeIBO); + vkh_buffer_resize(&ctx->indices, ctx->sizeIBO * sizeof(VKVG_IBO_INDEX_TYPE), true); +} +void _add_vertexf(VkvgContext ctx, float x, float y) { + Vertex *pVert = &ctx->vertexCache[ctx->vertCount]; + pVert->pos.x = x; + pVert->pos.y = y; + pVert->color = ctx->curColor; + pVert->uv.z = -1; + LOG(VKVG_LOG_INFO_VBO, "Add Vertexf %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", + ctx->vertCount, pVert->pos.x, pVert->pos.y, pVert->uv.x, pVert->uv.y, pVert->uv.z, pVert->color); + ctx->vertCount++; + _check_vertex_cache_size(ctx); +} +void _add_vertexf_unchecked(VkvgContext ctx, float x, float y) { + Vertex *pVert = &ctx->vertexCache[ctx->vertCount]; + pVert->pos.x = x; + pVert->pos.y = y; + pVert->color = ctx->curColor; + pVert->uv.z = -1; + LOG(VKVG_LOG_INFO_VBO, "Add Vertexf %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", + ctx->vertCount, pVert->pos.x, pVert->pos.y, pVert->uv.x, pVert->uv.y, pVert->uv.z, pVert->color); + ctx->vertCount++; +} +void _add_vertex(VkvgContext ctx, Vertex v) { + ctx->vertexCache[ctx->vertCount] = v; + LOG(VKVG_LOG_INFO_VBO, "Add Vertex %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", + ctx->vertCount, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.uv.z, v.color); + ctx->vertCount++; + _check_vertex_cache_size(ctx); +} +void _set_vertex(VkvgContext ctx, uint32_t idx, Vertex v) { ctx->vertexCache[idx] = v; } #ifdef VKVG_FILL_NZ_GLUTESS -void _add_indice (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i) { - ctx->indexCache[ctx->indCount++] = i; - _check_index_cache_size(ctx); -} -void _add_indice_for_fan (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i) { - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; - inds[0] = ctx->tesselator_fan_start; - inds[1] = ctx->indexCache[ctx->indCount-1]; - inds[2] = i; - ctx->indCount+=3; - _check_index_cache_size(ctx); -} -void _add_indice_for_strip (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i, bool odd) { - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; - if (odd) { - inds[0] = ctx->indexCache[ctx->indCount-2]; - inds[1] = i; - inds[2] = ctx->indexCache[ctx->indCount-1]; - } else { - inds[0] = ctx->indexCache[ctx->indCount-1]; - inds[1] = ctx->indexCache[ctx->indCount-2]; - inds[2] = i; - } - ctx->indCount+=3; - _check_index_cache_size(ctx); +void _add_indice(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i) { + ctx->indexCache[ctx->indCount++] = i; + _check_index_cache_size(ctx); +} +void _add_indice_for_fan(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i) { + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount]; + inds[0] = ctx->tesselator_fan_start; + inds[1] = ctx->indexCache[ctx->indCount - 1]; + inds[2] = i; + ctx->indCount += 3; + _check_index_cache_size(ctx); +} +void _add_indice_for_strip(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i, bool odd) { + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount]; + if (odd) { + inds[0] = ctx->indexCache[ctx->indCount - 2]; + inds[1] = i; + inds[2] = ctx->indexCache[ctx->indCount - 1]; + } else { + inds[0] = ctx->indexCache[ctx->indCount - 1]; + inds[1] = ctx->indexCache[ctx->indCount - 2]; + inds[2] = i; + } + ctx->indCount += 3; + _check_index_cache_size(ctx); } #endif -void _add_tri_indices_for_rect (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i){ - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; - inds[0] = i; - inds[1] = i+2; - inds[2] = i+1; - inds[3] = i+1; - inds[4] = i+2; - inds[5] = i+3; - ctx->indCount+=6; - - _check_index_cache_size(ctx); - LOG(VKVG_LOG_INFO_IBO, "Rectangle IDX: %d %d %d | %d %d %d (count=%d)\n", inds[0], inds[1], inds[2], inds[3], inds[4], inds[5], ctx->indCount); -} -void _add_triangle_indices(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2){ - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; - inds[0] = i0; - inds[1] = i1; - inds[2] = i2; - ctx->indCount+=3; - - _check_index_cache_size(ctx); - LOG(VKVG_LOG_INFO_IBO, "Triangle IDX: %d %d %d (indCount=%d)\n", i0,i1,i2,ctx->indCount); -} -void _add_triangle_indices_unchecked (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2){ - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; - inds[0] = i0; - inds[1] = i1; - inds[2] = i2; - ctx->indCount+=3; - - LOG(VKVG_LOG_INFO_IBO, "Triangle IDX: %d %d %d (indCount=%d)\n", i0,i1,i2,ctx->indCount); -} -void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float height){ - Vertex v[4] = - { - {{x,y}, ctx->curColor, {0,0,-1}}, - {{x,y+height}, ctx->curColor, {0,0,-1}}, - {{x+width,y}, ctx->curColor, {0,0,-1}}, - {{x+width,y+height},ctx->curColor, {0,0,-1}} - }; - VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; - memcpy (pVert,v,4*sizeof(Vertex)); - ctx->vertCount+=4; - - _check_vertex_cache_size(ctx); - - _add_tri_indices_for_rect(ctx, firstIdx); -} -//start render pass if not yet started or update push const if requested -void _ensure_renderpass_is_started (VkvgContext ctx) { - LOG(VKVG_LOG_INFO, "_ensure_renderpass_is_started\n"); - if (!ctx->cmdStarted) - _start_cmd_for_render_pass(ctx); - else if (ctx->pushCstDirty) - _update_push_constants(ctx); -} -void _create_cmd_buff (VkvgContext ctx){ - vkh_cmd_buffs_create((VkhDevice)ctx->dev, ctx->cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY, 2, ctx->cmdBuffers); +void _add_tri_indices_for_rect(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i) { + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount]; + inds[0] = i; + inds[1] = i + 2; + inds[2] = i + 1; + inds[3] = i + 1; + inds[4] = i + 2; + inds[5] = i + 3; + ctx->indCount += 6; + + _check_index_cache_size(ctx); + LOG(VKVG_LOG_INFO_IBO, "Rectangle IDX: %d %d %d | %d %d %d (count=%d)\n", inds[0], inds[1], inds[2], inds[3], + inds[4], inds[5], ctx->indCount); +} +void _add_triangle_indices(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2) { + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount]; + inds[0] = i0; + inds[1] = i1; + inds[2] = i2; + ctx->indCount += 3; + + _check_index_cache_size(ctx); + LOG(VKVG_LOG_INFO_IBO, "Triangle IDX: %d %d %d (indCount=%d)\n", i0, i1, i2, ctx->indCount); +} +void _add_triangle_indices_unchecked(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, + VKVG_IBO_INDEX_TYPE i2) { + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount]; + inds[0] = i0; + inds[1] = i1; + inds[2] = i2; + ctx->indCount += 3; + + LOG(VKVG_LOG_INFO_IBO, "Triangle IDX: %d %d %d (indCount=%d)\n", i0, i1, i2, ctx->indCount); +} +void _vao_add_rectangle(VkvgContext ctx, float x, float y, float width, float height) { + Vertex v[4] = {{{x, y}, ctx->curColor, {0, 0, -1}}, + {{x, y + height}, ctx->curColor, {0, 0, -1}}, + {{x + width, y}, ctx->curColor, {0, 0, -1}}, + {{x + width, y + height}, ctx->curColor, {0, 0, -1}}}; + VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + Vertex *pVert = &ctx->vertexCache[ctx->vertCount]; + memcpy(pVert, v, 4 * sizeof(Vertex)); + ctx->vertCount += 4; + + _check_vertex_cache_size(ctx); + + _add_tri_indices_for_rect(ctx, firstIdx); +} +// start render pass if not yet started or update push const if requested +void _ensure_renderpass_is_started(VkvgContext ctx) { + LOG(VKVG_LOG_INFO, "_ensure_renderpass_is_started\n"); + if (!ctx->cmdStarted) + _start_cmd_for_render_pass(ctx); + else if (ctx->pushCstDirty) + _update_push_constants(ctx); +} +void _create_cmd_buff(VkvgContext ctx) { + vkh_cmd_buffs_create((VkhDevice)ctx->dev, ctx->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 2, ctx->cmdBuffers); #if defined(DEBUG) && defined(ENABLE_VALIDATION) - vkh_device_set_object_name((VkhDevice)ctx->pSurf->dev, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)ctx->cmd, "vkvgCtxCmd"); + vkh_device_set_object_name((VkhDevice)ctx->pSurf->dev, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + (uint64_t)ctx->cmd, "vkvgCtxCmd"); #endif } -void _clear_attachment (VkvgContext ctx) { - -} +void _clear_attachment(VkvgContext ctx) {} -bool _wait_ctx_flush_end (VkvgContext ctx) { - LOG(VKVG_LOG_INFO, "CTX: _wait_flush_fence\n"); +bool _wait_ctx_flush_end(VkvgContext ctx) { + LOG(VKVG_LOG_INFO, "CTX: _wait_flush_fence\n"); #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - if (vkh_timeline_wait ((VkhDevice)ctx->dev, ctx->pSurf->timeline, ctx->timelineStep) == VK_SUCCESS) - return true; + if (vkh_timeline_wait((VkhDevice)ctx->dev, ctx->pSurf->timeline, ctx->timelineStep) == VK_SUCCESS) + return true; #else - if (WaitForFences (ctx->dev->vkDev, 1, &ctx->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) - return true; + if (WaitForFences(ctx->dev->vkDev, 1, &ctx->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) + return true; #endif - LOG(VKVG_LOG_DEBUG, "CTX: _wait_flush_fence timeout\n"); - ctx->status = VKVG_STATUS_TIMEOUT; - return false; + LOG(VKVG_LOG_DEBUG, "CTX: _wait_flush_fence timeout\n"); + ctx->status = VKVG_STATUS_TIMEOUT; + return false; } +bool _wait_and_submit_cmd(VkvgContext ctx) { + if (!ctx->cmdStarted) // current cmd buff is empty, be aware that wait is also canceled!! + return true; -bool _wait_and_submit_cmd (VkvgContext ctx){ - if (!ctx->cmdStarted)//current cmd buff is empty, be aware that wait is also canceled!! - return true; - - LOG(VKVG_LOG_INFO, "CTX: _wait_and_submit_cmd\n"); + LOG(VKVG_LOG_INFO, "CTX: _wait_and_submit_cmd\n"); #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - VkvgSurface surf = ctx->pSurf; - VkvgDevice dev = surf->dev; - //vkh_timeline_wait ((VkhDevice)dev, surf->timeline, ct->timelineStep); - if (ctx->pattern && ctx->pattern->type == VKVG_PATTERN_TYPE_SURFACE) { - //add source surface timeline sync. - VkvgSurface source = (VkvgSurface)ctx->pattern->data; - LOCK_SURFACE(surf) - LOCK_SURFACE(source) - LOCK_DEVICE - vkh_cmd_submit_timelined2 (dev->gQueue, &ctx->cmd, - (VkSemaphore[2]){surf->timeline,source->timeline}, - (uint64_t[2]){surf->timelineStep,source->timelineStep}, - (uint64_t[2]){surf->timelineStep+1,source->timelineStep+1}); - surf->timelineStep++; - source->timelineStep++; - ctx->timelineStep = surf->timelineStep; - UNLOCK_DEVICE - UNLOCK_SURFACE(source) - UNLOCK_SURFACE(surf) - } else { - LOCK_SURFACE(surf) - LOCK_DEVICE - vkh_cmd_submit_timelined (dev->gQueue, &ctx->cmd, surf->timeline, surf->timelineStep, surf->timelineStep+1); - surf->timelineStep++; - ctx->timelineStep = surf->timelineStep; - UNLOCK_DEVICE - UNLOCK_SURFACE(surf) - } + VkvgSurface surf = ctx->pSurf; + VkvgDevice dev = surf->dev; + // vkh_timeline_wait ((VkhDevice)dev, surf->timeline, ct->timelineStep); + if (ctx->pattern && ctx->pattern->type == VKVG_PATTERN_TYPE_SURFACE) { + // add source surface timeline sync. + VkvgSurface source = (VkvgSurface)ctx->pattern->data; + LOCK_SURFACE(surf) + LOCK_SURFACE(source) + LOCK_DEVICE + vkh_cmd_submit_timelined2(dev->gQueue, &ctx->cmd, (VkSemaphore[2]){surf->timeline, source->timeline}, + (uint64_t[2]){surf->timelineStep, source->timelineStep}, + (uint64_t[2]){surf->timelineStep + 1, source->timelineStep + 1}); + surf->timelineStep++; + source->timelineStep++; + ctx->timelineStep = surf->timelineStep; + UNLOCK_DEVICE + UNLOCK_SURFACE(source) + UNLOCK_SURFACE(surf) + } else { + LOCK_SURFACE(surf) + LOCK_DEVICE + vkh_cmd_submit_timelined(dev->gQueue, &ctx->cmd, surf->timeline, surf->timelineStep, surf->timelineStep + 1); + surf->timelineStep++; + ctx->timelineStep = surf->timelineStep; + UNLOCK_DEVICE + UNLOCK_SURFACE(surf) + } #else - if (!_wait_ctx_flush_end (ctx)) - return false; - ResetFences (ctx->dev->vkDev, 1, &ctx->flushFence); - _device_submit_cmd (ctx->dev, &ctx->cmd, ctx->flushFence); + if (!_wait_ctx_flush_end(ctx)) + return false; + ResetFences(ctx->dev->vkDev, 1, &ctx->flushFence); + _device_submit_cmd(ctx->dev, &ctx->cmd, ctx->flushFence); #endif - if (ctx->cmd == ctx->cmdBuffers[0]) - ctx->cmd = ctx->cmdBuffers[1]; - else - ctx->cmd = ctx->cmdBuffers[0]; - - ResetCommandBuffer (ctx->cmd, 0); - ctx->cmdStarted = false; - return true; -} -/*void _explicit_ms_resolve (VkvgContext ctx){//should init cmd before calling this (unused, using automatic resolve by renderpass) - vkh_image_set_layout (ctx->cmd, ctx->pSurf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (ctx->cmd, ctx->pSurf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkImageResolve re = { - .extent = {ctx->pSurf->width, ctx->pSurf->height,1}, - .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}, - .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1} - }; - - vkCmdResolveImage(ctx->cmd, - vkh_image_get_vkimage (ctx->pSurf->imgMS), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (ctx->pSurf->img) ,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1,&re); - vkh_image_set_layout (ctx->cmd, ctx->pSurf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL , - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + if (ctx->cmd == ctx->cmdBuffers[0]) + ctx->cmd = ctx->cmdBuffers[1]; + else + ctx->cmd = ctx->cmdBuffers[0]; + + ResetCommandBuffer(ctx->cmd, 0); + ctx->cmdStarted = false; + return true; +} +/*void _explicit_ms_resolve (VkvgContext ctx){//should init cmd before calling this (unused, using automatic resolve by +renderpass) vkh_image_set_layout (ctx->cmd, ctx->pSurf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout (ctx->cmd, ctx->pSurf->img, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkImageResolve re = { + .extent = {ctx->pSurf->width, ctx->pSurf->height,1}, + .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}, + .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1} + }; + + vkCmdResolveImage(ctx->cmd, + vkh_image_get_vkimage (ctx->pSurf->imgMS), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage (ctx->pSurf->img) ,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1,&re); + vkh_image_set_layout (ctx->cmd, ctx->pSurf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL , + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); }*/ -//pre flush vertices because of vbo or ibo too small, all vertices except last draw call are flushed -//this function expects a vertex offset > 0 -void _flush_vertices_caches_until_vertex_base (VkvgContext ctx) { - _wait_ctx_flush_end (ctx); - - memcpy(vkh_buffer_get_mapped_pointer(&ctx->vertices), ctx->vertexCache, ctx->curVertOffset * sizeof (Vertex)); - memcpy(vkh_buffer_get_mapped_pointer(&ctx->indices), ctx->indexCache, ctx->curIndStart * sizeof (VKVG_IBO_INDEX_TYPE)); - - //copy remaining vertices and indices to caches starts - //this could be optimized at the cost of additional offsets. - ctx->vertCount -= ctx->curVertOffset; - ctx->indCount -= ctx->curIndStart; - memcpy(ctx->vertexCache, &ctx->vertexCache[ctx->curVertOffset], ctx->vertCount * sizeof (Vertex)); - memcpy(ctx->indexCache, &ctx->indexCache[ctx->curIndStart], ctx->indCount * sizeof (VKVG_IBO_INDEX_TYPE)); - - ctx->curVertOffset = 0; - ctx->curIndStart = 0; -} -//copy vertex and index caches to the vbo and ibo vkbuffers used by gpu for drawing -//current running cmd has to be completed to free usage of those -void _flush_vertices_caches (VkvgContext ctx) { - if (!_wait_ctx_flush_end (ctx)) - return; - - memcpy(vkh_buffer_get_mapped_pointer(&ctx->vertices), ctx->vertexCache, ctx->vertCount * sizeof (Vertex)); - memcpy(vkh_buffer_get_mapped_pointer(&ctx->indices), ctx->indexCache, ctx->indCount * sizeof (VKVG_IBO_INDEX_TYPE)); - - ctx->vertCount = ctx->indCount = ctx->curIndStart = ctx->curVertOffset = 0; -} -//this func expect cmdStarted to be true -void _end_render_pass (VkvgContext ctx) { - LOG(VKVG_LOG_INFO, "END RENDER PASS: ctx = %p;\n", ctx); - CmdEndRenderPass (ctx->cmd); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); +// pre flush vertices because of vbo or ibo too small, all vertices except last draw call are flushed +// this function expects a vertex offset > 0 +void _flush_vertices_caches_until_vertex_base(VkvgContext ctx) { + _wait_ctx_flush_end(ctx); + + memcpy(vkh_buffer_get_mapped_pointer(&ctx->vertices), ctx->vertexCache, ctx->curVertOffset * sizeof(Vertex)); + memcpy(vkh_buffer_get_mapped_pointer(&ctx->indices), ctx->indexCache, + ctx->curIndStart * sizeof(VKVG_IBO_INDEX_TYPE)); + + // copy remaining vertices and indices to caches starts + // this could be optimized at the cost of additional offsets. + ctx->vertCount -= ctx->curVertOffset; + ctx->indCount -= ctx->curIndStart; + memcpy(ctx->vertexCache, &ctx->vertexCache[ctx->curVertOffset], ctx->vertCount * sizeof(Vertex)); + memcpy(ctx->indexCache, &ctx->indexCache[ctx->curIndStart], ctx->indCount * sizeof(VKVG_IBO_INDEX_TYPE)); + + ctx->curVertOffset = 0; + ctx->curIndStart = 0; +} +// copy vertex and index caches to the vbo and ibo vkbuffers used by gpu for drawing +// current running cmd has to be completed to free usage of those +void _flush_vertices_caches(VkvgContext ctx) { + if (!_wait_ctx_flush_end(ctx)) + return; + + memcpy(vkh_buffer_get_mapped_pointer(&ctx->vertices), ctx->vertexCache, ctx->vertCount * sizeof(Vertex)); + memcpy(vkh_buffer_get_mapped_pointer(&ctx->indices), ctx->indexCache, ctx->indCount * sizeof(VKVG_IBO_INDEX_TYPE)); + + ctx->vertCount = ctx->indCount = ctx->curIndStart = ctx->curVertOffset = 0; +} +// this func expect cmdStarted to be true +void _end_render_pass(VkvgContext ctx) { + LOG(VKVG_LOG_INFO, "END RENDER PASS: ctx = %p;\n", ctx); + CmdEndRenderPass(ctx->cmd); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); #endif - ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass; + ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass; } -void _check_vao_size (VkvgContext ctx) { - if (ctx->vertCount > ctx->sizeVBO || ctx->indCount > ctx->sizeIBO){ - //vbo or ibo buffers too small - if (ctx->cmdStarted) - //if cmd is started buffers, are already bound, so no resize is possible - //instead we flush, and clear vbo and ibo caches - _flush_cmd_until_vx_base (ctx); - if (ctx->vertCount > ctx->sizeVBO) - _resize_vbo(ctx, ctx->sizeVertices); - if (ctx->indCount > ctx->sizeIBO) - _resize_ibo(ctx, ctx->sizeIndices); - } +void _check_vao_size(VkvgContext ctx) { + if (ctx->vertCount > ctx->sizeVBO || ctx->indCount > ctx->sizeIBO) { + // vbo or ibo buffers too small + if (ctx->cmdStarted) + // if cmd is started buffers, are already bound, so no resize is possible + // instead we flush, and clear vbo and ibo caches + _flush_cmd_until_vx_base(ctx); + if (ctx->vertCount > ctx->sizeVBO) + _resize_vbo(ctx, ctx->sizeVertices); + if (ctx->indCount > ctx->sizeIBO) + _resize_ibo(ctx, ctx->sizeIndices); + } } -//stroke and non-zero draw call for solid color flush -void _emit_draw_cmd_undrawn_vertices (VkvgContext ctx){ - if (ctx->indCount == ctx->curIndStart) - return; +// stroke and non-zero draw call for solid color flush +void _emit_draw_cmd_undrawn_vertices(VkvgContext ctx) { + if (ctx->indCount == ctx->curIndStart) + return; - _check_vao_size (ctx); + _check_vao_size(ctx); - _ensure_renderpass_is_started (ctx); + _ensure_renderpass_is_started(ctx); #ifdef VKVG_WIRED_DEBUG - if (vkvg_wired_debug&vkvg_wired_debug_mode_normal) - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); - if (vkvg_wired_debug&vkvg_wired_debug_mode_lines) { - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineLineList); - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); - } - if (vkvg_wired_debug&vkvg_wired_debug_mode_points) { - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineWired); - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); - } - if (vkvg_wired_debug&vkvg_wired_debug_mode_both) - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipe_OVER); + if (vkvg_wired_debug & vkvg_wired_debug_mode_normal) + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + if (vkvg_wired_debug & vkvg_wired_debug_mode_lines) { + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineLineList); + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + } + if (vkvg_wired_debug & vkvg_wired_debug_mode_points) { + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineWired); + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + } + if (vkvg_wired_debug & vkvg_wired_debug_mode_both) + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipe_OVER); #else - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); #endif - LOG(VKVG_LOG_INFO, "RECORD DRAW CMD: ctx = %p; vertices = %d; indices = %d (vxOff = %d idxStart = %d idxTot = %d )\n", - ctx, ctx->vertCount - ctx->curVertOffset, - ctx->indCount - ctx->curIndStart, ctx->curVertOffset, ctx->curIndStart, ctx->indCount); - - ctx->curIndStart = ctx->indCount; - ctx->curVertOffset = ctx->vertCount; -} -//preflush vertices with drawcommand already emited -void _flush_cmd_until_vx_base (VkvgContext ctx){ - _end_render_pass (ctx); - if (ctx->curVertOffset > 0){ - LOG(VKVG_LOG_INFO, "FLUSH UNTIL VX BASE CTX: ctx = %p; vertices = %d; indices = %d\n", ctx, ctx->vertCount, ctx->indCount); - _flush_vertices_caches_until_vertex_base (ctx); - } - vkh_cmd_end (ctx->cmd); - _wait_and_submit_cmd (ctx); -} -void _flush_cmd_buff (VkvgContext ctx){ - _emit_draw_cmd_undrawn_vertices (ctx); - if (!ctx->cmdStarted) - return; - _end_render_pass (ctx); - LOG(VKVG_LOG_INFO, "FLUSH CTX: ctx = %p; vertices = %d; indices = %d\n", ctx, ctx->vertCount, ctx->indCount); - _flush_vertices_caches (ctx); - vkh_cmd_end (ctx->cmd); - - _wait_and_submit_cmd (ctx); -} - -//bind correct draw pipeline depending on current OPERATOR -void _bind_draw_pipeline (VkvgContext ctx) { - switch (ctx->curOperator) { - case VKVG_OPERATOR_OVER: - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_OVER); - break; - case VKVG_OPERATOR_CLEAR: - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_CLEAR); - break; - case VKVG_OPERATOR_DIFFERENCE: - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_SUB); - break; - default: - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_OVER); - break; - } -} -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) -const float DBG_LAB_COLOR_RP[4] = {0,0,1,1}; -const float DBG_LAB_COLOR_FSQ[4] = {1,0,0,1}; + LOG(VKVG_LOG_INFO, + "RECORD DRAW CMD: ctx = %p; vertices = %d; indices = %d (vxOff = %d idxStart = %d idxTot = %d )\n", ctx, + ctx->vertCount - ctx->curVertOffset, ctx->indCount - ctx->curIndStart, ctx->curVertOffset, ctx->curIndStart, + ctx->indCount); + + ctx->curIndStart = ctx->indCount; + ctx->curVertOffset = ctx->vertCount; +} +// preflush vertices with drawcommand already emited +void _flush_cmd_until_vx_base(VkvgContext ctx) { + _end_render_pass(ctx); + if (ctx->curVertOffset > 0) { + LOG(VKVG_LOG_INFO, "FLUSH UNTIL VX BASE CTX: ctx = %p; vertices = %d; indices = %d\n", ctx, ctx->vertCount, + ctx->indCount); + _flush_vertices_caches_until_vertex_base(ctx); + } + vkh_cmd_end(ctx->cmd); + _wait_and_submit_cmd(ctx); +} +void _flush_cmd_buff(VkvgContext ctx) { + _emit_draw_cmd_undrawn_vertices(ctx); + if (!ctx->cmdStarted) + return; + _end_render_pass(ctx); + LOG(VKVG_LOG_INFO, "FLUSH CTX: ctx = %p; vertices = %d; indices = %d\n", ctx, ctx->vertCount, ctx->indCount); + _flush_vertices_caches(ctx); + vkh_cmd_end(ctx->cmd); + + _wait_and_submit_cmd(ctx); +} + +// bind correct draw pipeline depending on current OPERATOR +void _bind_draw_pipeline(VkvgContext ctx) { + switch (ctx->curOperator) { + case VKVG_OPERATOR_OVER: + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_OVER); + break; + case VKVG_OPERATOR_CLEAR: + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_CLEAR); + break; + case VKVG_OPERATOR_DIFFERENCE: + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_SUB); + break; + default: + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_OVER); + break; + } +} +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) +const float DBG_LAB_COLOR_RP[4] = {0, 0, 1, 1}; +const float DBG_LAB_COLOR_FSQ[4] = {1, 0, 0, 1}; #endif -void _start_cmd_for_render_pass (VkvgContext ctx) { - LOG(VKVG_LOG_INFO, "START RENDER PASS: ctx = %p\n", ctx); - vkh_cmd_begin (ctx->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - - if (ctx->pSurf->img->layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || ctx->dev->threadAware){ - VkhImage imgMs = ctx->pSurf->imgMS; - if (imgMs != NULL) - vkh_image_set_layout(ctx->cmd, imgMs, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - - vkh_image_set_layout(ctx->cmd, ctx->pSurf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - vkh_image_set_layout (ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); - } - -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "ctx render pass", DBG_LAB_COLOR_RP); +void _start_cmd_for_render_pass(VkvgContext ctx) { + LOG(VKVG_LOG_INFO, "START RENDER PASS: ctx = %p\n", ctx); + vkh_cmd_begin(ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + + if (ctx->pSurf->img->layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || ctx->dev->threadAware) { + VkhImage imgMs = ctx->pSurf->imgMS; + if (imgMs != NULL) + vkh_image_set_layout(ctx->cmd, imgMs, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + + vkh_image_set_layout(ctx->cmd, ctx->pSurf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + vkh_image_set_layout(ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + } + +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "ctx render pass", DBG_LAB_COLOR_RP); #endif - CmdBeginRenderPass (ctx->cmd, &ctx->renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - VkViewport viewport = {0,0,(float)ctx->pSurf->width,(float)ctx->pSurf->height,0,1.f}; - CmdSetViewport(ctx->cmd, 0, 1, &viewport); - - CmdSetScissor(ctx->cmd, 0, 1, &ctx->bounds); - - VkDescriptorSet dss[] = {ctx->dsFont, ctx->dsSrc,ctx->dsGrad}; - CmdBindDescriptorSets(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineLayout, - 0, 3, dss, 0, NULL); - - VkDeviceSize offsets[1] = { 0 }; - CmdBindVertexBuffers(ctx->cmd, 0, 1, &ctx->vertices.buffer, offsets); - CmdBindIndexBuffer(ctx->cmd, ctx->indices.buffer, 0, VKVG_VK_INDEX_TYPE); - - _update_push_constants (ctx); - - _bind_draw_pipeline (ctx); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - ctx->cmdStarted = true; -} -//compute inverse mat used in shader when context matrix has changed -//then trigger push constants command -void _set_mat_inv_and_vkCmdPush (VkvgContext ctx) { - ctx->pushConsts.matInv = ctx->pushConsts.mat; - vkvg_matrix_invert (&ctx->pushConsts.matInv); - ctx->pushCstDirty = true; -} -void _update_push_constants (VkvgContext ctx) { - CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push_constants),&ctx->pushConsts); - ctx->pushCstDirty = false; -} -void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat) { - VkvgPattern lastPat = ctx->pattern; - ctx->pattern = pat; - - uint32_t newPatternType = VKVG_PATTERN_TYPE_SOLID; - - LOG(VKVG_LOG_INFO, "CTX: _update_cur_pattern: %p -> %p\n", lastPat, pat); - - if (pat == NULL) {//solid color - if (lastPat == NULL)//solid - return;//solid to solid transition, no extra action requested - }else - newPatternType = pat->type; - - switch (newPatternType) { - case VKVG_PATTERN_TYPE_SOLID: - _flush_cmd_buff (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; - if (lastPat->type == VKVG_PATTERN_TYPE_SURFACE)//unbind current source surface by replacing it with empty texture - _update_descriptor_set (ctx, ctx->dev->emptyImg, ctx->dsSrc); - break; - case VKVG_PATTERN_TYPE_SURFACE: - { - _emit_draw_cmd_undrawn_vertices(ctx); - - VkvgSurface surf = (VkvgSurface)pat->data; - - //flush ctx in two steps to add the src transitioning in the cmd buff - if (ctx->cmdStarted){//transition of img without appropriate dependencies in subpass must be done outside renderpass. - _end_render_pass (ctx); - _flush_vertices_caches (ctx); - } else { - vkh_cmd_begin (ctx->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - ctx->cmdStarted = true; - } - - //transition source surface for sampling - vkh_image_set_layout (ctx->cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - - vkh_cmd_end (ctx->cmd); - _wait_and_submit_cmd (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; - - VkSamplerAddressMode addrMode = 0; - VkFilter filter = VK_FILTER_NEAREST; - switch (pat->extend) { - case VKVG_EXTEND_NONE: - addrMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - break; - case VKVG_EXTEND_PAD: - addrMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - break; - case VKVG_EXTEND_REPEAT: - addrMode = VK_SAMPLER_ADDRESS_MODE_REPEAT; - break; - case VKVG_EXTEND_REFLECT: - addrMode = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; - break; - } - switch (pat->filter) { - case VKVG_FILTER_BILINEAR: - case VKVG_FILTER_BEST: - filter = VK_FILTER_LINEAR; - break; - default: - filter = VK_FILTER_NEAREST; - break; - } - vkh_image_create_sampler (surf->img, filter, filter, - VK_SAMPLER_MIPMAP_MODE_NEAREST, addrMode); - - _update_descriptor_set (ctx, surf->img, ctx->dsSrc); - - if (pat->hasMatrix) { - - } - - ctx->pushConsts.source.width = (float)surf->width; - ctx->pushConsts.source.height = (float)surf->height; - break; - } - case VKVG_PATTERN_TYPE_LINEAR: - case VKVG_PATTERN_TYPE_RADIAL: - _flush_cmd_buff (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; - - if (lastPat && lastPat->type == VKVG_PATTERN_TYPE_SURFACE) - _update_descriptor_set (ctx, ctx->dev->emptyImg, ctx->dsSrc); - - vec4 bounds = {{(float)ctx->pSurf->width}, {(float)ctx->pSurf->height}, {0}, {0}};//store img bounds in unused source field - ctx->pushConsts.source = bounds; - - //transform control point with current ctx matrix - vkvg_gradient_t grad = *(vkvg_gradient_t*)pat->data; - - if (grad.count < 2) { - ctx->status = VKVG_STATUS_PATTERN_INVALID_GRADIENT; - return; - } - vkvg_matrix_t mat; - if (pat->hasMatrix) { - vkvg_pattern_get_matrix (pat, &mat); - if (vkvg_matrix_invert (&mat) != VKVG_STATUS_SUCCESS) - mat = VKVG_IDENTITY_MATRIX; - } - - if (pat->hasMatrix) - vkvg_matrix_transform_point (&mat, &grad.cp[0].x, &grad.cp[0].y); - vkvg_matrix_transform_point (&ctx->pushConsts.mat, &grad.cp[0].x, &grad.cp[0].y); - if (pat->type == VKVG_PATTERN_TYPE_LINEAR) { - if (pat->hasMatrix) - vkvg_matrix_transform_point (&mat, &grad.cp[0].z, &grad.cp[0].w); - vkvg_matrix_transform_point (&ctx->pushConsts.mat, &grad.cp[0].z, &grad.cp[0].w); - } else { - if (pat->hasMatrix) - vkvg_matrix_transform_point (&mat, &grad.cp[1].x, &grad.cp[1].y); - vkvg_matrix_transform_point (&ctx->pushConsts.mat, &grad.cp[1].x, &grad.cp[1].y); - - //radii - if (pat->hasMatrix) { - vkvg_matrix_transform_distance (&mat, &grad.cp[0].z, &grad.cp[0].w); - vkvg_matrix_transform_distance (&mat, &grad.cp[1].z, &grad.cp[0].w); - } - vkvg_matrix_transform_distance (&ctx->pushConsts.mat, &grad.cp[0].z, &grad.cp[0].w); - vkvg_matrix_transform_distance (&ctx->pushConsts.mat, &grad.cp[1].z, &grad.cp[0].w); - } - - memcpy (vkh_buffer_get_mapped_pointer(&ctx->uboGrad) , &grad, sizeof(vkvg_gradient_t)); - vkh_buffer_flush(&ctx->uboGrad); - break; - } - ctx->pushConsts.fsq_patternType = (ctx->pushConsts.fsq_patternType & FULLSCREEN_BIT) + newPatternType; - ctx->pushCstDirty = true; - if (lastPat) - vkvg_pattern_destroy (lastPat); -} -void _update_descriptor_set (VkvgContext ctx, VkhImage img, VkDescriptorSet ds){ - VkDescriptorImageInfo descSrcTex = vkh_image_get_descriptor (img, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - VkWriteDescriptorSet writeDescriptorSet = { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = ds, - .dstBinding = 0, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .pImageInfo = &descSrcTex - }; - vkUpdateDescriptorSets(ctx->dev->vkDev, 1, &writeDescriptorSet, 0, NULL); -} - -void _update_gradient_desc_set (VkvgContext ctx){ - VkDescriptorBufferInfo dbi = {ctx->uboGrad.buffer, 0, VK_WHOLE_SIZE}; - VkWriteDescriptorSet writeDescriptorSet = { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = ctx->dsGrad, - .dstBinding = 0, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .pBufferInfo = &dbi - }; - vkUpdateDescriptorSets(ctx->dev->vkDev, 1, &writeDescriptorSet, 0, NULL); + CmdBeginRenderPass(ctx->cmd, &ctx->renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + VkViewport viewport = {0, 0, (float)ctx->pSurf->width, (float)ctx->pSurf->height, 0, 1.f}; + CmdSetViewport(ctx->cmd, 0, 1, &viewport); + + CmdSetScissor(ctx->cmd, 0, 1, &ctx->bounds); + + VkDescriptorSet dss[] = {ctx->dsFont, ctx->dsSrc, ctx->dsGrad}; + CmdBindDescriptorSets(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineLayout, 0, 3, dss, 0, NULL); + + VkDeviceSize offsets[1] = {0}; + CmdBindVertexBuffers(ctx->cmd, 0, 1, &ctx->vertices.buffer, offsets); + CmdBindIndexBuffer(ctx->cmd, ctx->indices.buffer, 0, VKVG_VK_INDEX_TYPE); + + _update_push_constants(ctx); + + _bind_draw_pipeline(ctx); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + ctx->cmdStarted = true; +} +// compute inverse mat used in shader when context matrix has changed +// then trigger push constants command +void _set_mat_inv_and_vkCmdPush(VkvgContext ctx) { + ctx->pushConsts.matInv = ctx->pushConsts.mat; + vkvg_matrix_invert(&ctx->pushConsts.matInv); + ctx->pushCstDirty = true; +} +void _update_push_constants(VkvgContext ctx) { + CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push_constants), + &ctx->pushConsts); + ctx->pushCstDirty = false; +} +void _update_cur_pattern(VkvgContext ctx, VkvgPattern pat) { + VkvgPattern lastPat = ctx->pattern; + ctx->pattern = pat; + + uint32_t newPatternType = VKVG_PATTERN_TYPE_SOLID; + + LOG(VKVG_LOG_INFO, "CTX: _update_cur_pattern: %p -> %p\n", lastPat, pat); + + if (pat == NULL) { // solid color + if (lastPat == NULL) // solid + return; // solid to solid transition, no extra action requested + } else + newPatternType = pat->type; + + switch (newPatternType) { + case VKVG_PATTERN_TYPE_SOLID: + _flush_cmd_buff(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; + if (lastPat->type == + VKVG_PATTERN_TYPE_SURFACE) // unbind current source surface by replacing it with empty texture + _update_descriptor_set(ctx, ctx->dev->emptyImg, ctx->dsSrc); + break; + case VKVG_PATTERN_TYPE_SURFACE: { + _emit_draw_cmd_undrawn_vertices(ctx); + + VkvgSurface surf = (VkvgSurface)pat->data; + + // flush ctx in two steps to add the src transitioning in the cmd buff + if (ctx->cmdStarted) { // transition of img without appropriate dependencies in subpass must be done outside + // renderpass. + _end_render_pass(ctx); + _flush_vertices_caches(ctx); + } else { + vkh_cmd_begin(ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + ctx->cmdStarted = true; + } + + // transition source surface for sampling + vkh_image_set_layout(ctx->cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + vkh_cmd_end(ctx->cmd); + _wait_and_submit_cmd(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; + + VkSamplerAddressMode addrMode = 0; + VkFilter filter = VK_FILTER_NEAREST; + switch (pat->extend) { + case VKVG_EXTEND_NONE: + addrMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + break; + case VKVG_EXTEND_PAD: + addrMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + break; + case VKVG_EXTEND_REPEAT: + addrMode = VK_SAMPLER_ADDRESS_MODE_REPEAT; + break; + case VKVG_EXTEND_REFLECT: + addrMode = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + break; + } + switch (pat->filter) { + case VKVG_FILTER_BILINEAR: + case VKVG_FILTER_BEST: + filter = VK_FILTER_LINEAR; + break; + default: + filter = VK_FILTER_NEAREST; + break; + } + vkh_image_create_sampler(surf->img, filter, filter, VK_SAMPLER_MIPMAP_MODE_NEAREST, addrMode); + + _update_descriptor_set(ctx, surf->img, ctx->dsSrc); + + if (pat->hasMatrix) { + } + + ctx->pushConsts.source.width = (float)surf->width; + ctx->pushConsts.source.height = (float)surf->height; + break; + } + case VKVG_PATTERN_TYPE_LINEAR: + case VKVG_PATTERN_TYPE_RADIAL: + _flush_cmd_buff(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; + + if (lastPat && lastPat->type == VKVG_PATTERN_TYPE_SURFACE) + _update_descriptor_set(ctx, ctx->dev->emptyImg, ctx->dsSrc); + + vec4 bounds = {{(float)ctx->pSurf->width}, + {(float)ctx->pSurf->height}, + {0}, + {0}}; // store img bounds in unused source field + ctx->pushConsts.source = bounds; + + // transform control point with current ctx matrix + vkvg_gradient_t grad = *(vkvg_gradient_t *)pat->data; + + if (grad.count < 2) { + ctx->status = VKVG_STATUS_PATTERN_INVALID_GRADIENT; + return; + } + vkvg_matrix_t mat; + if (pat->hasMatrix) { + vkvg_pattern_get_matrix(pat, &mat); + if (vkvg_matrix_invert(&mat) != VKVG_STATUS_SUCCESS) + mat = VKVG_IDENTITY_MATRIX; + } + + if (pat->hasMatrix) + vkvg_matrix_transform_point(&mat, &grad.cp[0].x, &grad.cp[0].y); + vkvg_matrix_transform_point(&ctx->pushConsts.mat, &grad.cp[0].x, &grad.cp[0].y); + if (pat->type == VKVG_PATTERN_TYPE_LINEAR) { + if (pat->hasMatrix) + vkvg_matrix_transform_point(&mat, &grad.cp[0].z, &grad.cp[0].w); + vkvg_matrix_transform_point(&ctx->pushConsts.mat, &grad.cp[0].z, &grad.cp[0].w); + } else { + if (pat->hasMatrix) + vkvg_matrix_transform_point(&mat, &grad.cp[1].x, &grad.cp[1].y); + vkvg_matrix_transform_point(&ctx->pushConsts.mat, &grad.cp[1].x, &grad.cp[1].y); + + // radii + if (pat->hasMatrix) { + vkvg_matrix_transform_distance(&mat, &grad.cp[0].z, &grad.cp[0].w); + vkvg_matrix_transform_distance(&mat, &grad.cp[1].z, &grad.cp[0].w); + } + vkvg_matrix_transform_distance(&ctx->pushConsts.mat, &grad.cp[0].z, &grad.cp[0].w); + vkvg_matrix_transform_distance(&ctx->pushConsts.mat, &grad.cp[1].z, &grad.cp[0].w); + } + + memcpy(vkh_buffer_get_mapped_pointer(&ctx->uboGrad), &grad, sizeof(vkvg_gradient_t)); + vkh_buffer_flush(&ctx->uboGrad); + break; + } + ctx->pushConsts.fsq_patternType = (ctx->pushConsts.fsq_patternType & FULLSCREEN_BIT) + newPatternType; + ctx->pushCstDirty = true; + if (lastPat) + vkvg_pattern_destroy(lastPat); +} +void _update_descriptor_set(VkvgContext ctx, VkhImage img, VkDescriptorSet ds) { + VkDescriptorImageInfo descSrcTex = vkh_image_get_descriptor(img, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + VkWriteDescriptorSet writeDescriptorSet = {.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = ds, + .dstBinding = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &descSrcTex}; + vkUpdateDescriptorSets(ctx->dev->vkDev, 1, &writeDescriptorSet, 0, NULL); +} + +void _update_gradient_desc_set(VkvgContext ctx) { + VkDescriptorBufferInfo dbi = {ctx->uboGrad.buffer, 0, VK_WHOLE_SIZE}; + VkWriteDescriptorSet writeDescriptorSet = {.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = ctx->dsGrad, + .dstBinding = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = &dbi}; + vkUpdateDescriptorSets(ctx->dev->vkDev, 1, &writeDescriptorSet, 0, NULL); } /* * Reset currently bound descriptor which image could be destroyed */ /*void _reset_src_descriptor_set (VkvgContext ctx){ - VkvgDevice dev = ctx->pSurf->dev; - //VkDescriptorSet dss[] = {ctx->dsSrc}; - vkFreeDescriptorSets (dev->vkDev, ctx->descriptorPool, 1, &ctx->dsSrc); - - VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .descriptorPool = ctx->descriptorPool, - .descriptorSetCount = 1, - .pSetLayouts = &dev->dslSrc }; - VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsSrc)); + VkvgDevice dev = ctx->pSurf->dev; + //VkDescriptorSet dss[] = {ctx->dsSrc}; + vkFreeDescriptorSets (dev->vkDev, ctx->descriptorPool, 1, &ctx->dsSrc); + + VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = ctx->descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &dev->dslSrc }; + VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsSrc)); }*/ -void _createDescriptorPool (VkvgContext ctx) { - VkvgDevice dev = ctx->dev; - const VkDescriptorPoolSize descriptorPoolSize[] = { - {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2 }, - {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 } - }; - VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .maxSets = 3, - .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, - .poolSizeCount = 2, - .pPoolSizes = descriptorPoolSize }; - VK_CHECK_RESULT(vkCreateDescriptorPool (dev->vkDev, &descriptorPoolCreateInfo, NULL, &ctx->descriptorPool)); -} -void _init_descriptor_sets (VkvgContext ctx){ - VkvgDevice dev = ctx->dev; - VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .descriptorPool = ctx->descriptorPool, - .descriptorSetCount = 1, - .pSetLayouts = &dev->dslFont - }; - VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsFont)); - descriptorSetAllocateInfo.pSetLayouts = &dev->dslSrc; - VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsSrc)); - descriptorSetAllocateInfo.pSetLayouts = &dev->dslGrad; - VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsGrad)); -} -void _release_context_ressources (VkvgContext ctx) { - VkDevice dev = ctx->dev->vkDev; - +void _createDescriptorPool(VkvgContext ctx) { + VkvgDevice dev = ctx->dev; + const VkDescriptorPoolSize descriptorPoolSize[] = {{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2}, + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1}}; + VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .maxSets = 3, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .poolSizeCount = 2, + .pPoolSizes = descriptorPoolSize}; + VK_CHECK_RESULT(vkCreateDescriptorPool(dev->vkDev, &descriptorPoolCreateInfo, NULL, &ctx->descriptorPool)); +} +void _init_descriptor_sets(VkvgContext ctx) { + VkvgDevice dev = ctx->dev; + VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = ctx->descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &dev->dslFont}; + VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsFont)); + descriptorSetAllocateInfo.pSetLayouts = &dev->dslSrc; + VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsSrc)); + descriptorSetAllocateInfo.pSetLayouts = &dev->dslGrad; + VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsGrad)); +} +void _release_context_ressources(VkvgContext ctx) { + VkDevice dev = ctx->dev->vkDev; + #ifndef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - vkDestroyFence (dev, ctx->flushFence, NULL); + vkDestroyFence(dev, ctx->flushFence, NULL); #endif - vkFreeCommandBuffers(dev, ctx->cmdPool, 2, ctx->cmdBuffers); - vkDestroyCommandPool(dev, ctx->cmdPool, NULL); - - VkDescriptorSet dss[] = {ctx->dsFont, ctx->dsSrc, ctx->dsGrad}; - vkFreeDescriptorSets (dev, ctx->descriptorPool, 3, dss); - - vkDestroyDescriptorPool (dev, ctx->descriptorPool,NULL); - - vkh_buffer_reset (&ctx->uboGrad); - vkh_buffer_reset (&ctx->indices); - vkh_buffer_reset (&ctx->vertices); - - free(ctx->vertexCache); - free(ctx->indexCache); - - vkh_image_destroy (ctx->fontCacheImg); - //TODO:check this for source counter - //vkh_image_destroy (ctx->source); - - free(ctx->pathes); - free(ctx->points); - - free(ctx); -} -//populate vertice buff for stroke -bool _build_vb_step(VkvgContext ctx, stroke_context_t* str, bool isCurve){ - Vertex v = {{0},ctx->curColor, {0,0,-1}}; - vec2 p0 = ctx->points[str->cp]; - vec2 v0 = vec2_sub(p0, ctx->points[str->iL]); - vec2 v1 = vec2_sub(ctx->points[str->iR], p0); - float length_v0 = vec2_length(v0); - float length_v1 = vec2_length(v1); - if (length_v0 < FLT_EPSILON || length_v1 < FLT_EPSILON) { - LOG(VKVG_LOG_STROKE, "vb_step discard, lengthhw); - - VKVG_IBO_INDEX_TYPE idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - - v.pos = vec2_add(p0, vPerp); - _add_vertex(ctx, v); - v.pos = vec2_sub(p0, vPerp); - _add_vertex(ctx, v); - - _add_triangle_indices(ctx, idx, idx+1, idx+2); - _add_triangle_indices(ctx, idx, idx+2, idx+3); - LOG(VKVG_LOG_STROKE, "vb_step cusp, dot==-1\n"); - return true; - } - - vec2 bisec_n = vec2_norm(vec2_add(v0n,v1n));//bisec/bisec_perp are inverted names - float alpha = acosf(dot); - - if (det<0) - alpha = -alpha; - - float halfAlpha = alpha / 2.f; - float cosHalfAlpha = cosf(halfAlpha); - float lh = str->hw / cosHalfAlpha; - vec2 bisec_n_perp = vec2_perp(bisec_n); - - //limit bisectrice length - float rlh = lh;//rlh is for inside pos tweeks - if (dot < 0.f) - rlh = fminf (rlh, fminf (length_v0, length_v1)); - //--- - - vec2 bisec = vec2_mult_s (bisec_n_perp, rlh); - - VKVG_IBO_INDEX_TYPE idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - - vec2 rlh_inside_pos, rlh_outside_pos; - if (rlh < lh) { - vec2 vnPerp; - if (length_v0 < length_v1) - vnPerp = vec2_perp (v1n); - else - vnPerp = vec2_perp (v0n); - vec2 vHwPerp = vec2_mult_s (vnPerp, str->hw); - - double lbc = cosHalfAlpha * rlh; - if (det < 0.f) { - rlh_inside_pos = vec2_add (vec2_add (vec2_mult_s(vnPerp, -lbc), vec2_add(p0, bisec)), vHwPerp); - rlh_outside_pos = vec2_sub (p0, vec2_mult_s (bisec_n_perp, lh)); - } else { - rlh_inside_pos = vec2_sub (vec2_add (vec2_mult_s(vnPerp, lbc), vec2_sub(p0, bisec)), vHwPerp); - rlh_outside_pos = vec2_add (p0, vec2_mult_s (bisec_n_perp, lh)); - } - } else { - if (det < 0.0) { - rlh_inside_pos = vec2_add (p0, bisec); - rlh_outside_pos = vec2_sub (p0, bisec); - } else { - rlh_inside_pos = vec2_sub (p0, bisec); - rlh_outside_pos = vec2_add (p0, bisec); - } - } - - vkvg_line_join_t join = ctx->lineJoin; - - if (isCurve) { - if (dot < 0.8f) - join = VKVG_LINE_JOIN_ROUND; - else - join = VKVG_LINE_JOIN_MITER; - } - - if (join == VKVG_LINE_JOIN_MITER){ - if (lh > str->lhMax) {//miter limit - double x = (lh - str->lhMax) * cosHalfAlpha; - vec2 bisecPerp = vec2_mult_s (bisec_n, x); - bisec = vec2_mult_s (bisec_n_perp, str->lhMax); - if (det < 0) { - v.pos = rlh_inside_pos; - _add_vertex(ctx, v); - - vec2 p = vec2_sub(p0, bisec); - - v.pos = vec2_sub(p, bisecPerp); - _add_vertex(ctx, v); - v.pos = vec2_add(p, bisecPerp); - _add_vertex(ctx, v); - - _add_triangle_indices(ctx, idx, idx+2, idx+1); - _add_triangle_indices(ctx, idx+2, idx+4, idx); - _add_triangle_indices(ctx, idx, idx+3, idx+4); - return true; - } else { - vec2 p = vec2_add(p0, bisec); - v.pos = vec2_sub(p, bisecPerp); - _add_vertex(ctx, v); - - v.pos = rlh_inside_pos; - _add_vertex(ctx, v); - - v.pos = vec2_add(p, bisecPerp); - _add_vertex(ctx, v); - - _add_triangle_indices(ctx, idx, idx+2, idx+1); - _add_triangle_indices(ctx, idx+2, idx+3, idx+1); - _add_triangle_indices(ctx, idx+1, idx+3, idx+4); - return false; - } - - } else {//normal miter - if (det < 0) { - v.pos = rlh_inside_pos; - _add_vertex(ctx, v); - v.pos = rlh_outside_pos; - _add_vertex(ctx, v); - } else { - v.pos = rlh_outside_pos; - _add_vertex(ctx, v); - v.pos = rlh_inside_pos; - _add_vertex(ctx, v); - } - - _add_tri_indices_for_rect(ctx, idx); - return false; - } - }else{ - vec2 vp = vec2_perp(v0n); - - if (det<0){ - if (dot < 0 && rlh < lh) - v.pos = rlh_inside_pos; - else - v.pos = vec2_add (p0, bisec); - _add_vertex(ctx, v); - v.pos = vec2_sub (p0, vec2_mult_s (vp, str->hw)); - }else{ - v.pos = vec2_add (p0, vec2_mult_s (vp, str->hw)); - _add_vertex(ctx, v); - if (dot < 0 && rlh < lh) - v.pos = rlh_inside_pos; - else - v.pos = vec2_sub (p0, bisec); - } - _add_vertex(ctx, v); - - if (join == VKVG_LINE_JOIN_BEVEL){ - if (det<0){ - _add_triangle_indices(ctx, idx, idx+2, idx+1); - _add_triangle_indices(ctx, idx+2, idx+4, idx+0); - _add_triangle_indices(ctx, idx, idx+3, idx+4); - }else{ - _add_triangle_indices(ctx, idx, idx+2, idx+1); - _add_triangle_indices(ctx, idx+2, idx+3, idx+1); - _add_triangle_indices(ctx, idx+1, idx+3, idx+4); - } - }else if (join == VKVG_LINE_JOIN_ROUND){ - if (!str->arcStep) - str->arcStep = _get_arc_step (ctx, str->hw); - float a = acosf(vp.x); - if (vp.y < 0) - a = -a; - - if (det<0){ - a+=M_PIF; - float a1 = a + alpha; - a-=str->arcStep; - while (a > a1){ - _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); - a-=str->arcStep; - } - }else{ - float a1 = a + alpha; - a+=str->arcStep; - while (a < a1){ - _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); - a+=str->arcStep; - } - } - VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - _add_triangle_indices(ctx, idx, idx+2, idx+1); - if (det < 0){ - for (VKVG_IBO_INDEX_TYPE p = idx+2; p < p0Idx; p++) - _add_triangle_indices(ctx, p, p+1, idx); - _add_triangle_indices(ctx, p0Idx, p0Idx+2, idx); - _add_triangle_indices(ctx, idx, p0Idx+1, p0Idx+2); - }else{ - for (VKVG_IBO_INDEX_TYPE p = idx+2; p < p0Idx; p++) - _add_triangle_indices(ctx, p, p+1, idx+1); - _add_triangle_indices(ctx, p0Idx, p0Idx+1, idx+1); - _add_triangle_indices(ctx, idx+1, p0Idx+1, p0Idx+2); - } - - } - - vp = vec2_mult_s (vec2_perp(v1n), str->hw); - if (det < 0) - v.pos = vec2_sub (p0, vp); - else - v.pos = vec2_add (p0, vp); - _add_vertex(ctx, v); - } - -/* -#ifdef DEBUG - - debugLinePoints[dlpCount] = p0; - debugLinePoints[dlpCount+1] = _v2add(p0, _vec2dToVec2(_v2Multd(v0n,10))); - dlpCount+=2; - debugLinePoints[dlpCount] = p0; - debugLinePoints[dlpCount+1] = _v2add(p0, _vec2dToVec2(_v2Multd(v1n,10))); - dlpCount+=2; - debugLinePoints[dlpCount] = p0; - debugLinePoints[dlpCount+1] = pR; - dlpCount+=2; -#endif*/ - /*if (reducedLH) - return -det; - else*/ - return (det < 0); -} - -void _draw_stoke_cap (VkvgContext ctx, stroke_context_t *str, vec2 p0, vec2 n, bool isStart) { - Vertex v = {{0},ctx->curColor,{0,0,-1}}; - - VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - - if (isStart){ - vec2 vhw = vec2_mult_s (n, str->hw); - - if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) - p0 = vec2_sub (p0, vhw); - - vhw = vec2_perp (vhw); - - if (ctx->lineCap == VKVG_LINE_CAP_ROUND){ - if (!str->arcStep) - str->arcStep = _get_arc_step (ctx, str->hw); - - float a = acosf(n.x) + M_PIF_2; - if (n.y < 0) - a = M_PIF-a; - float a1 = a + M_PIF; - - a += str->arcStep; - while (a < a1){ - _add_vertexf (ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); - a += str->arcStep; - } - VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - for (VKVG_IBO_INDEX_TYPE p = firstIdx; p < p0Idx; p++) - _add_triangle_indices (ctx, p0Idx+1, p, p+1); - firstIdx = p0Idx; - } - - v.pos = vec2_add (p0, vhw); - _add_vertex (ctx, v); - v.pos = vec2_sub (p0, vhw); - _add_vertex (ctx, v); - - _add_tri_indices_for_rect (ctx, firstIdx); - }else{ - vec2 vhw = vec2_mult_s (n, str->hw); - - if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) - p0 = vec2_add (p0, vhw); - - vhw = vec2_perp (vhw); - - v.pos = vec2_add (p0, vhw); - _add_vertex (ctx, v); - v.pos = vec2_sub (p0, vhw); - _add_vertex (ctx, v); - - firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - - if (ctx->lineCap == VKVG_LINE_CAP_ROUND){ - if (!str->arcStep) - str->arcStep = _get_arc_step (ctx, str->hw); - - float a = acosf(n.x)+ M_PIF_2; - if (n.y < 0) - a = M_PIF-a; - float a1 = a - M_PIF; - - a -= str->arcStep; - while ( a > a1){ - _add_vertexf (ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); - a -= str->arcStep; - } - - VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset - 1); - for (VKVG_IBO_INDEX_TYPE p = firstIdx-1 ; p < p0Idx; p++) - _add_triangle_indices (ctx, p+1, p, firstIdx-2); - } - } -} -float _draw_dashed_segment (VkvgContext ctx, stroke_context_t* str, dash_context_t* dc, bool isCurve) { - //vec2 pL = ctx->points[str->iL]; - vec2 p = ctx->points[str->cp]; - vec2 pR = ctx->points[str->iR]; - - if (!dc->dashOn)//we test in fact the next dash start, if dashOn = true => next segment is a void. - _build_vb_step (ctx, str, isCurve); - - vec2 d = vec2_sub (pR, p); - dc->normal = vec2_norm (d); - float segmentLength = vec2_length(d); - - while (dc->curDashOffset < segmentLength){ - vec2 p0 = vec2_add (p, vec2_mult_s(dc->normal, dc->curDashOffset)); - - _draw_stoke_cap (ctx, str, p0, dc->normal, dc->dashOn); - dc->dashOn ^= true; - dc->curDashOffset += ctx->dashes[dc->curDash]; - if (++dc->curDash == ctx->dashCount) - dc->curDash = 0; - } - dc->curDashOffset -= segmentLength; - dc->curDashOffset = fmodf(dc->curDashOffset, dc->totDashLength); - return segmentLength; -} -void _draw_segment (VkvgContext ctx, stroke_context_t* str, dash_context_t* dc, bool isCurve) { - str->iR = str->cp + 1; - if (ctx->dashCount > 0) - _draw_dashed_segment(ctx, str, dc, isCurve); - else - _build_vb_step (ctx, str, isCurve); - str->iL = str->cp++; - if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) { - Vertex v0 = ctx->vertexCache[ctx->curVertOffset + str->firstIdx]; - Vertex v1 = ctx->vertexCache[ctx->curVertOffset + str->firstIdx + 1]; - _emit_draw_cmd_undrawn_vertices(ctx); - //repeat first 2 vertices for closed pathes - str->firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - _add_vertex(ctx, v0); - _add_vertex(ctx, v1); - ctx->curVertOffset = ctx->vertCount;//prevent redrawing them at the start of the batch - } + vkFreeCommandBuffers(dev, ctx->cmdPool, 2, ctx->cmdBuffers); + vkDestroyCommandPool(dev, ctx->cmdPool, NULL); + + VkDescriptorSet dss[] = {ctx->dsFont, ctx->dsSrc, ctx->dsGrad}; + vkFreeDescriptorSets(dev, ctx->descriptorPool, 3, dss); + + vkDestroyDescriptorPool(dev, ctx->descriptorPool, NULL); + + vkh_buffer_reset(&ctx->uboGrad); + vkh_buffer_reset(&ctx->indices); + vkh_buffer_reset(&ctx->vertices); + + free(ctx->vertexCache); + free(ctx->indexCache); + + vkh_image_destroy(ctx->fontCacheImg); + // TODO:check this for source counter + // vkh_image_destroy (ctx->source); + + free(ctx->pathes); + free(ctx->points); + + free(ctx); +} +// populate vertice buff for stroke +bool _build_vb_step(VkvgContext ctx, stroke_context_t *str, bool isCurve) { + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; + vec2 p0 = ctx->points[str->cp]; + vec2 v0 = vec2_sub(p0, ctx->points[str->iL]); + vec2 v1 = vec2_sub(ctx->points[str->iR], p0); + float length_v0 = vec2_length(v0); + float length_v1 = vec2_length(v1); + if (length_v0 < FLT_EPSILON || length_v1 < FLT_EPSILON) { + LOG(VKVG_LOG_STROKE, "vb_step discard, lengthhw); + + VKVG_IBO_INDEX_TYPE idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + + v.pos = vec2_add(p0, vPerp); + _add_vertex(ctx, v); + v.pos = vec2_sub(p0, vPerp); + _add_vertex(ctx, v); + + _add_triangle_indices(ctx, idx, idx + 1, idx + 2); + _add_triangle_indices(ctx, idx, idx + 2, idx + 3); + LOG(VKVG_LOG_STROKE, "vb_step cusp, dot==-1\n"); + return true; + } + + vec2 bisec_n = vec2_norm(vec2_add(v0n, v1n)); // bisec/bisec_perp are inverted names + float alpha = acosf(dot); + + if (det < 0) + alpha = -alpha; + + float halfAlpha = alpha / 2.f; + float cosHalfAlpha = cosf(halfAlpha); + float lh = str->hw / cosHalfAlpha; + vec2 bisec_n_perp = vec2_perp(bisec_n); + + // limit bisectrice length + float rlh = lh; // rlh is for inside pos tweeks + if (dot < 0.f) + rlh = fminf(rlh, fminf(length_v0, length_v1)); + //--- + + vec2 bisec = vec2_mult_s(bisec_n_perp, rlh); + + VKVG_IBO_INDEX_TYPE idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + + vec2 rlh_inside_pos, rlh_outside_pos; + if (rlh < lh) { + vec2 vnPerp; + if (length_v0 < length_v1) + vnPerp = vec2_perp(v1n); + else + vnPerp = vec2_perp(v0n); + vec2 vHwPerp = vec2_mult_s(vnPerp, str->hw); + + double lbc = cosHalfAlpha * rlh; + if (det < 0.f) { + rlh_inside_pos = vec2_add(vec2_add(vec2_mult_s(vnPerp, -lbc), vec2_add(p0, bisec)), vHwPerp); + rlh_outside_pos = vec2_sub(p0, vec2_mult_s(bisec_n_perp, lh)); + } else { + rlh_inside_pos = vec2_sub(vec2_add(vec2_mult_s(vnPerp, lbc), vec2_sub(p0, bisec)), vHwPerp); + rlh_outside_pos = vec2_add(p0, vec2_mult_s(bisec_n_perp, lh)); + } + } else { + if (det < 0.0) { + rlh_inside_pos = vec2_add(p0, bisec); + rlh_outside_pos = vec2_sub(p0, bisec); + } else { + rlh_inside_pos = vec2_sub(p0, bisec); + rlh_outside_pos = vec2_add(p0, bisec); + } + } + + vkvg_line_join_t join = ctx->lineJoin; + + if (isCurve) { + if (dot < 0.8f) + join = VKVG_LINE_JOIN_ROUND; + else + join = VKVG_LINE_JOIN_MITER; + } + + if (join == VKVG_LINE_JOIN_MITER) { + if (lh > str->lhMax) { // miter limit + double x = (lh - str->lhMax) * cosHalfAlpha; + vec2 bisecPerp = vec2_mult_s(bisec_n, x); + bisec = vec2_mult_s(bisec_n_perp, str->lhMax); + if (det < 0) { + v.pos = rlh_inside_pos; + _add_vertex(ctx, v); + + vec2 p = vec2_sub(p0, bisec); + + v.pos = vec2_sub(p, bisecPerp); + _add_vertex(ctx, v); + v.pos = vec2_add(p, bisecPerp); + _add_vertex(ctx, v); + + _add_triangle_indices(ctx, idx, idx + 2, idx + 1); + _add_triangle_indices(ctx, idx + 2, idx + 4, idx); + _add_triangle_indices(ctx, idx, idx + 3, idx + 4); + return true; + } else { + vec2 p = vec2_add(p0, bisec); + v.pos = vec2_sub(p, bisecPerp); + _add_vertex(ctx, v); + + v.pos = rlh_inside_pos; + _add_vertex(ctx, v); + + v.pos = vec2_add(p, bisecPerp); + _add_vertex(ctx, v); + + _add_triangle_indices(ctx, idx, idx + 2, idx + 1); + _add_triangle_indices(ctx, idx + 2, idx + 3, idx + 1); + _add_triangle_indices(ctx, idx + 1, idx + 3, idx + 4); + return false; + } + + } else { // normal miter + if (det < 0) { + v.pos = rlh_inside_pos; + _add_vertex(ctx, v); + v.pos = rlh_outside_pos; + _add_vertex(ctx, v); + } else { + v.pos = rlh_outside_pos; + _add_vertex(ctx, v); + v.pos = rlh_inside_pos; + _add_vertex(ctx, v); + } + + _add_tri_indices_for_rect(ctx, idx); + return false; + } + } else { + vec2 vp = vec2_perp(v0n); + + if (det < 0) { + if (dot < 0 && rlh < lh) + v.pos = rlh_inside_pos; + else + v.pos = vec2_add(p0, bisec); + _add_vertex(ctx, v); + v.pos = vec2_sub(p0, vec2_mult_s(vp, str->hw)); + } else { + v.pos = vec2_add(p0, vec2_mult_s(vp, str->hw)); + _add_vertex(ctx, v); + if (dot < 0 && rlh < lh) + v.pos = rlh_inside_pos; + else + v.pos = vec2_sub(p0, bisec); + } + _add_vertex(ctx, v); + + if (join == VKVG_LINE_JOIN_BEVEL) { + if (det < 0) { + _add_triangle_indices(ctx, idx, idx + 2, idx + 1); + _add_triangle_indices(ctx, idx + 2, idx + 4, idx + 0); + _add_triangle_indices(ctx, idx, idx + 3, idx + 4); + } else { + _add_triangle_indices(ctx, idx, idx + 2, idx + 1); + _add_triangle_indices(ctx, idx + 2, idx + 3, idx + 1); + _add_triangle_indices(ctx, idx + 1, idx + 3, idx + 4); + } + } else if (join == VKVG_LINE_JOIN_ROUND) { + if (!str->arcStep) + str->arcStep = _get_arc_step(ctx, str->hw); + float a = acosf(vp.x); + if (vp.y < 0) + a = -a; + + if (det < 0) { + a += M_PIF; + float a1 = a + alpha; + a -= str->arcStep; + while (a > a1) { + _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); + a -= str->arcStep; + } + } else { + float a1 = a + alpha; + a += str->arcStep; + while (a < a1) { + _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); + a += str->arcStep; + } + } + VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + _add_triangle_indices(ctx, idx, idx + 2, idx + 1); + if (det < 0) { + for (VKVG_IBO_INDEX_TYPE p = idx + 2; p < p0Idx; p++) + _add_triangle_indices(ctx, p, p + 1, idx); + _add_triangle_indices(ctx, p0Idx, p0Idx + 2, idx); + _add_triangle_indices(ctx, idx, p0Idx + 1, p0Idx + 2); + } else { + for (VKVG_IBO_INDEX_TYPE p = idx + 2; p < p0Idx; p++) + _add_triangle_indices(ctx, p, p + 1, idx + 1); + _add_triangle_indices(ctx, p0Idx, p0Idx + 1, idx + 1); + _add_triangle_indices(ctx, idx + 1, p0Idx + 1, p0Idx + 2); + } + } + + vp = vec2_mult_s(vec2_perp(v1n), str->hw); + if (det < 0) + v.pos = vec2_sub(p0, vp); + else + v.pos = vec2_add(p0, vp); + _add_vertex(ctx, v); + } + + /* + #ifdef DEBUG + + debugLinePoints[dlpCount] = p0; + debugLinePoints[dlpCount+1] = _v2add(p0, _vec2dToVec2(_v2Multd(v0n,10))); + dlpCount+=2; + debugLinePoints[dlpCount] = p0; + debugLinePoints[dlpCount+1] = _v2add(p0, _vec2dToVec2(_v2Multd(v1n,10))); + dlpCount+=2; + debugLinePoints[dlpCount] = p0; + debugLinePoints[dlpCount+1] = pR; + dlpCount+=2; + #endif*/ + /*if (reducedLH) + return -det; + else*/ + return (det < 0); +} + +void _draw_stoke_cap(VkvgContext ctx, stroke_context_t *str, vec2 p0, vec2 n, bool isStart) { + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; + + VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + + if (isStart) { + vec2 vhw = vec2_mult_s(n, str->hw); + + if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) + p0 = vec2_sub(p0, vhw); + + vhw = vec2_perp(vhw); + + if (ctx->lineCap == VKVG_LINE_CAP_ROUND) { + if (!str->arcStep) + str->arcStep = _get_arc_step(ctx, str->hw); + + float a = acosf(n.x) + M_PIF_2; + if (n.y < 0) + a = M_PIF - a; + float a1 = a + M_PIF; + + a += str->arcStep; + while (a < a1) { + _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); + a += str->arcStep; + } + VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + for (VKVG_IBO_INDEX_TYPE p = firstIdx; p < p0Idx; p++) + _add_triangle_indices(ctx, p0Idx + 1, p, p + 1); + firstIdx = p0Idx; + } + + v.pos = vec2_add(p0, vhw); + _add_vertex(ctx, v); + v.pos = vec2_sub(p0, vhw); + _add_vertex(ctx, v); + + _add_tri_indices_for_rect(ctx, firstIdx); + } else { + vec2 vhw = vec2_mult_s(n, str->hw); + + if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) + p0 = vec2_add(p0, vhw); + + vhw = vec2_perp(vhw); + + v.pos = vec2_add(p0, vhw); + _add_vertex(ctx, v); + v.pos = vec2_sub(p0, vhw); + _add_vertex(ctx, v); + + firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + + if (ctx->lineCap == VKVG_LINE_CAP_ROUND) { + if (!str->arcStep) + str->arcStep = _get_arc_step(ctx, str->hw); + + float a = acosf(n.x) + M_PIF_2; + if (n.y < 0) + a = M_PIF - a; + float a1 = a - M_PIF; + + a -= str->arcStep; + while (a > a1) { + _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); + a -= str->arcStep; + } + + VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset - 1); + for (VKVG_IBO_INDEX_TYPE p = firstIdx - 1; p < p0Idx; p++) + _add_triangle_indices(ctx, p + 1, p, firstIdx - 2); + } + } +} +float _draw_dashed_segment(VkvgContext ctx, stroke_context_t *str, dash_context_t *dc, bool isCurve) { + // vec2 pL = ctx->points[str->iL]; + vec2 p = ctx->points[str->cp]; + vec2 pR = ctx->points[str->iR]; + + if (!dc->dashOn) // we test in fact the next dash start, if dashOn = true => next segment is a void. + _build_vb_step(ctx, str, isCurve); + + vec2 d = vec2_sub(pR, p); + dc->normal = vec2_norm(d); + float segmentLength = vec2_length(d); + + while (dc->curDashOffset < segmentLength) { + vec2 p0 = vec2_add(p, vec2_mult_s(dc->normal, dc->curDashOffset)); + + _draw_stoke_cap(ctx, str, p0, dc->normal, dc->dashOn); + dc->dashOn ^= true; + dc->curDashOffset += ctx->dashes[dc->curDash]; + if (++dc->curDash == ctx->dashCount) + dc->curDash = 0; + } + dc->curDashOffset -= segmentLength; + dc->curDashOffset = fmodf(dc->curDashOffset, dc->totDashLength); + return segmentLength; +} +void _draw_segment(VkvgContext ctx, stroke_context_t *str, dash_context_t *dc, bool isCurve) { + str->iR = str->cp + 1; + if (ctx->dashCount > 0) + _draw_dashed_segment(ctx, str, dc, isCurve); + else + _build_vb_step(ctx, str, isCurve); + str->iL = str->cp++; + if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) { + Vertex v0 = ctx->vertexCache[ctx->curVertOffset + str->firstIdx]; + Vertex v1 = ctx->vertexCache[ctx->curVertOffset + str->firstIdx + 1]; + _emit_draw_cmd_undrawn_vertices(ctx); + // repeat first 2 vertices for closed pathes + str->firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + _add_vertex(ctx, v0); + _add_vertex(ctx, v1); + ctx->curVertOffset = ctx->vertCount; // prevent redrawing them at the start of the batch + } } bool ptInTriangle(vec2 p, vec2 p0, vec2 p1, vec2 p2) { - float dX = p.x-p2.x; - float dY = p.y-p2.y; - float dX21 = p2.x-p1.x; - float dY12 = p1.y-p2.y; - float D = dY12*(p0.x-p2.x) + dX21*(p0.y-p2.y); - float s = dY12*dX + dX21*dY; - float t = (p2.y-p0.y)*dX + (p0.x-p2.x)*dY; - if (D<0) - return (s<=0) && (t<=0) && (s+t>=D); - return (s>=0) && (t>=0) && (s+t<=D); -} - -void _free_ctx_save (vkvg_context_save_t* sav){ - if (sav->dashCount > 0) - free (sav->dashes); - if (sav->pattern) - vkvg_pattern_destroy(sav->pattern); - free (sav); -} - - -#define M_APPROXIMATION_SCALE 1.0 -#define M_ANGLE_TOLERANCE 0.01 -#define M_CUSP_LIMIT 0.01 -#define CURVE_RECURSION_LIMIT 100 -#define CURVE_COLLINEARITY_EPSILON 1.7 + float dX = p.x - p2.x; + float dY = p.y - p2.y; + float dX21 = p2.x - p1.x; + float dY12 = p1.y - p2.y; + float D = dY12 * (p0.x - p2.x) + dX21 * (p0.y - p2.y); + float s = dY12 * dX + dX21 * dY; + float t = (p2.y - p0.y) * dX + (p0.x - p2.x) * dY; + if (D < 0) + return (s <= 0) && (t <= 0) && (s + t >= D); + return (s >= 0) && (t >= 0) && (s + t <= D); +} + +void _free_ctx_save(vkvg_context_save_t *sav) { + if (sav->dashCount > 0) + free(sav->dashes); + if (sav->pattern) + vkvg_pattern_destroy(sav->pattern); + free(sav); +} + +#define M_APPROXIMATION_SCALE 1.0 +#define M_ANGLE_TOLERANCE 0.01 +#define M_CUSP_LIMIT 0.01 +#define CURVE_RECURSION_LIMIT 100 +#define CURVE_COLLINEARITY_EPSILON 1.7 #define CURVE_ANGLE_TOLERANCE_EPSILON 0.001 -//no floating point arithmetic operation allowed in macro. -#pragma warning(disable:4127) -void _recursive_bezier (VkvgContext ctx, float distanceTolerance, - float x1, float y1, float x2, float y2, - float x3, float y3, float x4, float y4, - unsigned level) { - if(level > CURVE_RECURSION_LIMIT) - { - return; - } - - // Calculate all the mid-points of the line segments - //---------------------- - float x12 = (x1 + x2) / 2; - float y12 = (y1 + y2) / 2; - float x23 = (x2 + x3) / 2; - float y23 = (y2 + y3) / 2; - float x34 = (x3 + x4) / 2; - float y34 = (y3 + y4) / 2; - float x123 = (x12 + x23) / 2; - float y123 = (y12 + y23) / 2; - float x234 = (x23 + x34) / 2; - float y234 = (y23 + y34) / 2; - float x1234 = (x123 + x234) / 2; - float y1234 = (y123 + y234) / 2; - - if(level > 0) // Enforce subdivision first time - { - // Try to approximate the full cubic curve by a single straight line - //------------------ - float dx = x4-x1; - float dy = y4-y1; - - float d2 = fabsf(((x2 - x4) * dy - (y2 - y4) * dx)); - float d3 = fabsf(((x3 - x4) * dy - (y3 - y4) * dx)); - - float da1, da2; - - if(d2 > CURVE_COLLINEARITY_EPSILON && d3 > CURVE_COLLINEARITY_EPSILON) - { - // Regular care - //----------------- - if((d2 + d3)*(d2 + d3) <= (dx*dx + dy*dy) * distanceTolerance) - { - // If the curvature doesn't exceed the distance_tolerance value - // we tend to finish subdivisions. - //---------------------- - if (M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) { - _add_point(ctx, x1234, y1234); - return; - } - - // Angle & Cusp Condition - //---------------------- - float a23 = atan2f(y3 - y2, x3 - x2); - da1 = fabsf(a23 - atan2f(y2 - y1, x2 - x1)); - da2 = fabsf(atan2f(y4 - y3, x4 - x3) - a23); - if(da1 >= M_PIF) da1 = M_2_PIF - da1; - if(da2 >= M_PIF) da2 = M_2_PIF - da2; - - if(da1 + da2 < (float)M_ANGLE_TOLERANCE) - { - // Finally we can stop the recursion - //---------------------- - _add_point (ctx, x1234, y1234); - return; - } - - if(M_CUSP_LIMIT != 0.0) - { - if(da1 > M_CUSP_LIMIT) - { - _add_point (ctx, x2, y2); - return; - } - - if(da2 > M_CUSP_LIMIT) - { - _add_point (ctx, x3, y3); - return; - } - } - } - } else { - if(d2 > CURVE_COLLINEARITY_EPSILON) - { - // p1,p3,p4 are collinear, p2 is considerable - //---------------------- - if(d2 * d2 <= distanceTolerance * (dx*dx + dy*dy)) - { - if(M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) - { - _add_point (ctx, x1234, y1234); - return; - } - - // Angle Condition - //---------------------- - da1 = fabsf(atan2f(y3 - y2, x3 - x2) - atan2f(y2 - y1, x2 - x1)); - if(da1 >= M_PIF) da1 = M_2_PIF - da1; - - if(da1 < M_ANGLE_TOLERANCE) - { - _add_point (ctx, x2, y2); - _add_point (ctx, x3, y3); - return; - } - - if(M_CUSP_LIMIT != 0.0) - { - if(da1 > M_CUSP_LIMIT) - { - _add_point (ctx, x2, y2); - return; - } - } - } - } else if(d3 > CURVE_COLLINEARITY_EPSILON) { - // p1,p2,p4 are collinear, p3 is considerable - //---------------------- - if(d3 * d3 <= distanceTolerance* (dx*dx + dy*dy)) - { - if(M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) - { - _add_point (ctx, x1234, y1234); - return; - } - - // Angle Condition - //---------------------- - da1 = fabsf(atan2f(y4 - y3, x4 - x3) - atan2f(y3 - y2, x3 - x2)); - if(da1 >= M_PIF) da1 = M_2_PIF - da1; - - if(da1 < M_ANGLE_TOLERANCE) - { - _add_point (ctx, x2, y2); - _add_point (ctx, x3, y3); - return; - } - - if(M_CUSP_LIMIT != 0.0) - { - if(da1 > M_CUSP_LIMIT) - { - _add_point (ctx, x3, y3); - return; - } - } - } - } - else - { - // Collinear case - //----------------- - dx = x1234 - (x1 + x4) / 2; - dy = y1234 - (y1 + y4) / 2; - if(dx*dx + dy*dy <= distanceTolerance) - { - _add_point (ctx, x1234, y1234); - return; - } - } - } - } - - // Continue subdivision - //---------------------- - _recursive_bezier (ctx, distanceTolerance, x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1); - _recursive_bezier (ctx, distanceTolerance,x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1); -} -#pragma warning(default:4127) -void _line_to (VkvgContext ctx, float x, float y) { - vec2 p = {x,y}; - if (!_current_path_is_empty (ctx)){ - //prevent adding the same point - if (vec2_equ (_get_current_position (ctx), p)) - return; - } - _add_point (ctx, x, y); - ctx->simpleConvex = false; -} -void _elliptic_arc (VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, float _rx, float _ry, float phi) { - if (ctx->status) - return; - - if (_rx==0||_ry==0) { - if (_current_path_is_empty(ctx)) - vkvg_move_to(ctx, x1, y1); - vkvg_line_to(ctx, x2, y2); - return; - } - float rx = fabsf(_rx); - float ry = fabsf(_ry); - - mat2 m = { - { cosf (phi), sinf (phi)}, - {-sinf (phi), cosf (phi)} - }; - vec2 p = {(x1 - x2)/2, (y1 - y2)/2}; - vec2 p1 = mat2_mult_vec2 (m, p); - - //radii corrections - double lambda = powf (p1.x, 2) / powf (rx, 2) + powf (p1.y, 2) / powf (ry, 2); - if (lambda > 1) { - lambda = sqrtf (lambda); - rx *= lambda; - ry *= lambda; - } - - p = (vec2){rx * p1.y / ry, -ry * p1.x / rx}; - - vec2 cp = vec2_mult_s (p, sqrtf (fabsf ( - (powf (rx,2) * powf (ry,2) - powf (rx,2) * powf (p1.y, 2) - powf (ry,2) * powf (p1.x, 2)) / - (powf (rx,2) * powf (p1.y, 2) + powf (ry,2) * powf (p1.x, 2)) - ))); - - if (largeArc == counterClockWise) - vec2_inv(&cp); - - m = (mat2) { - {cosf (phi),-sinf (phi)}, - {sinf (phi), cosf (phi)} - }; - p = (vec2){(x1 + x2)/2, (y1 + y2)/2}; - vec2 c = vec2_add (mat2_mult_vec2(m, cp) , p); - - vec2 u = vec2_unit_x; - vec2 v = {(p1.x-cp.x)/rx, (p1.y-cp.y)/ry}; - double sa = acosf (vec2_dot (u, v) / (fabsf(vec2_length(v)) * fabsf(vec2_length(u)))); - if (isnan(sa)) - sa=M_PIF; - if (u.x*v.y-u.y*v.x < 0) - sa = -sa; - - u = v; - v = (vec2) {(-p1.x-cp.x)/rx, (-p1.y-cp.y)/ry}; - double delta_theta = acosf (vec2_dot (u, v) / (fabsf(vec2_length (v)) * fabsf(vec2_length (u)))); - if (isnan(delta_theta)) - delta_theta=M_PIF; - if (u.x*v.y-u.y*v.x < 0) - delta_theta = -delta_theta; - - if (counterClockWise) { - if (delta_theta < 0) - delta_theta += M_PIF * 2.0; - } else if (delta_theta > 0) - delta_theta -= M_PIF * 2.0; - - m = (mat2) { - {cosf (phi),-sinf (phi)}, - {sinf (phi), cosf (phi)} - }; - - double theta = sa; - double ea = sa + delta_theta; - - float step = fmaxf(0.001f, fminf(M_PIF, _get_arc_step(ctx, fminf (rx, ry))*0.1f)); - - p = (vec2) { - rx * cosf (theta), - ry * sinf (theta) - }; - vec2 xy = vec2_add (mat2_mult_vec2 (m, p), c); - - if (_current_path_is_empty(ctx)){ - _set_curve_start (ctx); - _add_point (ctx, xy.x, xy.y); - if (!ctx->pathPtr) - ctx->simpleConvex = true; - else - ctx->simpleConvex = false; - }else{ - _line_to(ctx, xy.x, xy.y); - _set_curve_start (ctx); - ctx->simpleConvex = false; - } - - _set_curve_start (ctx); - - if (sa < ea) { - theta += step; - while (theta < ea) { - p = (vec2) { - rx * cosf (theta), - ry * sinf (theta) - }; - xy = vec2_add (mat2_mult_vec2 (m, p), c); - _add_point (ctx, xy.x, xy.y); - theta += step; - } - } else { - theta -= step; - while (theta > ea) { - p = (vec2) { - rx * cosf (theta), - ry * sinf (theta) - }; - xy = vec2_add (mat2_mult_vec2 (m, p), c); - _add_point (ctx, xy.x, xy.y); - theta -= step; - } - } - p = (vec2) { - rx * cosf (ea), - ry * sinf (ea) - }; - xy = vec2_add (mat2_mult_vec2 (m, p), c); - _add_point (ctx, xy.x, xy.y); - _set_curve_end(ctx); -} - - -//Even-Odd inside test with stencil buffer implementation. -void _poly_fill (VkvgContext ctx, vec4* bounds){ - //we anticipate the check for vbo buffer size, ibo is not used in poly_fill - //the polyfill emit a single vertex for each point in the path. - if (ctx->sizeVBO - VKVG_ARRAY_THRESHOLD < ctx->vertCount + ctx->pointCount) { - if (ctx->cmdStarted) { - _end_render_pass (ctx); - if (ctx->vertCount > 0) - _flush_vertices_caches (ctx); - vkh_cmd_end (ctx->cmd); - _wait_and_submit_cmd (ctx); - _wait_ctx_flush_end (ctx); - if (ctx->sizeVBO - VKVG_ARRAY_THRESHOLD < ctx->pointCount){ - _resize_vbo (ctx, ctx->pointCount + VKVG_ARRAY_THRESHOLD); - _resize_vertex_cache (ctx, ctx->sizeVBO); - } - }else{ - _resize_vbo (ctx, ctx->vertCount + ctx->pointCount + VKVG_ARRAY_THRESHOLD); - _resize_vertex_cache (ctx, ctx->sizeVBO); - } - - _start_cmd_for_render_pass(ctx); - } else { - _ensure_vertex_cache_size (ctx, ctx->pointCount); - _ensure_renderpass_is_started (ctx); - } - - CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelinePolyFill); - - Vertex v = {{0}, ctx->curColor, {0,0,-1}}; - uint32_t ptrPath = 0; - uint32_t firstPtIdx = 0; - - while (ptrPath < ctx->pathPtr){ - uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; - if (pathPointCount > 2) { - VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)ctx->vertCount; - - for (uint32_t i = 0; i < pathPointCount; i++) { - v.pos = ctx->points [i+firstPtIdx]; - ctx->vertexCache[ctx->vertCount++] = v; - if (!bounds) - continue; - //bounds are computed here to scissor the painting operation - //that speed up fill drastically. - vkvg_matrix_transform_point (&ctx->pushConsts.mat, &v.pos.x, &v.pos.y); - - if (v.pos.x < bounds->xMin) - bounds->xMin = v.pos.x; - if (v.pos.x > bounds->xMax) - bounds->xMax = v.pos.x; - if (v.pos.y < bounds->yMin) - bounds->yMin = v.pos.y; - if (v.pos.y > bounds->yMax) - bounds->yMax = v.pos.y; - } - - LOG(VKVG_LOG_INFO_PATH, "\tpoly fill: point count = %d; 1st vert = %d; vert count = %d\n", pathPointCount, firstVertIdx, ctx->vertCount - firstVertIdx); - CmdDraw (ctx->cmd, pathPointCount, 1, firstVertIdx , 0); - } - firstPtIdx += pathPointCount; - - if (_path_has_curves (ctx, ptrPath)) { - //skip segments lengths used in stroke - ptrPath++; - uint32_t totPts = 0; - while (totPts < pathPointCount) - totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); - }else - ptrPath++; - } - ctx->curVertOffset = ctx->vertCount; +// no floating point arithmetic operation allowed in macro. +#pragma warning(disable : 4127) +void _recursive_bezier(VkvgContext ctx, float distanceTolerance, float x1, float y1, float x2, float y2, float x3, + float y3, float x4, float y4, unsigned level) { + if (level > CURVE_RECURSION_LIMIT) { + return; + } + + // Calculate all the mid-points of the line segments + //---------------------- + float x12 = (x1 + x2) / 2; + float y12 = (y1 + y2) / 2; + float x23 = (x2 + x3) / 2; + float y23 = (y2 + y3) / 2; + float x34 = (x3 + x4) / 2; + float y34 = (y3 + y4) / 2; + float x123 = (x12 + x23) / 2; + float y123 = (y12 + y23) / 2; + float x234 = (x23 + x34) / 2; + float y234 = (y23 + y34) / 2; + float x1234 = (x123 + x234) / 2; + float y1234 = (y123 + y234) / 2; + + if (level > 0) // Enforce subdivision first time + { + // Try to approximate the full cubic curve by a single straight line + //------------------ + float dx = x4 - x1; + float dy = y4 - y1; + + float d2 = fabsf(((x2 - x4) * dy - (y2 - y4) * dx)); + float d3 = fabsf(((x3 - x4) * dy - (y3 - y4) * dx)); + + float da1, da2; + + if (d2 > CURVE_COLLINEARITY_EPSILON && d3 > CURVE_COLLINEARITY_EPSILON) { + // Regular care + //----------------- + if ((d2 + d3) * (d2 + d3) <= (dx * dx + dy * dy) * distanceTolerance) { + // If the curvature doesn't exceed the distance_tolerance value + // we tend to finish subdivisions. + //---------------------- + if (M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) { + _add_point(ctx, x1234, y1234); + return; + } + + // Angle & Cusp Condition + //---------------------- + float a23 = atan2f(y3 - y2, x3 - x2); + da1 = fabsf(a23 - atan2f(y2 - y1, x2 - x1)); + da2 = fabsf(atan2f(y4 - y3, x4 - x3) - a23); + if (da1 >= M_PIF) + da1 = M_2_PIF - da1; + if (da2 >= M_PIF) + da2 = M_2_PIF - da2; + + if (da1 + da2 < (float)M_ANGLE_TOLERANCE) { + // Finally we can stop the recursion + //---------------------- + _add_point(ctx, x1234, y1234); + return; + } + + if (M_CUSP_LIMIT != 0.0) { + if (da1 > M_CUSP_LIMIT) { + _add_point(ctx, x2, y2); + return; + } + + if (da2 > M_CUSP_LIMIT) { + _add_point(ctx, x3, y3); + return; + } + } + } + } else { + if (d2 > CURVE_COLLINEARITY_EPSILON) { + // p1,p3,p4 are collinear, p2 is considerable + //---------------------- + if (d2 * d2 <= distanceTolerance * (dx * dx + dy * dy)) { + if (M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) { + _add_point(ctx, x1234, y1234); + return; + } + + // Angle Condition + //---------------------- + da1 = fabsf(atan2f(y3 - y2, x3 - x2) - atan2f(y2 - y1, x2 - x1)); + if (da1 >= M_PIF) + da1 = M_2_PIF - da1; + + if (da1 < M_ANGLE_TOLERANCE) { + _add_point(ctx, x2, y2); + _add_point(ctx, x3, y3); + return; + } + + if (M_CUSP_LIMIT != 0.0) { + if (da1 > M_CUSP_LIMIT) { + _add_point(ctx, x2, y2); + return; + } + } + } + } else if (d3 > CURVE_COLLINEARITY_EPSILON) { + // p1,p2,p4 are collinear, p3 is considerable + //---------------------- + if (d3 * d3 <= distanceTolerance * (dx * dx + dy * dy)) { + if (M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) { + _add_point(ctx, x1234, y1234); + return; + } + + // Angle Condition + //---------------------- + da1 = fabsf(atan2f(y4 - y3, x4 - x3) - atan2f(y3 - y2, x3 - x2)); + if (da1 >= M_PIF) + da1 = M_2_PIF - da1; + + if (da1 < M_ANGLE_TOLERANCE) { + _add_point(ctx, x2, y2); + _add_point(ctx, x3, y3); + return; + } + + if (M_CUSP_LIMIT != 0.0) { + if (da1 > M_CUSP_LIMIT) { + _add_point(ctx, x3, y3); + return; + } + } + } + } else { + // Collinear case + //----------------- + dx = x1234 - (x1 + x4) / 2; + dy = y1234 - (y1 + y4) / 2; + if (dx * dx + dy * dy <= distanceTolerance) { + _add_point(ctx, x1234, y1234); + return; + } + } + } + } + + // Continue subdivision + //---------------------- + _recursive_bezier(ctx, distanceTolerance, x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1); + _recursive_bezier(ctx, distanceTolerance, x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1); +} +#pragma warning(default : 4127) +void _line_to(VkvgContext ctx, float x, float y) { + vec2 p = {x, y}; + if (!_current_path_is_empty(ctx)) { + // prevent adding the same point + if (vec2_equ(_get_current_position(ctx), p)) + return; + } + _add_point(ctx, x, y); + ctx->simpleConvex = false; +} +void _elliptic_arc(VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, + float _rx, float _ry, float phi) { + if (ctx->status) + return; + + if (_rx == 0 || _ry == 0) { + if (_current_path_is_empty(ctx)) + vkvg_move_to(ctx, x1, y1); + vkvg_line_to(ctx, x2, y2); + return; + } + float rx = fabsf(_rx); + float ry = fabsf(_ry); + + mat2 m = {{cosf(phi), sinf(phi)}, {-sinf(phi), cosf(phi)}}; + vec2 p = {(x1 - x2) / 2, (y1 - y2) / 2}; + vec2 p1 = mat2_mult_vec2(m, p); + + // radii corrections + double lambda = powf(p1.x, 2) / powf(rx, 2) + powf(p1.y, 2) / powf(ry, 2); + if (lambda > 1) { + lambda = sqrtf(lambda); + rx *= lambda; + ry *= lambda; + } + + p = (vec2){rx * p1.y / ry, -ry * p1.x / rx}; + + vec2 cp = vec2_mult_s( + p, sqrtf(fabsf((powf(rx, 2) * powf(ry, 2) - powf(rx, 2) * powf(p1.y, 2) - powf(ry, 2) * powf(p1.x, 2)) / + (powf(rx, 2) * powf(p1.y, 2) + powf(ry, 2) * powf(p1.x, 2))))); + + if (largeArc == counterClockWise) + vec2_inv(&cp); + + m = (mat2){{cosf(phi), -sinf(phi)}, {sinf(phi), cosf(phi)}}; + p = (vec2){(x1 + x2) / 2, (y1 + y2) / 2}; + vec2 c = vec2_add(mat2_mult_vec2(m, cp), p); + + vec2 u = vec2_unit_x; + vec2 v = {(p1.x - cp.x) / rx, (p1.y - cp.y) / ry}; + double sa = acosf(vec2_dot(u, v) / (fabsf(vec2_length(v)) * fabsf(vec2_length(u)))); + if (isnan(sa)) + sa = M_PIF; + if (u.x * v.y - u.y * v.x < 0) + sa = -sa; + + u = v; + v = (vec2){(-p1.x - cp.x) / rx, (-p1.y - cp.y) / ry}; + double delta_theta = acosf(vec2_dot(u, v) / (fabsf(vec2_length(v)) * fabsf(vec2_length(u)))); + if (isnan(delta_theta)) + delta_theta = M_PIF; + if (u.x * v.y - u.y * v.x < 0) + delta_theta = -delta_theta; + + if (counterClockWise) { + if (delta_theta < 0) + delta_theta += M_PIF * 2.0; + } else if (delta_theta > 0) + delta_theta -= M_PIF * 2.0; + + m = (mat2){{cosf(phi), -sinf(phi)}, {sinf(phi), cosf(phi)}}; + + double theta = sa; + double ea = sa + delta_theta; + + float step = fmaxf(0.001f, fminf(M_PIF, _get_arc_step(ctx, fminf(rx, ry)) * 0.1f)); + + p = (vec2){rx * cosf(theta), ry * sinf(theta)}; + vec2 xy = vec2_add(mat2_mult_vec2(m, p), c); + + if (_current_path_is_empty(ctx)) { + _set_curve_start(ctx); + _add_point(ctx, xy.x, xy.y); + if (!ctx->pathPtr) + ctx->simpleConvex = true; + else + ctx->simpleConvex = false; + } else { + _line_to(ctx, xy.x, xy.y); + _set_curve_start(ctx); + ctx->simpleConvex = false; + } + + _set_curve_start(ctx); + + if (sa < ea) { + theta += step; + while (theta < ea) { + p = (vec2){rx * cosf(theta), ry * sinf(theta)}; + xy = vec2_add(mat2_mult_vec2(m, p), c); + _add_point(ctx, xy.x, xy.y); + theta += step; + } + } else { + theta -= step; + while (theta > ea) { + p = (vec2){rx * cosf(theta), ry * sinf(theta)}; + xy = vec2_add(mat2_mult_vec2(m, p), c); + _add_point(ctx, xy.x, xy.y); + theta -= step; + } + } + p = (vec2){rx * cosf(ea), ry * sinf(ea)}; + xy = vec2_add(mat2_mult_vec2(m, p), c); + _add_point(ctx, xy.x, xy.y); + _set_curve_end(ctx); +} + +// Even-Odd inside test with stencil buffer implementation. +void _poly_fill(VkvgContext ctx, vec4 *bounds) { + // we anticipate the check for vbo buffer size, ibo is not used in poly_fill + // the polyfill emit a single vertex for each point in the path. + if (ctx->sizeVBO - VKVG_ARRAY_THRESHOLD < ctx->vertCount + ctx->pointCount) { + if (ctx->cmdStarted) { + _end_render_pass(ctx); + if (ctx->vertCount > 0) + _flush_vertices_caches(ctx); + vkh_cmd_end(ctx->cmd); + _wait_and_submit_cmd(ctx); + _wait_ctx_flush_end(ctx); + if (ctx->sizeVBO - VKVG_ARRAY_THRESHOLD < ctx->pointCount) { + _resize_vbo(ctx, ctx->pointCount + VKVG_ARRAY_THRESHOLD); + _resize_vertex_cache(ctx, ctx->sizeVBO); + } + } else { + _resize_vbo(ctx, ctx->vertCount + ctx->pointCount + VKVG_ARRAY_THRESHOLD); + _resize_vertex_cache(ctx, ctx->sizeVBO); + } + + _start_cmd_for_render_pass(ctx); + } else { + _ensure_vertex_cache_size(ctx, ctx->pointCount); + _ensure_renderpass_is_started(ctx); + } + + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelinePolyFill); + + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; + uint32_t ptrPath = 0; + uint32_t firstPtIdx = 0; + + while (ptrPath < ctx->pathPtr) { + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + if (pathPointCount > 2) { + VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)ctx->vertCount; + + for (uint32_t i = 0; i < pathPointCount; i++) { + v.pos = ctx->points[i + firstPtIdx]; + ctx->vertexCache[ctx->vertCount++] = v; + if (!bounds) + continue; + // bounds are computed here to scissor the painting operation + // that speed up fill drastically. + vkvg_matrix_transform_point(&ctx->pushConsts.mat, &v.pos.x, &v.pos.y); + + if (v.pos.x < bounds->xMin) + bounds->xMin = v.pos.x; + if (v.pos.x > bounds->xMax) + bounds->xMax = v.pos.x; + if (v.pos.y < bounds->yMin) + bounds->yMin = v.pos.y; + if (v.pos.y > bounds->yMax) + bounds->yMax = v.pos.y; + } + + LOG(VKVG_LOG_INFO_PATH, "\tpoly fill: point count = %d; 1st vert = %d; vert count = %d\n", pathPointCount, + firstVertIdx, ctx->vertCount - firstVertIdx); + CmdDraw(ctx->cmd, pathPointCount, 1, firstVertIdx, 0); + } + firstPtIdx += pathPointCount; + + if (_path_has_curves(ctx, ptrPath)) { + // skip segments lengths used in stroke + ptrPath++; + uint32_t totPts = 0; + while (totPts < pathPointCount) + totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); + } else + ptrPath++; + } + ctx->curVertOffset = ctx->vertCount; } #ifdef VKVG_FILL_NZ_GLUTESS void fan_vertex2(VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) { - VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; - switch (ctx->tesselator_idx_counter) { - case 0: - _add_indice(ctx, i); - ctx->tesselator_fan_start = i; - ctx->tesselator_idx_counter ++; - break; - case 1: - case 2: - _add_indice(ctx, i); - ctx->tesselator_idx_counter ++; - break; - default: - _add_indice_for_fan (ctx, i); - break; - } + VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; + switch (ctx->tesselator_idx_counter) { + case 0: + _add_indice(ctx, i); + ctx->tesselator_fan_start = i; + ctx->tesselator_idx_counter++; + break; + case 1: + case 2: + _add_indice(ctx, i); + ctx->tesselator_idx_counter++; + break; + default: + _add_indice_for_fan(ctx, i); + break; + } } void strip_vertex2(VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) { - VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; - if (ctx->tesselator_idx_counter < 3) { - _add_indice(ctx, i); - } else - _add_indice_for_strip(ctx, i, ctx->tesselator_idx_counter % 2); - ctx->tesselator_idx_counter ++; -} - -void triangle_vertex2 (VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) { - VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; - _add_indice(ctx, i); -} -void skip_vertex2 (VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) {} -void begin2(GLenum which, void *poly_data) -{ - VkvgContext ctx = (VkvgContext)poly_data; - switch (which) { - case GL_TRIANGLES: - ctx->vertex_cb = &triangle_vertex2; - break; - case GL_TRIANGLE_STRIP: - ctx->tesselator_idx_counter = 0; - ctx->vertex_cb = &strip_vertex2; - break; - case GL_TRIANGLE_FAN: - ctx->tesselator_idx_counter = ctx->tesselator_fan_start = 0; - ctx->vertex_cb = &fan_vertex2; - break; - default: - fprintf(stderr, "ERROR, can't handle %d\n", (int)which); - ctx->vertex_cb = &skip_vertex2; - } -} - -void combine2(const GLdouble newVertex[3], - const void *neighborVertex_s[4], - const GLfloat neighborWeight[4], void **outData, void *poly_data) -{ - VkvgContext ctx = (VkvgContext)poly_data; - Vertex v = {{newVertex[0],newVertex[1]},ctx->curColor, {0,0,-1}}; - *outData = (void*)((unsigned long)(ctx->vertCount - ctx->curVertOffset)); - _add_vertex(ctx, v); -} -void vertex2(void *vertex_data, void *poly_data) -{ - VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)vertex_data; - VkvgContext ctx = (VkvgContext)poly_data; - ctx->vertex_cb(i, ctx); -} -void _fill_non_zero (VkvgContext ctx){ - Vertex v = {{0},ctx->curColor, {0,0,-1}}; - - uint32_t ptrPath = 0; - uint32_t firstPtIdx = 0; - - if (ctx->pathPtr == 1 && ctx->pathes[0] & PATH_IS_CONVEX_BIT) { - //simple concave rectangle or circle - VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; - - _ensure_vertex_cache_size(ctx, pathPointCount); - _ensure_index_cache_size(ctx, (pathPointCount-2)*3); - - VKVG_IBO_INDEX_TYPE i = 0; - while (i < 2){ - v.pos = ctx->points [i++]; - _set_vertex (ctx, ctx->vertCount++, v); - } - while (i < pathPointCount){ - v.pos = ctx->points [i]; - _set_vertex (ctx, ctx->vertCount++, v); - _add_triangle_indices_unchecked(ctx, firstVertIdx, firstVertIdx + i - 1, firstVertIdx + i); - i++; - } - return; - } - - - GLUtesselator *tess = gluNewTess(); - gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); - gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (*) ()) &vertex2); - gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (GLvoid (*) ()) &begin2); - gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (GLvoid (*) ()) &combine2); - - gluTessBeginPolygon(tess, ctx); - - while (ptrPath < ctx->pathPtr){ - uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; - - if (pathPointCount > 2) { - VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - gluTessBeginContour(tess); - - VKVG_IBO_INDEX_TYPE i = 0; - - while (i < pathPointCount){ - v.pos = ctx->points[i+firstPtIdx]; - double dp[] = {v.pos.x,v.pos.y,0}; - _add_vertex(ctx, v); - gluTessVertex(tess, dp, (void*)((unsigned long)firstVertIdx + i)); - i++; - } - gluTessEndContour(tess); - - //limit batch size here to 1/3 of the ibo index type ability - //if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) - // _emit_draw_cmd_undrawn_vertices(ctx); - } - - firstPtIdx += pathPointCount; - if (_path_has_curves (ctx, ptrPath)) { - //skip segments lengths used in stroke - ptrPath++; - uint32_t totPts = 0; - while (totPts < pathPointCount) - totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); - }else - ptrPath++; - } - - gluTessEndPolygon(tess); - - gluDeleteTess(tess); + VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; + if (ctx->tesselator_idx_counter < 3) { + _add_indice(ctx, i); + } else + _add_indice_for_strip(ctx, i, ctx->tesselator_idx_counter % 2); + ctx->tesselator_idx_counter++; +} + +void triangle_vertex2(VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) { + VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; + _add_indice(ctx, i); +} +void skip_vertex2(VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) {} +void begin2(GLenum which, void *poly_data) { + VkvgContext ctx = (VkvgContext)poly_data; + switch (which) { + case GL_TRIANGLES: + ctx->vertex_cb = &triangle_vertex2; + break; + case GL_TRIANGLE_STRIP: + ctx->tesselator_idx_counter = 0; + ctx->vertex_cb = &strip_vertex2; + break; + case GL_TRIANGLE_FAN: + ctx->tesselator_idx_counter = ctx->tesselator_fan_start = 0; + ctx->vertex_cb = &fan_vertex2; + break; + default: + fprintf(stderr, "ERROR, can't handle %d\n", (int)which); + ctx->vertex_cb = &skip_vertex2; + } +} + +void combine2(const GLdouble newVertex[3], const void *neighborVertex_s[4], const GLfloat neighborWeight[4], + void **outData, void *poly_data) { + VkvgContext ctx = (VkvgContext)poly_data; + Vertex v = {{newVertex[0], newVertex[1]}, ctx->curColor, {0, 0, -1}}; + *outData = (void *)((unsigned long)(ctx->vertCount - ctx->curVertOffset)); + _add_vertex(ctx, v); +} +void vertex2(void *vertex_data, void *poly_data) { + VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)vertex_data; + VkvgContext ctx = (VkvgContext)poly_data; + ctx->vertex_cb(i, ctx); +} +void _fill_non_zero(VkvgContext ctx) { + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; + + uint32_t ptrPath = 0; + uint32_t firstPtIdx = 0; + + if (ctx->pathPtr == 1 && ctx->pathes[0] & PATH_IS_CONVEX_BIT) { + // simple concave rectangle or circle + VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + + _ensure_vertex_cache_size(ctx, pathPointCount); + _ensure_index_cache_size(ctx, (pathPointCount - 2) * 3); + + VKVG_IBO_INDEX_TYPE i = 0; + while (i < 2) { + v.pos = ctx->points[i++]; + _set_vertex(ctx, ctx->vertCount++, v); + } + while (i < pathPointCount) { + v.pos = ctx->points[i]; + _set_vertex(ctx, ctx->vertCount++, v); + _add_triangle_indices_unchecked(ctx, firstVertIdx, firstVertIdx + i - 1, firstVertIdx + i); + i++; + } + return; + } + + GLUtesselator *tess = gluNewTess(); + gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); + gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid(*)()) & vertex2); + gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (GLvoid(*)()) & begin2); + gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (GLvoid(*)()) & combine2); + + gluTessBeginPolygon(tess, ctx); + + while (ptrPath < ctx->pathPtr) { + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + + if (pathPointCount > 2) { + VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + gluTessBeginContour(tess); + + VKVG_IBO_INDEX_TYPE i = 0; + + while (i < pathPointCount) { + v.pos = ctx->points[i + firstPtIdx]; + double dp[] = {v.pos.x, v.pos.y, 0}; + _add_vertex(ctx, v); + gluTessVertex(tess, dp, (void *)((unsigned long)firstVertIdx + i)); + i++; + } + gluTessEndContour(tess); + + // limit batch size here to 1/3 of the ibo index type ability + // if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) + // _emit_draw_cmd_undrawn_vertices(ctx); + } + + firstPtIdx += pathPointCount; + if (_path_has_curves(ctx, ptrPath)) { + // skip segments lengths used in stroke + ptrPath++; + uint32_t totPts = 0; + while (totPts < pathPointCount) + totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); + } else + ptrPath++; + } + + gluTessEndPolygon(tess); + + gluDeleteTess(tess); } #else -//create fill from current path with ear clipping technic -void _fill_non_zero (VkvgContext ctx){ - Vertex v = {{0},ctx->curColor, {0,0,-1}}; - - uint32_t ptrPath = 0; - uint32_t firstPtIdx = 0; - - while (ptrPath < ctx->pathPtr){ - uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; - - if (pathPointCount > 2) { - VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - //ear_clip_point* ecps = (ear_clip_point*)malloc(pathPointCount*sizeof(ear_clip_point)); - ear_clip_point ecps[pathPointCount]; - uint32_t ecps_count = pathPointCount; - VKVG_IBO_INDEX_TYPE i = 0; - - //init points link list - while (i < pathPointCount-1){ - v.pos = ctx->points[i+firstPtIdx]; - ear_clip_point ecp = {v.pos, firstVertIdx+i, &ecps[i+1]}; - ecps[i] = ecp; - _add_vertex(ctx, v); - i++; - } - - v.pos = ctx->points[i+firstPtIdx]; - ear_clip_point ecp = {v.pos, firstVertIdx+i, ecps}; - ecps[i] = ecp; - _add_vertex(ctx, v); - - ear_clip_point* ecp_current = ecps; - uint32_t tries = 0; - - while (ecps_count > 3) { - if (tries > ecps_count) { - break; - } - ear_clip_point* v0 = ecp_current->next, - *v1 = ecp_current, *v2 = ecp_current->next->next; - if (ecp_zcross (v0, v2, v1)<0){ - ecp_current = ecp_current->next; - tries++; - continue; - } - ear_clip_point* vP = v2->next; - bool isEar = true; - while (vP!=v1){ - if (ptInTriangle (vP->pos, v0->pos, v2->pos, v1->pos)){ - isEar = false; - break; - } - vP = vP->next; - } - if (isEar){ - _add_triangle_indices (ctx, v0->idx, v1->idx, v2->idx); - v1->next = v2; - ecps_count --; - tries = 0; - }else{ - ecp_current = ecp_current->next; - tries++; - } - } - if (ecps_count == 3) - _add_triangle_indices(ctx, ecp_current->next->idx, ecp_current->idx, ecp_current->next->next->idx); - - //limit batch size here to 1/3 of the ibo index type ability - if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) - _emit_draw_cmd_undrawn_vertices(ctx); - } - - firstPtIdx += pathPointCount; - if (_path_has_curves (ctx, ptrPath)) { - //skip segments lengths used in stroke - ptrPath++; - uint32_t totPts = 0; - while (totPts < pathPointCount) - totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); - }else - ptrPath++; - } +// create fill from current path with ear clipping technic +void _fill_non_zero(VkvgContext ctx) { + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; + + uint32_t ptrPath = 0; + uint32_t firstPtIdx = 0; + + while (ptrPath < ctx->pathPtr) { + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + + if (pathPointCount > 2) { + VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + // ear_clip_point* ecps = (ear_clip_point*)malloc(pathPointCount*sizeof(ear_clip_point)); + ear_clip_point ecps[pathPointCount]; + uint32_t ecps_count = pathPointCount; + VKVG_IBO_INDEX_TYPE i = 0; + + // init points link list + while (i < pathPointCount - 1) { + v.pos = ctx->points[i + firstPtIdx]; + ear_clip_point ecp = {v.pos, firstVertIdx + i, &ecps[i + 1]}; + ecps[i] = ecp; + _add_vertex(ctx, v); + i++; + } + + v.pos = ctx->points[i + firstPtIdx]; + ear_clip_point ecp = {v.pos, firstVertIdx + i, ecps}; + ecps[i] = ecp; + _add_vertex(ctx, v); + + ear_clip_point *ecp_current = ecps; + uint32_t tries = 0; + + while (ecps_count > 3) { + if (tries > ecps_count) { + break; + } + ear_clip_point *v0 = ecp_current->next, *v1 = ecp_current, *v2 = ecp_current->next->next; + if (ecp_zcross(v0, v2, v1) < 0) { + ecp_current = ecp_current->next; + tries++; + continue; + } + ear_clip_point *vP = v2->next; + bool isEar = true; + while (vP != v1) { + if (ptInTriangle(vP->pos, v0->pos, v2->pos, v1->pos)) { + isEar = false; + break; + } + vP = vP->next; + } + if (isEar) { + _add_triangle_indices(ctx, v0->idx, v1->idx, v2->idx); + v1->next = v2; + ecps_count--; + tries = 0; + } else { + ecp_current = ecp_current->next; + tries++; + } + } + if (ecps_count == 3) + _add_triangle_indices(ctx, ecp_current->next->idx, ecp_current->idx, ecp_current->next->next->idx); + + // limit batch size here to 1/3 of the ibo index type ability + if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) + _emit_draw_cmd_undrawn_vertices(ctx); + } + + firstPtIdx += pathPointCount; + if (_path_has_curves(ctx, ptrPath)) { + // skip segments lengths used in stroke + ptrPath++; + uint32_t totPts = 0; + while (totPts < pathPointCount) + totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); + } else + ptrPath++; + } } #endif -void _vkvg_path_extents (VkvgContext ctx, bool transformed, float *x1, float *y1, float *x2, float *y2) { - uint32_t ptrPath = 0; - uint32_t firstPtIdx = 0; - - float xMin = FLT_MAX, yMin = FLT_MAX; - float xMax = FLT_MIN, yMax = FLT_MIN; - - while (ptrPath < ctx->pathPtr){ - uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; - - for (uint32_t i = firstPtIdx; i < firstPtIdx + pathPointCount; i++){ - vec2 p = ctx->points[i]; - if (transformed) - vkvg_matrix_transform_point (&ctx->pushConsts.mat, &p.x, &p.y); - if (p.x < xMin) - xMin = p.x; - if (p.x > xMax) - xMax = p.x; - if (p.y < yMin) - yMin = p.y; - if (p.y > yMax) - yMax = p.y; - } - - firstPtIdx += pathPointCount; - if (_path_has_curves (ctx, ptrPath)) { - //skip segments lengths used in stroke - ptrPath++; - uint32_t totPts = 0; - while (totPts < pathPointCount) - totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); - }else - ptrPath++; - } - *x1 = xMin; - *x2 = xMax; - *y1 = yMin; - *y2 = yMax; -} - -void _draw_full_screen_quad (VkvgContext ctx, vec4* scissor) { -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "_draw_full_screen_quad", DBG_LAB_COLOR_FSQ); +void _vkvg_path_extents(VkvgContext ctx, bool transformed, float *x1, float *y1, float *x2, float *y2) { + uint32_t ptrPath = 0; + uint32_t firstPtIdx = 0; + + float xMin = FLT_MAX, yMin = FLT_MAX; + float xMax = FLT_MIN, yMax = FLT_MIN; + + while (ptrPath < ctx->pathPtr) { + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + + for (uint32_t i = firstPtIdx; i < firstPtIdx + pathPointCount; i++) { + vec2 p = ctx->points[i]; + if (transformed) + vkvg_matrix_transform_point(&ctx->pushConsts.mat, &p.x, &p.y); + if (p.x < xMin) + xMin = p.x; + if (p.x > xMax) + xMax = p.x; + if (p.y < yMin) + yMin = p.y; + if (p.y > yMax) + yMax = p.y; + } + + firstPtIdx += pathPointCount; + if (_path_has_curves(ctx, ptrPath)) { + // skip segments lengths used in stroke + ptrPath++; + uint32_t totPts = 0; + while (totPts < pathPointCount) + totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); + } else + ptrPath++; + } + *x1 = xMin; + *x2 = xMax; + *y1 = yMin; + *y2 = yMax; +} + +void _draw_full_screen_quad(VkvgContext ctx, vec4 *scissor) { +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "_draw_full_screen_quad", DBG_LAB_COLOR_FSQ); #endif - if (scissor) { - VkRect2D r = { - {(int32_t)MAX(scissor->xMin, 0), (int32_t)MAX(scissor->yMin, 0)}, - {(int32_t)MAX(scissor->xMax - (int32_t)scissor->xMin + 1, 1), (int32_t)MAX(scissor->yMax - (int32_t)scissor->yMin + 1, 1)} - }; - CmdSetScissor(ctx->cmd, 0, 1, &r); - } - - uint32_t firstVertIdx = ctx->vertCount; - _ensure_vertex_cache_size (ctx, 3); - - _add_vertexf_unchecked (ctx, -1, -1); - _add_vertexf_unchecked (ctx, 3, -1); - _add_vertexf_unchecked (ctx, -1, 3); - - ctx->curVertOffset = ctx->vertCount; - - ctx->pushConsts.fsq_patternType |= FULLSCREEN_BIT; - CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT, 24, 4,&ctx->pushConsts.fsq_patternType); - CmdDraw (ctx->cmd,3,1,firstVertIdx,0); - ctx->pushConsts.fsq_patternType &= ~FULLSCREEN_BIT; - CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT, 24, 4,&ctx->pushConsts.fsq_patternType); - if (scissor) - CmdSetScissor(ctx->cmd, 0, 1, &ctx->bounds); - -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); + if (scissor) { + VkRect2D r = {{(int32_t)MAX(scissor->xMin, 0), (int32_t)MAX(scissor->yMin, 0)}, + {(int32_t)MAX(scissor->xMax - (int32_t)scissor->xMin + 1, 1), + (int32_t)MAX(scissor->yMax - (int32_t)scissor->yMin + 1, 1)}}; + CmdSetScissor(ctx->cmd, 0, 1, &r); + } + + uint32_t firstVertIdx = ctx->vertCount; + _ensure_vertex_cache_size(ctx, 3); + + _add_vertexf_unchecked(ctx, -1, -1); + _add_vertexf_unchecked(ctx, 3, -1); + _add_vertexf_unchecked(ctx, -1, 3); + + ctx->curVertOffset = ctx->vertCount; + + ctx->pushConsts.fsq_patternType |= FULLSCREEN_BIT; + CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 24, 4, + &ctx->pushConsts.fsq_patternType); + CmdDraw(ctx->cmd, 3, 1, firstVertIdx, 0); + ctx->pushConsts.fsq_patternType &= ~FULLSCREEN_BIT; + CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 24, 4, + &ctx->pushConsts.fsq_patternType); + if (scissor) + CmdSetScissor(ctx->cmd, 0, 1, &ctx->bounds); + +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); #endif } -void _select_font_face (VkvgContext ctx, const char* name){ - if (strcmp(ctx->selectedFontName, name) == 0) - return; - strcpy (ctx->selectedFontName, name); - ctx->currentFont = NULL; - ctx->currentFontSize = NULL; +void _select_font_face(VkvgContext ctx, const char *name) { + if (strcmp(ctx->selectedFontName, name) == 0) + return; + strcpy(ctx->selectedFontName, name); + ctx->currentFont = NULL; + ctx->currentFontSize = NULL; } diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index 3e74ae7..4c598b7 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -26,56 +26,58 @@ #include "vkvg_fonts.h" #if VKVG_RECORDING - #include "recording/vkvg_record_internal.h" +#include "recording/vkvg_record_internal.h" #else - #define RECORD(ctx,cmd,...) - #define RECORD2(ctx,cmd,...) +#define RECORD(ctx, cmd, ...) +#define RECORD2(ctx, cmd, ...) #endif -#define VKVG_PTS_SIZE 1024 -#define VKVG_VBO_SIZE (VKVG_PTS_SIZE * 4) -#define VKVG_IBO_SIZE (VKVG_VBO_SIZE * 6) -#define VKVG_PATHES_SIZE 16 -#define VKVG_ARRAY_THRESHOLD 8 +#define VKVG_PTS_SIZE 1024 +#define VKVG_VBO_SIZE (VKVG_PTS_SIZE * 4) +#define VKVG_IBO_SIZE (VKVG_VBO_SIZE * 6) +#define VKVG_PATHES_SIZE 16 +#define VKVG_ARRAY_THRESHOLD 8 -#define VKVG_IBO_16 0 -#define VKVG_IBO_32 1 +#define VKVG_IBO_16 0 +#define VKVG_IBO_32 1 -#define VKVG_CUR_IBO_TYPE VKVG_IBO_32//change this only +#define VKVG_CUR_IBO_TYPE VKVG_IBO_32 // change this only #if VKVG_CUR_IBO_TYPE == VKVG_IBO_16 - #define VKVG_IBO_MAX UINT16_MAX - #define VKVG_IBO_INDEX_TYPE uint16_t - #define VKVG_VK_INDEX_TYPE VK_INDEX_TYPE_UINT16 +#define VKVG_IBO_MAX UINT16_MAX +#define VKVG_IBO_INDEX_TYPE uint16_t +#define VKVG_VK_INDEX_TYPE VK_INDEX_TYPE_UINT16 #else - #define VKVG_IBO_MAX UINT32_MAX - #define VKVG_IBO_INDEX_TYPE uint32_t - #define VKVG_VK_INDEX_TYPE VK_INDEX_TYPE_UINT32 +#define VKVG_IBO_MAX UINT32_MAX +#define VKVG_IBO_INDEX_TYPE uint32_t +#define VKVG_VK_INDEX_TYPE VK_INDEX_TYPE_UINT32 #endif -#define FULLSCREEN_BIT 0x10000000 -#define SRCTYPE_MASK 0x000000FF +#define FULLSCREEN_BIT 0x10000000 +#define SRCTYPE_MASK 0x000000FF #define CreateRgba(r, g, b, a) ((a << 24) | (r << 16) | (g << 8) | b) #ifdef VKVG_PREMULT_ALPHA - #define CreateRgbaf(r, g, b, a) (((int)(a * 255.0f) << 24) | ((int)(b * a * 255.0f) << 16) | ((int)(g * a * 255.0f) << 8) | (int)(r * a * 255.0f)) +#define CreateRgbaf(r, g, b, a) \ + (((int)(a * 255.0f) << 24) | ((int)(b * a * 255.0f) << 16) | ((int)(g * a * 255.0f) << 8) | (int)(r * a * 255.0f)) #else - #define CreateRgbaf(r, g, b, a) (((int)(a * 255.0f) << 24) | ((int)(b * 255.0f) << 16) | ((int)(g * 255.0f) << 8) | (int)(r * 255.0f)) +#define CreateRgbaf(r, g, b, a) \ + (((int)(a * 255.0f) << 24) | ((int)(b * 255.0f) << 16) | ((int)(g * 255.0f) << 8) | (int)(r * 255.0f)) #endif typedef struct { - vec2 pos; - uint32_t color; - vec3 uv; + vec2 pos; + uint32_t color; + vec3 uv; } Vertex; typedef struct { - vec4 source; - vec2 size; - uint32_t fsq_patternType; - float opacity; - vkvg_matrix_t mat; - vkvg_matrix_t matInv; + vec4 source; + vec2 size; + uint32_t fsq_patternType; + float opacity; + vkvg_matrix_t mat; + vkvg_matrix_t matInv; } push_constants; /* context.curClipState may be one of the following, it's set @@ -90,249 +92,244 @@ typedef struct { * - clip_saved: context is clipped and the clip region is saved at that level. */ typedef enum { - vkvg_clip_state_none = 0x00, - vkvg_clip_state_clear = 0x01, - vkvg_clip_state_clip = 0x02, - vkvg_clip_state_clip_saved = 0x06, + vkvg_clip_state_none = 0x00, + vkvg_clip_state_clear = 0x01, + vkvg_clip_state_clip = 0x02, + vkvg_clip_state_clip_saved = 0x06, } vkvg_clip_state_t; typedef struct _vkvg_context_save_t { - struct _vkvg_context_save_t* pNext; - - float lineWidth; - float miterLimit; - uint32_t dashCount; //value count in dash array, 0 if dash not set. - float dashOffset; //an offset for dash - float* dashes; //an array of alternate lengths of on and off stroke. - - vkvg_operator_t curOperator; - vkvg_line_cap_t lineCap; - vkvg_line_join_t lineJoint; - vkvg_fill_rule_t curFillRule; - - long selectedCharSize; /* Font size*/ - char selectedFontName[FONT_NAME_MAX_SIZE]; - _vkvg_font_identity_t selectedFont; //hold current face and size before cache addition - _vkvg_font_identity_t* currentFont; //font ready for lookup - vkvg_direction_t textDirection; - push_constants pushConsts; - uint32_t curColor; - VkvgPattern pattern; - vkvg_clip_state_t clippingState; + struct _vkvg_context_save_t *pNext; + + float lineWidth; + float miterLimit; + uint32_t dashCount; // value count in dash array, 0 if dash not set. + float dashOffset; // an offset for dash + float *dashes; // an array of alternate lengths of on and off stroke. + + vkvg_operator_t curOperator; + vkvg_line_cap_t lineCap; + vkvg_line_join_t lineJoint; + vkvg_fill_rule_t curFillRule; + + long selectedCharSize; /* Font size*/ + char selectedFontName[FONT_NAME_MAX_SIZE]; + _vkvg_font_identity_t selectedFont; // hold current face and size before cache addition + _vkvg_font_identity_t *currentFont; // font ready for lookup + vkvg_direction_t textDirection; + push_constants pushConsts; + uint32_t curColor; + VkvgPattern pattern; + vkvg_clip_state_t clippingState; } vkvg_context_save_t; typedef struct _vkvg_context_t { - vkvg_status_t status; - uint32_t references; //reference count + vkvg_status_t status; + uint32_t references; // reference count - VkvgDevice dev; - VkvgSurface pSurf; //surface bound to context, set on creation of ctx + VkvgDevice dev; + VkvgSurface pSurf; // surface bound to context, set on creation of ctx #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - uint64_t timelineStep; //context cmd last submission timeline id. + uint64_t timelineStep; // context cmd last submission timeline id. #else - VkFence flushFence; //context fence + VkFence flushFence; // context fence #endif - //VkDescriptorImageInfo sourceDescriptor; //Store view/sampler in context + // VkDescriptorImageInfo sourceDescriptor; //Store view/sampler in context - VkCommandPool cmdPool; //local pools ensure thread safety - VkCommandBuffer cmdBuffers[2]; //double cmd buff for context operations - VkCommandBuffer cmd; //current recording buffer - bool cmdStarted; //prevent flushing empty renderpass - bool pushCstDirty; //prevent pushing to gpu if not requested - VkDescriptorPool descriptorPool; //one pool per thread - VkDescriptorSet dsFont; //fonts glyphs texture atlas descriptor (local for thread safety) - VkDescriptorSet dsSrc; //source ds - VkDescriptorSet dsGrad; //gradient uniform buffer + VkCommandPool cmdPool; // local pools ensure thread safety + VkCommandBuffer cmdBuffers[2]; // double cmd buff for context operations + VkCommandBuffer cmd; // current recording buffer + bool cmdStarted; // prevent flushing empty renderpass + bool pushCstDirty; // prevent pushing to gpu if not requested + VkDescriptorPool descriptorPool; // one pool per thread + VkDescriptorSet dsFont; // fonts glyphs texture atlas descriptor (local for thread safety) + VkDescriptorSet dsSrc; // source ds + VkDescriptorSet dsGrad; // gradient uniform buffer - VkhImage fontCacheImg; //current font cache, may not be the last one, updated only if new glyphs are - //uploaded by the current context + VkhImage fontCacheImg; // current font cache, may not be the last one, updated only if new glyphs are + // uploaded by the current context - VkRect2D bounds; + VkRect2D bounds; - uint32_t curColor; + uint32_t curColor; #if VKVG_FILL_NZ_GLUTESS - void (*vertex_cb)(VKVG_IBO_INDEX_TYPE, VkvgContext);//tesselator vertex callback - VKVG_IBO_INDEX_TYPE tesselator_fan_start; - uint32_t tesselator_idx_counter; + void (*vertex_cb)(VKVG_IBO_INDEX_TYPE, VkvgContext); // tesselator vertex callback + VKVG_IBO_INDEX_TYPE tesselator_fan_start; + uint32_t tesselator_idx_counter; #endif #if VKVG_RECORDING - vkvg_recording_t* recording; + vkvg_recording_t *recording; #endif - vkh_buffer_t uboGrad; //uniform buff obj holdings gradient infos - - //vk buffers, holds data until flush - vkh_buffer_t indices; //index buffer with persistent map memory - uint32_t sizeIBO; //size of vk ibo - uint32_t sizeIndices; //reserved size - uint32_t indCount; //current indice count - - uint32_t curIndStart; //last index recorded in cmd buff - VKVG_IBO_INDEX_TYPE curVertOffset; //vertex offset in draw indexed command - - vkh_buffer_t vertices; //vertex buffer with persistent mapped memory - uint32_t sizeVBO; //size of vk vbo size - uint32_t sizeVertices; //reserved size - uint32_t vertCount; //effective vertices count - - Vertex* vertexCache; - VKVG_IBO_INDEX_TYPE* indexCache; - - //pathes, exists until stroke of fill - vec2* points; //points array - uint32_t sizePoints; //reserved size - uint32_t pointCount; //effective points count - - //pathes array is a list of point count per segment - uint32_t pathPtr; //pointer in the path array - uint32_t* pathes; - uint32_t sizePathes; - - uint32_t segmentPtr; //current segment count in current path having curves - uint32_t subpathCount; //store count of subpath, not straight forward to retrieve from segmented path array - bool simpleConvex; //true if path is single rect or concave closed curve. - - float lineWidth; - float miterLimit; - uint32_t dashCount; //value count in dash array, 0 if dash not set. - float dashOffset; //an offset for dash - float* dashes; //an array of alternate lengths of on and off stroke. - - vkvg_operator_t curOperator; - vkvg_line_cap_t lineCap; - vkvg_line_join_t lineJoin; - vkvg_fill_rule_t curFillRule; - - long selectedCharSize; /* Font size*/ - char selectedFontName[FONT_NAME_MAX_SIZE]; - //_vkvg_font_t selectedFont; //hold current face and size before cache addition - _vkvg_font_identity_t* currentFont; //font pointing to cached fonts identity - _vkvg_font_t* currentFontSize; //font structure by size ready for lookup - vkvg_direction_t textDirection; - - push_constants pushConsts; - VkvgPattern pattern; - - vkvg_context_save_t* pSavedCtxs; //last ctx saved ptr - uint8_t curSavBit; //current stencil bit used to save context, 6 bits used by stencil for save/restore - VkhImage* savedStencils; //additional image for saving contexes once more than 6 save/restore are reached - vkvg_clip_state_t curClipState; //current clipping status relative to the previous saved one or clear state if none. - - VkClearRect clearRect; - VkRenderPassBeginInfo renderPassBeginInfo; + vkh_buffer_t uboGrad; // uniform buff obj holdings gradient infos + + // vk buffers, holds data until flush + vkh_buffer_t indices; // index buffer with persistent map memory + uint32_t sizeIBO; // size of vk ibo + uint32_t sizeIndices; // reserved size + uint32_t indCount; // current indice count + + uint32_t curIndStart; // last index recorded in cmd buff + VKVG_IBO_INDEX_TYPE curVertOffset; // vertex offset in draw indexed command + + vkh_buffer_t vertices; // vertex buffer with persistent mapped memory + uint32_t sizeVBO; // size of vk vbo size + uint32_t sizeVertices; // reserved size + uint32_t vertCount; // effective vertices count + + Vertex *vertexCache; + VKVG_IBO_INDEX_TYPE *indexCache; + + // pathes, exists until stroke of fill + vec2 *points; // points array + uint32_t sizePoints; // reserved size + uint32_t pointCount; // effective points count + + // pathes array is a list of point count per segment + uint32_t pathPtr; // pointer in the path array + uint32_t *pathes; + uint32_t sizePathes; + + uint32_t segmentPtr; // current segment count in current path having curves + uint32_t subpathCount; // store count of subpath, not straight forward to retrieve from segmented path array + bool simpleConvex; // true if path is single rect or concave closed curve. + + float lineWidth; + float miterLimit; + uint32_t dashCount; // value count in dash array, 0 if dash not set. + float dashOffset; // an offset for dash + float *dashes; // an array of alternate lengths of on and off stroke. + + vkvg_operator_t curOperator; + vkvg_line_cap_t lineCap; + vkvg_line_join_t lineJoin; + vkvg_fill_rule_t curFillRule; + + long selectedCharSize; /* Font size*/ + char selectedFontName[FONT_NAME_MAX_SIZE]; + //_vkvg_font_t selectedFont; //hold current face and size before cache addition + _vkvg_font_identity_t *currentFont; // font pointing to cached fonts identity + _vkvg_font_t *currentFontSize; // font structure by size ready for lookup + vkvg_direction_t textDirection; + + push_constants pushConsts; + VkvgPattern pattern; + + vkvg_context_save_t *pSavedCtxs; // last ctx saved ptr + uint8_t curSavBit; // current stencil bit used to save context, 6 bits used by stencil for save/restore + VkhImage *savedStencils; // additional image for saving contexes once more than 6 save/restore are reached + vkvg_clip_state_t curClipState; // current clipping status relative to the previous saved one or clear state if + // none. + + VkClearRect clearRect; + VkRenderPassBeginInfo renderPassBeginInfo; } vkvg_context; typedef struct _ear_clip_point { - vec2 pos; - VKVG_IBO_INDEX_TYPE idx; - struct _ear_clip_point* next; + vec2 pos; + VKVG_IBO_INDEX_TYPE idx; + struct _ear_clip_point *next; } ear_clip_point; typedef struct { - bool dashOn; - uint32_t curDash; //current dash index - float curDashOffset; //cur dash offset between defined path point and last dash segment(on/off) start - float totDashLength; //total length of dashes - vec2 normal; + bool dashOn; + uint32_t curDash; // current dash index + float curDashOffset; // cur dash offset between defined path point and last dash segment(on/off) start + float totDashLength; // total length of dashes + vec2 normal; } dash_context_t; typedef struct { - uint32_t iL; - uint32_t iR; - uint32_t cp;//current point - - VKVG_IBO_INDEX_TYPE firstIdx;//save first point idx for closed path - float hw; //stroke half width, computed once. - float lhMax; //miter limit * line width - float arcStep; //cached arcStep, prevent compute multiple times for same stroke, 0 if not yet computed + uint32_t iL; + uint32_t iR; + uint32_t cp; // current point + + VKVG_IBO_INDEX_TYPE firstIdx; // save first point idx for closed path + float hw; // stroke half width, computed once. + float lhMax; // miter limit * line width + float arcStep; // cached arcStep, prevent compute multiple times for same stroke, 0 if not yet computed } stroke_context_t; -void _check_vertex_cache_size (VkvgContext ctx); -void _ensure_vertex_cache_size (VkvgContext ctx, uint32_t addedVerticesCount); -void _resize_vertex_cache (VkvgContext ctx, uint32_t newSize); - -void _check_index_cache_size (VkvgContext ctx); -void _ensure_index_cache_size (VkvgContext ctx, uint32_t addedIndicesCount); -void _resize_index_cache (VkvgContext ctx, uint32_t newSize); - -bool _check_pathes_array (VkvgContext ctx); - -bool _current_path_is_empty (VkvgContext ctx); -void _finish_path (VkvgContext ctx); -void _clear_path (VkvgContext ctx); -void _remove_last_point (VkvgContext ctx); -bool _path_is_closed (VkvgContext ctx, uint32_t ptrPath); -void _set_curve_start (VkvgContext ctx); -void _set_curve_end (VkvgContext ctx); -bool _path_has_curves (VkvgContext ctx, uint32_t ptrPath); - -float _normalizeAngle (float a); -float _get_arc_step (VkvgContext ctx, float radius); - -vec2 _get_current_position (VkvgContext ctx); -void _add_point (VkvgContext ctx, float x, float y); - -void _resetMinMax (VkvgContext ctx); -void _vkvg_path_extents (VkvgContext ctx, bool transformed, float *x1, float *y1, float *x2, float *y2); -void _draw_stoke_cap (VkvgContext ctx, stroke_context_t* str, vec2 p0, vec2 n, bool isStart); -void _draw_segment (VkvgContext ctx, stroke_context_t* str, dash_context_t* dc, bool isCurve); -float _draw_dashed_segment (VkvgContext ctx, stroke_context_t *str, dash_context_t* dc, bool isCurve); -bool _build_vb_step (VkvgContext ctx, stroke_context_t *str, bool isCurve); - -void _poly_fill (VkvgContext ctx, vec4 *bounds); -void _fill_non_zero (VkvgContext ctx); -void _draw_full_screen_quad (VkvgContext ctx, vec4 *scissor); - -void _create_gradient_buff (VkvgContext ctx); -void _create_vertices_buff (VkvgContext ctx); -void _add_vertex (VkvgContext ctx, Vertex v); -void _add_vertexf (VkvgContext ctx, float x, float y); -void _set_vertex (VkvgContext ctx, uint32_t idx, Vertex v); -void _add_triangle_indices (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2); -void _add_tri_indices_for_rect (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i); - -void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float height); - -void _bind_draw_pipeline (VkvgContext ctx); -void _create_cmd_buff (VkvgContext ctx); -void _check_vao_size (VkvgContext ctx); -void _flush_cmd_buff (VkvgContext ctx); -void _ensure_renderpass_is_started (VkvgContext ctx); -void _emit_draw_cmd_undrawn_vertices (VkvgContext ctx); -void _flush_cmd_until_vx_base (VkvgContext ctx); -bool _wait_ctx_flush_end (VkvgContext ctx); -bool _wait_and_submit_cmd (VkvgContext ctx); -void _update_push_constants (VkvgContext ctx); -void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat); -void _set_mat_inv_and_vkCmdPush (VkvgContext ctx); -void _start_cmd_for_render_pass (VkvgContext ctx); - -void _createDescriptorPool (VkvgContext ctx); -void _init_descriptor_sets (VkvgContext ctx); -void _update_descriptor_set (VkvgContext ctx, VkhImage img, VkDescriptorSet ds); -void _update_gradient_desc_set (VkvgContext ctx); -void _free_ctx_save (vkvg_context_save_t* sav); +void _check_vertex_cache_size(VkvgContext ctx); +void _ensure_vertex_cache_size(VkvgContext ctx, uint32_t addedVerticesCount); +void _resize_vertex_cache(VkvgContext ctx, uint32_t newSize); + +void _check_index_cache_size(VkvgContext ctx); +void _ensure_index_cache_size(VkvgContext ctx, uint32_t addedIndicesCount); +void _resize_index_cache(VkvgContext ctx, uint32_t newSize); + +bool _check_pathes_array(VkvgContext ctx); + +bool _current_path_is_empty(VkvgContext ctx); +void _finish_path(VkvgContext ctx); +void _clear_path(VkvgContext ctx); +void _remove_last_point(VkvgContext ctx); +bool _path_is_closed(VkvgContext ctx, uint32_t ptrPath); +void _set_curve_start(VkvgContext ctx); +void _set_curve_end(VkvgContext ctx); +bool _path_has_curves(VkvgContext ctx, uint32_t ptrPath); + +float _normalizeAngle(float a); +float _get_arc_step(VkvgContext ctx, float radius); + +vec2 _get_current_position(VkvgContext ctx); +void _add_point(VkvgContext ctx, float x, float y); + +void _resetMinMax(VkvgContext ctx); +void _vkvg_path_extents(VkvgContext ctx, bool transformed, float *x1, float *y1, float *x2, float *y2); +void _draw_stoke_cap(VkvgContext ctx, stroke_context_t *str, vec2 p0, vec2 n, bool isStart); +void _draw_segment(VkvgContext ctx, stroke_context_t *str, dash_context_t *dc, bool isCurve); +float _draw_dashed_segment(VkvgContext ctx, stroke_context_t *str, dash_context_t *dc, bool isCurve); +bool _build_vb_step(VkvgContext ctx, stroke_context_t *str, bool isCurve); + +void _poly_fill(VkvgContext ctx, vec4 *bounds); +void _fill_non_zero(VkvgContext ctx); +void _draw_full_screen_quad(VkvgContext ctx, vec4 *scissor); + +void _create_gradient_buff(VkvgContext ctx); +void _create_vertices_buff(VkvgContext ctx); +void _add_vertex(VkvgContext ctx, Vertex v); +void _add_vertexf(VkvgContext ctx, float x, float y); +void _set_vertex(VkvgContext ctx, uint32_t idx, Vertex v); +void _add_triangle_indices(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2); +void _add_tri_indices_for_rect(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i); + +void _vao_add_rectangle(VkvgContext ctx, float x, float y, float width, float height); + +void _bind_draw_pipeline(VkvgContext ctx); +void _create_cmd_buff(VkvgContext ctx); +void _check_vao_size(VkvgContext ctx); +void _flush_cmd_buff(VkvgContext ctx); +void _ensure_renderpass_is_started(VkvgContext ctx); +void _emit_draw_cmd_undrawn_vertices(VkvgContext ctx); +void _flush_cmd_until_vx_base(VkvgContext ctx); +bool _wait_ctx_flush_end(VkvgContext ctx); +bool _wait_and_submit_cmd(VkvgContext ctx); +void _update_push_constants(VkvgContext ctx); +void _update_cur_pattern(VkvgContext ctx, VkvgPattern pat); +void _set_mat_inv_and_vkCmdPush(VkvgContext ctx); +void _start_cmd_for_render_pass(VkvgContext ctx); + +void _createDescriptorPool(VkvgContext ctx); +void _init_descriptor_sets(VkvgContext ctx); +void _update_descriptor_set(VkvgContext ctx, VkhImage img, VkDescriptorSet ds); +void _update_gradient_desc_set(VkvgContext ctx); +void _free_ctx_save(vkvg_context_save_t *sav); void _release_context_ressources(VkvgContext ctx); -static inline float vec2_zcross (vec2 v1, vec2 v2){ - return v1.x*v2.y-v1.y*v2.x; +static inline float vec2_zcross(vec2 v1, vec2 v2) { return v1.x * v2.y - v1.y * v2.x; } +static inline float ecp_zcross(ear_clip_point *p0, ear_clip_point *p1, ear_clip_point *p2) { + return vec2_zcross(vec2_sub(p1->pos, p0->pos), vec2_sub(p2->pos, p0->pos)); } -static inline float ecp_zcross (ear_clip_point* p0, ear_clip_point* p1, ear_clip_point* p2){ - return vec2_zcross (vec2_sub (p1->pos, p0->pos), vec2_sub (p2->pos, p0->pos)); -} -void _recursive_bezier(VkvgContext ctx, float distanceTolerance, - float x1, float y1, float x2, float y2, - float x3, float y3, float x4, float y4, - unsigned level); -void _bezier (VkvgContext ctx, - float x1, float y1, float x2, float y2, - float x3, float y3, float x4, float y4); -void _line_to (VkvgContext ctx, float x, float y); -void _elliptic_arc (VkvgContext ctx, float x1, float y1, float x2, float y2, - bool largeArc, bool counterClockWise, float _rx, float _ry, float phi); - -void _select_font_face (VkvgContext ctx, const char* name); +void _recursive_bezier(VkvgContext ctx, float distanceTolerance, float x1, float y1, float x2, float y2, float x3, + float y3, float x4, float y4, unsigned level); +void _bezier(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4); +void _line_to(VkvgContext ctx, float x, float y); +void _elliptic_arc(VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, + float _rx, float _ry, float phi); + +void _select_font_face(VkvgContext ctx, const char *name); #endif diff --git a/src/vkvg_device.c b/src/vkvg_device.c index 893d23e..ad54fea 100644 --- a/src/vkvg_device.c +++ b/src/vkvg_device.c @@ -26,295 +26,309 @@ #include "vkh_phyinfo.h" #include "vk_mem_alloc.h" -#define TRY_LOAD_DEVICE_EXT(ext) { \ -if (vkh_phyinfo_try_get_extension_properties(pi, #ext, NULL)) \ - enabledExts[enabledExtsCount++] = #ext; \ -} -void vkvg_device_set_context_cache_size (VkvgDevice dev, uint32_t maxCount) { - if (maxCount == dev->cachedContextMaxCount) - return; - - dev->cachedContextMaxCount = maxCount; - - _cached_ctx* cur = dev->cachedContextLast; - while (cur && dev->cachedContextCount > dev->cachedContextMaxCount) { - _release_context_ressources (cur->ctx); - _cached_ctx* prev = cur; - cur = cur->pNext; - free (prev); - dev->cachedContextCount--; - } - dev->cachedContextLast = cur; +#define TRY_LOAD_DEVICE_EXT(ext) \ + { \ + if (vkh_phyinfo_try_get_extension_properties(pi, #ext, NULL)) \ + enabledExts[enabledExtsCount++] = #ext; \ + } +void vkvg_device_set_context_cache_size(VkvgDevice dev, uint32_t maxCount) { + if (maxCount == dev->cachedContextMaxCount) + return; + + dev->cachedContextMaxCount = maxCount; + + _cached_ctx *cur = dev->cachedContextLast; + while (cur && dev->cachedContextCount > dev->cachedContextMaxCount) { + _release_context_ressources(cur->ctx); + _cached_ctx *prev = cur; + cur = cur->pNext; + free(prev); + dev->cachedContextCount--; + } + dev->cachedContextLast = cur; } -void _device_init (VkvgDevice dev, const vkvg_device_create_info_t* info) { - dev->vkDev = info->vkdev; - dev->phy = info->phy; +void _device_init(VkvgDevice dev, const vkvg_device_create_info_t *info) { + dev->vkDev = info->vkdev; + dev->phy = info->phy; dev->instance = info->inst; - dev->hdpi = 72; - dev->vdpi = 72; - dev->samples= info->samples; - if (dev->samples == VK_SAMPLE_COUNT_1_BIT) - dev->deferredResolve = false; + dev->hdpi = 72; + dev->vdpi = 72; + dev->samples = info->samples; + if (dev->samples == VK_SAMPLE_COUNT_1_BIT) + dev->deferredResolve = false; else dev->deferredResolve = info->deferredResolve; - dev->cachedContextMaxCount = VKVG_MAX_CACHED_CONTEXT_COUNT; + dev->cachedContextMaxCount = VKVG_MAX_CACHED_CONTEXT_COUNT; #if VKVG_DBG_STATS - dev->debug_stats = (vkvg_debug_stats_t) {0}; + dev->debug_stats = (vkvg_debug_stats_t){0}; #endif - VkFormat format = FB_COLOR_FORMAT; + VkFormat format = FB_COLOR_FORMAT; - _device_check_best_image_tiling(dev, format); - if (dev->status != VKVG_STATUS_SUCCESS) - return; + _device_check_best_image_tiling(dev, format); + if (dev->status != VKVG_STATUS_SUCCESS) + return; - if (!_device_init_function_pointers (dev)){ - dev->status = VKVG_STATUS_NULL_POINTER; - return; - } + if (!_device_init_function_pointers(dev)) { + dev->status = VKVG_STATUS_NULL_POINTER; + return; + } - VkhPhyInfo phyInfos = vkh_phyinfo_create (dev->phy, NULL); + VkhPhyInfo phyInfos = vkh_phyinfo_create(dev->phy, NULL); dev->phyMemProps = phyInfos->memProps; - dev->gQueue = vkh_queue_create ((VkhDevice)dev, info->qFamIdx, info->qIndex); - //mtx_init (&dev->gQMutex, mtx_plain); + dev->gQueue = vkh_queue_create((VkhDevice)dev, info->qFamIdx, info->qIndex); + // mtx_init (&dev->gQMutex, mtx_plain); - vkh_phyinfo_destroy (phyInfos); + vkh_phyinfo_destroy(phyInfos); #ifdef VKH_USE_VMA - VmaAllocatorCreateInfo allocatorInfo = { - .physicalDevice = info->phy, - .device = info->vkdev - }; - vmaCreateAllocator(&allocatorInfo, (VmaAllocator*)&dev->allocator); + VmaAllocatorCreateInfo allocatorInfo = {.physicalDevice = info->phy, .device = info->vkdev}; + vmaCreateAllocator(&allocatorInfo, (VmaAllocator *)&dev->allocator); #endif - dev->cmdPool= vkh_cmd_pool_create ((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); - dev->cmd = vkh_cmd_buff_create ((VkhDevice)dev, dev->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); - dev->fence = vkh_fence_create_signaled ((VkhDevice)dev); - - _device_create_pipeline_cache (dev); - _fonts_cache_create (dev); - if (dev->deferredResolve || dev->samples == VK_SAMPLE_COUNT_1_BIT){ - dev->renderPass = _device_createRenderPassNoResolve (dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD); - dev->renderPass_ClearStencil = _device_createRenderPassNoResolve (dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_CLEAR); - dev->renderPass_ClearAll = _device_createRenderPassNoResolve (dev, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR); - }else{ - dev->renderPass = _device_createRenderPassMS (dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD); - dev->renderPass_ClearStencil = _device_createRenderPassMS (dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_CLEAR); - dev->renderPass_ClearAll = _device_createRenderPassMS (dev, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR); - } - _device_createDescriptorSetLayout (dev); - _device_setupPipelines (dev); - - _device_create_empty_texture (dev, format, dev->supportedTiling); + dev->cmdPool = + vkh_cmd_pool_create((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + dev->cmd = vkh_cmd_buff_create((VkhDevice)dev, dev->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); + dev->fence = vkh_fence_create_signaled((VkhDevice)dev); + + _device_create_pipeline_cache(dev); + _fonts_cache_create(dev); + if (dev->deferredResolve || dev->samples == VK_SAMPLE_COUNT_1_BIT) { + dev->renderPass = + _device_createRenderPassNoResolve(dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD); + dev->renderPass_ClearStencil = + _device_createRenderPassNoResolve(dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_CLEAR); + dev->renderPass_ClearAll = + _device_createRenderPassNoResolve(dev, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR); + } else { + dev->renderPass = _device_createRenderPassMS(dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD); + dev->renderPass_ClearStencil = + _device_createRenderPassMS(dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_CLEAR); + dev->renderPass_ClearAll = + _device_createRenderPassMS(dev, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR); + } + _device_createDescriptorSetLayout(dev); + _device_setupPipelines(dev); + + _device_create_empty_texture(dev, format, dev->supportedTiling); #ifdef DEBUG - #if defined(__linux__) && defined(__GLIBC__) - _linux_register_error_handler (); - #endif - #ifdef VKVG_DBG_UTILS - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)dev->cmdPool, "Device Cmd Pool"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)dev->cmd, "Device Cmd Buff"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)dev->fence, "Device Fence"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass, "RP load img/stencil"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearStencil, "RP clear stencil"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearAll, "RP clear all"); - - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslSrc, "DSLayout SOURCE"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslFont, "DSLayout FONT"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslGrad, "DSLayout GRADIENT"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE_LAYOUT, (uint64_t)dev->pipelineLayout, "PLLayout dev"); - - #ifndef __APPLE__ - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelinePolyFill, "PL Poly fill"); - #endif - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelineClipping, "PL Clipping"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_OVER, "PL draw Over"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_SUB, "PL draw Substract"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_CLEAR, "PL draw Clear"); - - vkh_image_set_name(dev->emptyImg, "empty IMG"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(dev->emptyImg), "empty IMG VIEW"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(dev->emptyImg), "empty IMG SAMPLER"); - #endif +#if defined(__linux__) && defined(__GLIBC__) + _linux_register_error_handler(); #endif - dev->status = VKVG_STATUS_SUCCESS; -} +#ifdef VKVG_DBG_UTILS + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)dev->cmdPool, "Device Cmd Pool"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)dev->cmd, "Device Cmd Buff"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)dev->fence, "Device Fence"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass, + "RP load img/stencil"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearStencil, + "RP clear stencil"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearAll, + "RP clear all"); + + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslSrc, + "DSLayout SOURCE"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslFont, + "DSLayout FONT"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslGrad, + "DSLayout GRADIENT"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE_LAYOUT, (uint64_t)dev->pipelineLayout, + "PLLayout dev"); -#define _CHECK_INST_EXT(ext)\ -if (vkh_instance_extension_supported(#ext)) { \ - if (pExtensions) \ - pExtensions[*pExtCount] = #ext; \ - (*pExtCount)++; \ +#ifndef __APPLE__ + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelinePolyFill, + "PL Poly fill"); +#endif + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelineClipping, "PL Clipping"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_OVER, "PL draw Over"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_SUB, "PL draw Substract"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_CLEAR, "PL draw Clear"); + + vkh_image_set_name(dev->emptyImg, "empty IMG"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(dev->emptyImg), + "empty IMG VIEW"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(dev->emptyImg), + "empty IMG SAMPLER"); +#endif +#endif + dev->status = VKVG_STATUS_SUCCESS; } -void vkvg_get_required_instance_extensions (const char** pExtensions, uint32_t* pExtCount) { - *pExtCount = 0; - vkh_instance_extensions_check_init (); +#define _CHECK_INST_EXT(ext) \ + if (vkh_instance_extension_supported(#ext)) { \ + if (pExtensions) \ + pExtensions[*pExtCount] = #ext; \ + (*pExtCount)++; \ + } +void vkvg_get_required_instance_extensions(const char **pExtensions, uint32_t *pExtCount) { + *pExtCount = 0; + + vkh_instance_extensions_check_init(); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - _CHECK_INST_EXT(VK_EXT_debug_utils) +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + _CHECK_INST_EXT(VK_EXT_debug_utils) #endif - _CHECK_INST_EXT(VK_KHR_get_physical_device_properties2) + _CHECK_INST_EXT(VK_KHR_get_physical_device_properties2) - vkh_instance_extensions_check_release(); + vkh_instance_extensions_check_release(); } -bool _get_dev_extension_is_supported (VkExtensionProperties* pExtensionProperties, uint32_t extensionCount, const char* name) { - for (uint32_t i=0; ifillModeNonSolid = VK_TRUE; - pEnabledFeatures->sampleRateShading = VK_TRUE; - pEnabledFeatures->logicOp = VK_TRUE; + pEnabledFeatures->fillModeNonSolid = VK_TRUE; + pEnabledFeatures->sampleRateShading = VK_TRUE; + pEnabledFeatures->logicOp = VK_TRUE; - void* pNext = NULL; + void *pNext = NULL; #ifdef VK_VERSION_1_2 - static VkPhysicalDeviceVulkan12Features enabledFeatures12 = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES + static VkPhysicalDeviceVulkan12Features enabledFeatures12 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - ,.scalarBlockLayout = VK_TRUE + , + .scalarBlockLayout = VK_TRUE #endif #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - ,.timelineSemaphore = VK_TRUE + , + .timelineSemaphore = VK_TRUE #endif - }; - enabledFeatures12.pNext = pNext; - pNext = &enabledFeatures12; + }; + enabledFeatures12.pNext = pNext; + pNext = &enabledFeatures12; #else #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - static VkPhysicalDeviceScalarBlockLayoutFeaturesEXT scalarBlockFeat = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT - ,.scalarBlockLayout = VK_TRUE - }; - scalarBlockFeat.pNext = pNext; - pNext = &scalarBlockFeat; + static VkPhysicalDeviceScalarBlockLayoutFeaturesEXT scalarBlockFeat = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT, .scalarBlockLayout = VK_TRUE}; + scalarBlockFeat.pNext = pNext; + pNext = &scalarBlockFeat; #endif #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - static VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timelineSemaFeat = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR - ,.timelineSemaphore = VK_TRUE - }; - timelineSemaFeat.pNext = pNext; - pNext = &timelineSemaFeat; + static VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timelineSemaFeat = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR, .timelineSemaphore = VK_TRUE}; + timelineSemaFeat.pNext = pNext; + pNext = &timelineSemaFeat; #endif #endif - return pNext; + return pNext; } +VkvgDevice vkvg_device_create(vkvg_device_create_info_t *info) { + LOG(VKVG_LOG_INFO, "CREATE Device\n"); + VkvgDevice dev = (vkvg_device *)calloc(1, sizeof(vkvg_device)); + if (!dev) { + LOG(VKVG_LOG_ERR, "CREATE Device failed, no memory\n"); + exit(-1); + } -VkvgDevice vkvg_device_create (vkvg_device_create_info_t* info) { - LOG(VKVG_LOG_INFO, "CREATE Device\n"); - VkvgDevice dev = (vkvg_device*)calloc(1,sizeof(vkvg_device)); - if (!dev) { - LOG(VKVG_LOG_ERR, "CREATE Device failed, no memory\n"); - exit(-1); - } - - dev->references = 1; + dev->references = 1; if (!info->vkdev) { - const char* enabledExts [10]; - const char* enabledLayers[10]; - uint32_t enabledExtsCount = 0, enabledLayersCount = 0, phyCount = 0; + const char *enabledExts[10]; + const char *enabledLayers[10]; + uint32_t enabledExtsCount = 0, enabledLayersCount = 0, phyCount = 0; vkh_layers_check_init(); - #ifdef VKVG_USE_VALIDATION +#ifdef VKVG_USE_VALIDATION if (vkh_layer_is_present("VK_LAYER_KHRONOS_validation")) enabledLayers[enabledLayersCount++] = "VK_LAYER_KHRONOS_validation"; - #endif +#endif - #ifdef VKVG_USE_RENDERDOC +#ifdef VKVG_USE_RENDERDOC if (vkh_layer_is_present("VK_LAYER_RENDERDOC_Capture")) enabledLayers[enabledLayersCount++] = "VK_LAYER_RENDERDOC_Capture"; - #endif +#endif vkh_layers_check_release(); - vkvg_get_required_instance_extensions (enabledExts, &enabledExtsCount); + vkvg_get_required_instance_extensions(enabledExts, &enabledExtsCount); - #ifdef VK_VERSION_1_2 +#ifdef VK_VERSION_1_2 VkhApp app = vkh_app_create(1, 2, "vkvg", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); - #else +#else VkhApp app = vkh_app_create(1, 1, "vkvg", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); - #endif +#endif - #if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_app_enable_debug_messenger(app - , VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT - , VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT - , NULL); - #endif +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_app_enable_debug_messenger(app, VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, NULL); +#endif - VkhPhyInfo* phys = vkh_app_get_phyinfos (app, &phyCount, VK_NULL_HANDLE); + VkhPhyInfo *phys = vkh_app_get_phyinfos(app, &phyCount, VK_NULL_HANDLE); if (phyCount == 0) { dev->status = VKVG_STATUS_DEVICE_ERROR; - vkh_app_destroy (app); + vkh_app_destroy(app); return dev; } @@ -326,170 +340,159 @@ VkvgDevice vkvg_device_create (vkvg_device_create_info_t* info) { if (!(pi->properties.limits.framebufferColorSampleCounts & info->samples)) { LOG(VKVG_LOG_ERR, "CREATE Device failed: sample count not supported: %d\n", info->samples); dev->status = VKVG_STATUS_DEVICE_ERROR; - vkh_app_free_phyinfos (phyCount, phys); - vkh_app_destroy (app); + vkh_app_free_phyinfos(phyCount, phys); + vkh_app_destroy(app); return dev; } - uint32_t qCount = 0; - float qPriorities[] = {0.0}; - VkDeviceQueueCreateInfo pQueueInfos[] = { {0},{0},{0} }; + uint32_t qCount = 0; + float qPriorities[] = {0.0}; + VkDeviceQueueCreateInfo pQueueInfos[] = {{0}, {0}, {0}}; - if (vkh_phyinfo_create_queues (pi, pi->gQueue, 1, qPriorities, &pQueueInfos[qCount])) + if (vkh_phyinfo_create_queues(pi, pi->gQueue, 1, qPriorities, &pQueueInfos[qCount])) qCount++; - enabledExtsCount=0; + enabledExtsCount = 0; - if (vkvg_get_required_device_extensions (pi->phy, enabledExts, &enabledExtsCount) != VKVG_STATUS_SUCCESS){ + if (vkvg_get_required_device_extensions(pi->phy, enabledExts, &enabledExtsCount) != VKVG_STATUS_SUCCESS) { dev->status = VKVG_STATUS_DEVICE_ERROR; - vkh_app_free_phyinfos (phyCount, phys); - vkh_app_destroy (app); + vkh_app_free_phyinfos(phyCount, phys); + vkh_app_destroy(app); return dev; } VkPhysicalDeviceFeatures enabledFeatures = {0}; - const void* pNext = vkvg_get_device_requirements (&enabledFeatures); - - VkDeviceCreateInfo device_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .queueCreateInfoCount = qCount, - .pQueueCreateInfos = (VkDeviceQueueCreateInfo*)&pQueueInfos, - .enabledExtensionCount = enabledExtsCount, - .ppEnabledExtensionNames = enabledExts, - .pEnabledFeatures = &enabledFeatures, - .pNext = pNext}; - dev->vkhDev = vkh_device_create(app, pi, &device_info); - - vkh_app_free_phyinfos (phyCount, phys); - - info->inst = vkh_app_get_inst(app); - info->phy = vkh_device_get_phy(dev->vkhDev); - info->vkdev = vkh_device_get_vkdev(dev->vkhDev); - info->qFamIdx = pi->gQueue; - info->qIndex = 0; + const void *pNext = vkvg_get_device_requirements(&enabledFeatures); + + VkDeviceCreateInfo device_info = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .queueCreateInfoCount = qCount, + .pQueueCreateInfos = (VkDeviceQueueCreateInfo *)&pQueueInfos, + .enabledExtensionCount = enabledExtsCount, + .ppEnabledExtensionNames = enabledExts, + .pEnabledFeatures = &enabledFeatures, + .pNext = pNext}; + dev->vkhDev = vkh_device_create(app, pi, &device_info); + + vkh_app_free_phyinfos(phyCount, phys); + + info->inst = vkh_app_get_inst(app); + info->phy = vkh_device_get_phy(dev->vkhDev); + info->vkdev = vkh_device_get_vkdev(dev->vkhDev); + info->qFamIdx = pi->gQueue; + info->qIndex = 0; } - _device_init (dev, info); + _device_init(dev, info); - return dev; + return dev; } -void vkvg_device_destroy (VkvgDevice dev) -{ - LOCK_DEVICE - dev->references--; - if (dev->references > 0) { - UNLOCK_DEVICE - return; - } - UNLOCK_DEVICE - - - if (dev->cachedContextCount > 0) { - _cached_ctx* cur = dev->cachedContextLast; - while (cur) { - _release_context_ressources (cur->ctx); - _cached_ctx* prev = cur; - cur = cur->pNext; - free (prev); - } - } - +void vkvg_device_destroy(VkvgDevice dev) { + LOCK_DEVICE + dev->references--; + if (dev->references > 0) { + UNLOCK_DEVICE + return; + } + UNLOCK_DEVICE + + if (dev->cachedContextCount > 0) { + _cached_ctx *cur = dev->cachedContextLast; + while (cur) { + _release_context_ressources(cur->ctx); + _cached_ctx *prev = cur; + cur = cur->pNext; + free(prev); + } + } - LOG(VKVG_LOG_INFO, "DESTROY Device\n"); + LOG(VKVG_LOG_INFO, "DESTROY Device\n"); - vkDeviceWaitIdle (dev->vkDev); + vkDeviceWaitIdle(dev->vkDev); - vkh_image_destroy (dev->emptyImg); + vkh_image_destroy(dev->emptyImg); - vkDestroyDescriptorSetLayout (dev->vkDev, dev->dslGrad,NULL); - vkDestroyDescriptorSetLayout (dev->vkDev, dev->dslFont,NULL); - vkDestroyDescriptorSetLayout (dev->vkDev, dev->dslSrc, NULL); + vkDestroyDescriptorSetLayout(dev->vkDev, dev->dslGrad, NULL); + vkDestroyDescriptorSetLayout(dev->vkDev, dev->dslFont, NULL); + vkDestroyDescriptorSetLayout(dev->vkDev, dev->dslSrc, NULL); #ifndef __APPLE__ - vkDestroyPipeline (dev->vkDev, dev->pipelinePolyFill, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipelinePolyFill, NULL); #endif - vkDestroyPipeline (dev->vkDev, dev->pipelineClipping, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipelineClipping, NULL); - vkDestroyPipeline (dev->vkDev, dev->pipe_OVER, NULL); - vkDestroyPipeline (dev->vkDev, dev->pipe_SUB, NULL); - vkDestroyPipeline (dev->vkDev, dev->pipe_CLEAR, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipe_OVER, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipe_SUB, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipe_CLEAR, NULL); #ifdef VKVG_WIRED_DEBUG - vkDestroyPipeline (dev->vkDev, dev->pipelineWired, NULL); - vkDestroyPipeline (dev->vkDev, dev->pipelineLineList, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipelineWired, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipelineLineList, NULL); #endif - vkDestroyPipelineLayout (dev->vkDev, dev->pipelineLayout, NULL); - vkDestroyPipelineCache (dev->vkDev, dev->pipelineCache, NULL); - vkDestroyRenderPass (dev->vkDev, dev->renderPass, NULL); - vkDestroyRenderPass (dev->vkDev, dev->renderPass_ClearStencil, NULL); - vkDestroyRenderPass (dev->vkDev, dev->renderPass_ClearAll, NULL); + vkDestroyPipelineLayout(dev->vkDev, dev->pipelineLayout, NULL); + vkDestroyPipelineCache(dev->vkDev, dev->pipelineCache, NULL); + vkDestroyRenderPass(dev->vkDev, dev->renderPass, NULL); + vkDestroyRenderPass(dev->vkDev, dev->renderPass_ClearStencil, NULL); + vkDestroyRenderPass(dev->vkDev, dev->renderPass_ClearAll, NULL); - vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); - vkDestroyFence (dev->vkDev, dev->fence,NULL); + vkWaitForFences(dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); + vkDestroyFence(dev->vkDev, dev->fence, NULL); - vkFreeCommandBuffers (dev->vkDev, dev->cmdPool, 1, &dev->cmd); - vkDestroyCommandPool (dev->vkDev, dev->cmdPool, NULL); + vkFreeCommandBuffers(dev->vkDev, dev->cmdPool, 1, &dev->cmd); + vkDestroyCommandPool(dev->vkDev, dev->cmdPool, NULL); - vkh_queue_destroy(dev->gQueue); + vkh_queue_destroy(dev->gQueue); - _font_cache_destroy(dev); + _font_cache_destroy(dev); #ifdef VKH_USE_VMA - vmaDestroyAllocator (dev->allocator); + vmaDestroyAllocator(dev->allocator); #endif - if (dev->threadAware) - mtx_destroy (&dev->mutex); + if (dev->threadAware) + mtx_destroy(&dev->mutex); - if (dev->vkhDev) { - VkhApp app = vkh_device_get_app (dev->vkhDev); - vkh_device_destroy (dev->vkhDev); - vkh_app_destroy (app); - } + if (dev->vkhDev) { + VkhApp app = vkh_device_get_app(dev->vkhDev); + vkh_device_destroy(dev->vkhDev); + vkh_app_destroy(app); + } - free(dev); + free(dev); } -vkvg_status_t vkvg_device_status (VkvgDevice dev) { - return dev->status; -} -VkvgDevice vkvg_device_reference (VkvgDevice dev) { - LOCK_DEVICE - dev->references++; - UNLOCK_DEVICE - return dev; +vkvg_status_t vkvg_device_status(VkvgDevice dev) { return dev->status; } +VkvgDevice vkvg_device_reference(VkvgDevice dev) { + LOCK_DEVICE + dev->references++; + UNLOCK_DEVICE + return dev; } -uint32_t vkvg_device_get_reference_count (VkvgDevice dev) { - return dev->references; -} -void vkvg_device_set_dpy (VkvgDevice dev, int hdpy, int vdpy) { - dev->hdpi = hdpy; - dev->vdpi = vdpy; +uint32_t vkvg_device_get_reference_count(VkvgDevice dev) { return dev->references; } +void vkvg_device_set_dpy(VkvgDevice dev, int hdpy, int vdpy) { + dev->hdpi = hdpy; + dev->vdpi = vdpy; - //TODO: reset font cache + // TODO: reset font cache } -void vkvg_device_get_dpy (VkvgDevice dev, int* hdpy, int* vdpy) { - *hdpy = dev->hdpi; - *vdpy = dev->vdpi; +void vkvg_device_get_dpy(VkvgDevice dev, int *hdpy, int *vdpy) { + *hdpy = dev->hdpi; + *vdpy = dev->vdpi; } -void vkvg_device_set_thread_aware (VkvgDevice dev, uint32_t thread_aware) { - if (thread_aware) { - if (dev->threadAware) - return; - mtx_init (&dev->mutex, mtx_plain); - mtx_init (&dev->fontCache->mutex, mtx_plain); - dev->threadAware = true; - } else if (dev->threadAware) { - mtx_destroy (&dev->mutex); - mtx_destroy (&dev->fontCache->mutex); - dev->threadAware = false; - } +void vkvg_device_set_thread_aware(VkvgDevice dev, uint32_t thread_aware) { + if (thread_aware) { + if (dev->threadAware) + return; + mtx_init(&dev->mutex, mtx_plain); + mtx_init(&dev->fontCache->mutex, mtx_plain); + dev->threadAware = true; + } else if (dev->threadAware) { + mtx_destroy(&dev->mutex); + mtx_destroy(&dev->fontCache->mutex); + dev->threadAware = false; + } } #if VKVG_DBG_STATS -vkvg_debug_stats_t vkvg_device_get_stats (VkvgDevice dev) { - return dev->debug_stats; -} -vkvg_debug_stats_t vkvg_device_reset_stats (VkvgDevice dev) { - dev->debug_stats = (vkvg_debug_stats_t) {0}; -} +vkvg_debug_stats_t vkvg_device_get_stats(VkvgDevice dev) { return dev->debug_stats; } +vkvg_debug_stats_t vkvg_device_reset_stats(VkvgDevice dev) { dev->debug_stats = (vkvg_debug_stats_t){0}; } #endif diff --git a/src/vkvg_device_internal.c b/src/vkvg_device_internal.c index f9f865c..1264d2f 100644 --- a/src/vkvg_device_internal.c +++ b/src/vkvg_device_internal.c @@ -20,9 +20,11 @@ * THE SOFTWARE. */ -#define GetInstProcAddress(inst, func)(PFN_##func)vkGetInstanceProcAddr(inst, #func); +#define GetInstProcAddress(inst, func) (PFN_##func) vkGetInstanceProcAddr(inst, #func); -#define GetVkProcAddress(dev, inst, func)(vkGetDeviceProcAddr(dev,#func)==NULL)?(PFN_##func)vkGetInstanceProcAddr(inst, #func):(PFN_##func)vkGetDeviceProcAddr(dev, #func) +#define GetVkProcAddress(dev, inst, func) \ + (vkGetDeviceProcAddr(dev, #func) == NULL) ? (PFN_##func)vkGetInstanceProcAddr(inst, #func) \ + : (PFN_##func)vkGetDeviceProcAddr(dev, #func) #include "vkvg_device_internal.h" #include "vkvg_context_internal.h" @@ -33,575 +35,586 @@ uint32_t vkvg_log_level = VKVG_LOG_DEBUG; vkvg_wired_debug_mode vkvg_wired_debug = vkvg_wired_debug_mode_normal; #endif -PFN_vkCmdBindPipeline CmdBindPipeline; -PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets; -PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer; -PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers; - -PFN_vkCmdDrawIndexed CmdDrawIndexed; -PFN_vkCmdDraw CmdDraw; - -PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask; -PFN_vkCmdSetStencilReference CmdSetStencilReference; -PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask; -PFN_vkCmdBeginRenderPass CmdBeginRenderPass; -PFN_vkCmdEndRenderPass CmdEndRenderPass; -PFN_vkCmdSetViewport CmdSetViewport; -PFN_vkCmdSetScissor CmdSetScissor; - -PFN_vkCmdPushConstants CmdPushConstants; - -PFN_vkWaitForFences WaitForFences; -PFN_vkResetFences ResetFences; -PFN_vkResetCommandBuffer ResetCommandBuffer; - -bool _device_try_get_phyinfo (VkhPhyInfo* phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo* phy) { - for (uint32_t i=0; ivkDev, &pipelineCacheCreateInfo, NULL, &dev->pipelineCache)); + VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO}; + VK_CHECK_RESULT(vkCreatePipelineCache(dev->vkDev, &pipelineCacheCreateInfo, NULL, &dev->pipelineCache)); } -VkRenderPass _device_createRenderPassNoResolve(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp) -{ - VkAttachmentDescription attColor = { - .format = FB_COLOR_FORMAT, - .samples = dev->samples, - .loadOp = loadOp, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkAttachmentDescription attDS = { - .format = dev->stencilFormat, - .samples = dev->samples, - .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .stencilLoadOp = stencilLoadOp, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, - .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; - - VkAttachmentDescription attachments[] = {attColor,attDS}; - VkAttachmentReference colorRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpassDescription = { .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .colorAttachmentCount = 1, - .pColorAttachments = &colorRef, - .pDepthStencilAttachment= &dsRef}; - - VkSubpassDependency dependencies[] = - { - { VK_SUBPASS_EXTERNAL, 0, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_DEPENDENCY_BY_REGION_BIT}, - { 0, VK_SUBPASS_EXTERNAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, - VK_DEPENDENCY_BY_REGION_BIT}, - }; - - VkRenderPassCreateInfo renderPassInfo = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .attachmentCount = 2, - .pAttachments = attachments, - .subpassCount = 1, - .pSubpasses = &subpassDescription, - .dependencyCount = 2, - .pDependencies = dependencies - }; - VkRenderPass rp; - VK_CHECK_RESULT(vkCreateRenderPass(dev->vkDev, &renderPassInfo, NULL, &rp)); - return rp; +VkRenderPass _device_createRenderPassNoResolve(VkvgDevice dev, VkAttachmentLoadOp loadOp, + VkAttachmentLoadOp stencilLoadOp) { + VkAttachmentDescription attColor = {.format = FB_COLOR_FORMAT, + .samples = dev->samples, + .loadOp = loadOp, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentDescription attDS = {.format = dev->stencilFormat, + .samples = dev->samples, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = stencilLoadOp, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkAttachmentDescription attachments[] = {attColor, attDS}; + VkAttachmentReference colorRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpassDescription = {.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = 1, + .pColorAttachments = &colorRef, + .pDepthStencilAttachment = &dsRef}; + + VkSubpassDependency dependencies[] = { + {VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_DEPENDENCY_BY_REGION_BIT}, + {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, + VK_DEPENDENCY_BY_REGION_BIT}, + }; + + VkRenderPassCreateInfo renderPassInfo = {.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 2, + .pAttachments = attachments, + .subpassCount = 1, + .pSubpasses = &subpassDescription, + .dependencyCount = 2, + .pDependencies = dependencies}; + VkRenderPass rp; + VK_CHECK_RESULT(vkCreateRenderPass(dev->vkDev, &renderPassInfo, NULL, &rp)); + return rp; } -VkRenderPass _device_createRenderPassMS(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp) -{ - VkAttachmentDescription attColor = { - .format = FB_COLOR_FORMAT, - .samples = dev->samples, - .loadOp = loadOp, - .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkAttachmentDescription attColorResolve = { - .format = FB_COLOR_FORMAT, - .samples = VK_SAMPLE_COUNT_1_BIT, - .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkAttachmentDescription attDS = { - .format = dev->stencilFormat, - .samples = dev->samples, - .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .stencilLoadOp = stencilLoadOp, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, - .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; - - VkAttachmentDescription attachments[] = {attColorResolve,attDS,attColor}; - VkAttachmentReference resolveRef= {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - VkAttachmentReference colorRef = {2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpassDescription = { .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .colorAttachmentCount = 1, - .pColorAttachments = &colorRef, - .pResolveAttachments = &resolveRef, - .pDepthStencilAttachment= &dsRef}; - - VkSubpassDependency dependencies[] = - { - { VK_SUBPASS_EXTERNAL, 0, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_DEPENDENCY_BY_REGION_BIT}, - { 0, VK_SUBPASS_EXTERNAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, - VK_DEPENDENCY_BY_REGION_BIT}, - }; - - VkRenderPassCreateInfo renderPassInfo = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .attachmentCount = 3, - .pAttachments = attachments, - .subpassCount = 1, - .pSubpasses = &subpassDescription, - .dependencyCount = 2, - .pDependencies = dependencies - }; - VkRenderPass rp; - VK_CHECK_RESULT(vkCreateRenderPass(dev->vkDev, &renderPassInfo, NULL, &rp)); - return rp; +VkRenderPass _device_createRenderPassMS(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp) { + VkAttachmentDescription attColor = {.format = FB_COLOR_FORMAT, + .samples = dev->samples, + .loadOp = loadOp, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentDescription attColorResolve = {.format = FB_COLOR_FORMAT, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentDescription attDS = {.format = dev->stencilFormat, + .samples = dev->samples, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = stencilLoadOp, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkAttachmentDescription attachments[] = {attColorResolve, attDS, attColor}; + VkAttachmentReference resolveRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + VkAttachmentReference colorRef = {2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpassDescription = {.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = 1, + .pColorAttachments = &colorRef, + .pResolveAttachments = &resolveRef, + .pDepthStencilAttachment = &dsRef}; + + VkSubpassDependency dependencies[] = { + {VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_DEPENDENCY_BY_REGION_BIT}, + {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, + VK_DEPENDENCY_BY_REGION_BIT}, + }; + + VkRenderPassCreateInfo renderPassInfo = {.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 3, + .pAttachments = attachments, + .subpassCount = 1, + .pSubpasses = &subpassDescription, + .dependencyCount = 2, + .pDependencies = dependencies}; + VkRenderPass rp; + VK_CHECK_RESULT(vkCreateRenderPass(dev->vkDev, &renderPassInfo, NULL, &rp)); + return rp; } -void _device_setupPipelines(VkvgDevice dev) -{ - VkGraphicsPipelineCreateInfo pipelineCreateInfo = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .renderPass = dev->renderPass }; - - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN }; - - VkPipelineRasterizationStateCreateInfo rasterizationState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - .polygonMode = VK_POLYGON_MODE_FILL, - .cullMode = VK_CULL_MODE_NONE, - .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, - .depthClampEnable = VK_FALSE, - .rasterizerDiscardEnable = VK_FALSE, - .depthBiasEnable = VK_FALSE, - .lineWidth = 1.0f }; - - VkPipelineColorBlendAttachmentState blendAttachmentState = - { .colorWriteMask = 0x0, .blendEnable = VK_TRUE, +void _device_setupPipelines(VkvgDevice dev) { + VkGraphicsPipelineCreateInfo pipelineCreateInfo = {.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .renderPass = dev->renderPass}; + + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN}; + + VkPipelineRasterizationStateCreateInfo rasterizationState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .depthBiasEnable = VK_FALSE, + .lineWidth = 1.0f}; + + VkPipelineColorBlendAttachmentState blendAttachmentState = { + .colorWriteMask = 0x0, + .blendEnable = VK_TRUE, #ifdef VKVG_PREMULT_ALPHA - .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, - .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .colorBlendOp = VK_BLEND_OP_ADD, - .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, - .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .alphaBlendOp = VK_BLEND_OP_ADD, + .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaBlendOp = VK_BLEND_OP_ADD, #else - .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, - .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .colorBlendOp = VK_BLEND_OP_ADD, - .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, - .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, - .alphaBlendOp = VK_BLEND_OP_ADD, + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD, #endif - }; - - VkPipelineColorBlendStateCreateInfo colorBlendState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = &blendAttachmentState }; - - /*failOp,passOp,depthFailOp,compareOp, compareMask, writeMask, reference;*/ - VkStencilOpState polyFillOpState ={VK_STENCIL_OP_KEEP,VK_STENCIL_OP_INVERT, VK_STENCIL_OP_KEEP,VK_COMPARE_OP_EQUAL,STENCIL_CLIP_BIT,STENCIL_FILL_BIT,0}; - VkStencilOpState clipingOpState = {VK_STENCIL_OP_ZERO,VK_STENCIL_OP_REPLACE,VK_STENCIL_OP_KEEP,VK_COMPARE_OP_EQUAL,STENCIL_FILL_BIT,STENCIL_ALL_BIT, 0x2}; - VkStencilOpState stencilOpState = {VK_STENCIL_OP_KEEP,VK_STENCIL_OP_ZERO, VK_STENCIL_OP_KEEP,VK_COMPARE_OP_EQUAL,STENCIL_FILL_BIT,STENCIL_FILL_BIT,0x1}; - - VkPipelineDepthStencilStateCreateInfo dsStateCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, - .depthTestEnable = VK_FALSE, - .depthWriteEnable = VK_FALSE, - .depthCompareOp = VK_COMPARE_OP_ALWAYS, - .stencilTestEnable = VK_TRUE, - .front = polyFillOpState, - .back = polyFillOpState }; - - VkDynamicState dynamicStateEnables[] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR, - VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, - VK_DYNAMIC_STATE_STENCIL_REFERENCE, - VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, - }; - VkPipelineDynamicStateCreateInfo dynamicState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .dynamicStateCount = 2, - .pDynamicStates = dynamicStateEnables }; - - VkPipelineViewportStateCreateInfo viewportState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .viewportCount = 1, .scissorCount = 1 }; - - VkPipelineMultisampleStateCreateInfo multisampleState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - .rasterizationSamples = dev->samples }; - /*if (dev->samples != VK_SAMPLE_COUNT_1_BIT){ - multisampleState.sampleShadingEnable = VK_TRUE; - multisampleState.minSampleShading = 0.5f; - }*/ - VkVertexInputBindingDescription vertexInputBinding = { .binding = 0, - .stride = sizeof(Vertex), - .inputRate = VK_VERTEX_INPUT_RATE_VERTEX }; - - VkVertexInputAttributeDescription vertexInputAttributs[3] = { - {0, 0, VK_FORMAT_R32G32_SFLOAT, 0}, - {1, 0, VK_FORMAT_R8G8B8A8_UNORM, 8}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, 12} - }; - - VkPipelineVertexInputStateCreateInfo vertexInputState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .vertexBindingDescriptionCount = 1, - .pVertexBindingDescriptions = &vertexInputBinding, - .vertexAttributeDescriptionCount= 3, - .pVertexAttributeDescriptions = vertexInputAttributs }; + }; + + VkPipelineColorBlendStateCreateInfo colorBlendState = {.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &blendAttachmentState}; + + /*failOp,passOp,depthFailOp,compareOp, compareMask, writeMask, reference;*/ + VkStencilOpState polyFillOpState = {VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_INVERT, + VK_STENCIL_OP_KEEP, + VK_COMPARE_OP_EQUAL, + STENCIL_CLIP_BIT, + STENCIL_FILL_BIT, + 0}; + VkStencilOpState clipingOpState = {VK_STENCIL_OP_ZERO, + VK_STENCIL_OP_REPLACE, + VK_STENCIL_OP_KEEP, + VK_COMPARE_OP_EQUAL, + STENCIL_FILL_BIT, + STENCIL_ALL_BIT, + 0x2}; + VkStencilOpState stencilOpState = {VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_ZERO, + VK_STENCIL_OP_KEEP, + VK_COMPARE_OP_EQUAL, + STENCIL_FILL_BIT, + STENCIL_FILL_BIT, + 0x1}; + + VkPipelineDepthStencilStateCreateInfo dsStateCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = VK_FALSE, + .depthWriteEnable = VK_FALSE, + .depthCompareOp = VK_COMPARE_OP_ALWAYS, + .stencilTestEnable = VK_TRUE, + .front = polyFillOpState, + .back = polyFillOpState}; + + VkDynamicState dynamicStateEnables[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, + VK_DYNAMIC_STATE_STENCIL_REFERENCE, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, + }; + VkPipelineDynamicStateCreateInfo dynamicState = {.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = 2, + .pDynamicStates = dynamicStateEnables}; + + VkPipelineViewportStateCreateInfo viewportState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .viewportCount = 1, .scissorCount = 1}; + + VkPipelineMultisampleStateCreateInfo multisampleState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .rasterizationSamples = dev->samples}; + /*if (dev->samples != VK_SAMPLE_COUNT_1_BIT){ + multisampleState.sampleShadingEnable = VK_TRUE; + multisampleState.minSampleShading = 0.5f; + }*/ + VkVertexInputBindingDescription vertexInputBinding = { + .binding = 0, .stride = sizeof(Vertex), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX}; + + VkVertexInputAttributeDescription vertexInputAttributs[3] = {{0, 0, VK_FORMAT_R32G32_SFLOAT, 0}, + {1, 0, VK_FORMAT_R8G8B8A8_UNORM, 8}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, 12}}; + + VkPipelineVertexInputStateCreateInfo vertexInputState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &vertexInputBinding, + .vertexAttributeDescriptionCount = 3, + .pVertexAttributeDescriptions = vertexInputAttributs}; #ifdef VKVG_WIRED_DEBUG - VkShaderModule modVert, modFrag, modFragWired; + VkShaderModule modVert, modFrag, modFragWired; #else - VkShaderModule modVert, modFrag; + VkShaderModule modVert, modFrag; #endif - VkShaderModuleCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .pCode = (uint32_t*)vkvg_main_vert_spv, - .codeSize = vkvg_main_vert_spv_len }; - VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modVert)); + VkShaderModuleCreateInfo createInfo = {.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pCode = (uint32_t *)vkvg_main_vert_spv, + .codeSize = vkvg_main_vert_spv_len}; + VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modVert)); #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - createInfo.pCode = (uint32_t*)vkvg_main_lcd_frag_spv; - createInfo.codeSize = vkvg_main_lcd_frag_spv_len; + createInfo.pCode = (uint32_t *)vkvg_main_lcd_frag_spv; + createInfo.codeSize = vkvg_main_lcd_frag_spv_len; #else - createInfo.pCode = (uint32_t*)vkvg_main_frag_spv; - createInfo.codeSize = vkvg_main_frag_spv_len; + createInfo.pCode = (uint32_t *)vkvg_main_frag_spv; + createInfo.codeSize = vkvg_main_frag_spv_len; #endif - VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modFrag)); - - VkPipelineShaderStageCreateInfo vertStage = { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = modVert, - .pName = "main", - }; - VkPipelineShaderStageCreateInfo fragStage = { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = modFrag, - .pName = "main", - }; - - // Use specialization constants to pass number of samples to the shader (used for MSAA resolve) - /*VkSpecializationMapEntry specializationEntry = { - .constantID = 0, - .offset = 0, - .size = sizeof(uint32_t)}; - uint32_t specializationData = VKVG_SAMPLES; - VkSpecializationInfo specializationInfo = { - .mapEntryCount = 1, - .pMapEntries = &specializationEntry, - .dataSize = sizeof(specializationData), - .pData = &specializationData};*/ - - VkPipelineShaderStageCreateInfo shaderStages[] = {vertStage,fragStage}; - - pipelineCreateInfo.stageCount = 1; - pipelineCreateInfo.pStages = shaderStages; - pipelineCreateInfo.pVertexInputState = &vertexInputState; - pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; - pipelineCreateInfo.pViewportState = &viewportState; - pipelineCreateInfo.pRasterizationState = &rasterizationState; - pipelineCreateInfo.pMultisampleState = &multisampleState; - pipelineCreateInfo.pColorBlendState = &colorBlendState; - pipelineCreateInfo.pDepthStencilState = &dsStateCreateInfo; - pipelineCreateInfo.pDynamicState = &dynamicState; - pipelineCreateInfo.layout = dev->pipelineLayout; + VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modFrag)); + + VkPipelineShaderStageCreateInfo vertStage = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = modVert, + .pName = "main", + }; + VkPipelineShaderStageCreateInfo fragStage = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = modFrag, + .pName = "main", + }; + + // Use specialization constants to pass number of samples to the shader (used for MSAA resolve) + /*VkSpecializationMapEntry specializationEntry = { + .constantID = 0, + .offset = 0, + .size = sizeof(uint32_t)}; + uint32_t specializationData = VKVG_SAMPLES; + VkSpecializationInfo specializationInfo = { + .mapEntryCount = 1, + .pMapEntries = &specializationEntry, + .dataSize = sizeof(specializationData), + .pData = &specializationData};*/ + + VkPipelineShaderStageCreateInfo shaderStages[] = {vertStage, fragStage}; + + pipelineCreateInfo.stageCount = 1; + pipelineCreateInfo.pStages = shaderStages; + pipelineCreateInfo.pVertexInputState = &vertexInputState; + pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; + pipelineCreateInfo.pViewportState = &viewportState; + pipelineCreateInfo.pRasterizationState = &rasterizationState; + pipelineCreateInfo.pMultisampleState = &multisampleState; + pipelineCreateInfo.pColorBlendState = &colorBlendState; + pipelineCreateInfo.pDepthStencilState = &dsStateCreateInfo; + pipelineCreateInfo.pDynamicState = &dynamicState; + pipelineCreateInfo.layout = dev->pipelineLayout; #ifndef __APPLE__ - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelinePolyFill)); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, + &dev->pipelinePolyFill)); #endif - inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - dsStateCreateInfo.back = dsStateCreateInfo.front = clipingOpState; - dynamicState.dynamicStateCount = 5; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelineClipping)); - - dsStateCreateInfo.back = dsStateCreateInfo.front = stencilOpState; - blendAttachmentState.colorWriteMask=0xf; - dynamicState.dynamicStateCount = 3; - pipelineCreateInfo.stageCount = 2; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_OVER)); - - blendAttachmentState.alphaBlendOp = blendAttachmentState.colorBlendOp = VK_BLEND_OP_SUBTRACT; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_SUB)); - - colorBlendState.logicOpEnable = VK_TRUE; - blendAttachmentState.blendEnable = VK_FALSE; - colorBlendState.logicOp = VK_LOGIC_OP_CLEAR; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_CLEAR)); - + inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + dsStateCreateInfo.back = dsStateCreateInfo.front = clipingOpState; + dynamicState.dynamicStateCount = 5; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, + &dev->pipelineClipping)); + + dsStateCreateInfo.back = dsStateCreateInfo.front = stencilOpState; + blendAttachmentState.colorWriteMask = 0xf; + dynamicState.dynamicStateCount = 3; + pipelineCreateInfo.stageCount = 2; + VK_CHECK_RESULT( + vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_OVER)); + + blendAttachmentState.alphaBlendOp = blendAttachmentState.colorBlendOp = VK_BLEND_OP_SUBTRACT; + VK_CHECK_RESULT( + vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_SUB)); + + colorBlendState.logicOpEnable = VK_TRUE; + blendAttachmentState.blendEnable = VK_FALSE; + colorBlendState.logicOp = VK_LOGIC_OP_CLEAR; + VK_CHECK_RESULT( + vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_CLEAR)); #ifdef VKVG_WIRED_DEBUG - colorBlendState.logicOpEnable = VK_FALSE; - blendAttachmentState.blendEnable = VK_TRUE; - colorBlendState.logicOp = VK_LOGIC_OP_CLEAR; + colorBlendState.logicOpEnable = VK_FALSE; + blendAttachmentState.blendEnable = VK_TRUE; + colorBlendState.logicOp = VK_LOGIC_OP_CLEAR; - createInfo.pCode = (uint32_t*)wired_frag_spv; + createInfo.pCode = (uint32_t *)wired_frag_spv; - createInfo.codeSize = wired_frag_spv_len; - VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modFragWired)); + createInfo.codeSize = wired_frag_spv_len; + VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modFragWired)); - shaderStages[1].module = modFragWired; + shaderStages[1].module = modFragWired; - rasterizationState.polygonMode = VK_POLYGON_MODE_LINE; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelineLineList)); + rasterizationState.polygonMode = VK_POLYGON_MODE_LINE; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, + &dev->pipelineLineList)); - inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; - rasterizationState.polygonMode = VK_POLYGON_MODE_FILL; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelineWired)); + inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + rasterizationState.polygonMode = VK_POLYGON_MODE_FILL; + VK_CHECK_RESULT( + vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelineWired)); - vkDestroyShaderModule(dev->vkDev, modFragWired, NULL); + vkDestroyShaderModule(dev->vkDev, modFragWired, NULL); #endif - vkDestroyShaderModule(dev->vkDev, modVert, NULL); - vkDestroyShaderModule(dev->vkDev, modFrag, NULL); + vkDestroyShaderModule(dev->vkDev, modVert, NULL); + vkDestroyShaderModule(dev->vkDev, modFrag, NULL); } -void _device_createDescriptorSetLayout (VkvgDevice dev) { - - VkDescriptorSetLayoutBinding dsLayoutBinding = - {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1,VK_SHADER_STAGE_FRAGMENT_BIT, NULL}; - VkDescriptorSetLayoutCreateInfo dsLayoutCreateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .bindingCount = 1, - .pBindings = &dsLayoutBinding }; - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslFont)); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslSrc)); - dsLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslGrad)); - - VkPushConstantRange pushConstantRange[] = { - {VK_SHADER_STAGE_VERTEX_BIT,0,sizeof(push_constants)}, - //{VK_SHADER_STAGE_FRAGMENT_BIT,0,sizeof(push_constants)} - }; - VkDescriptorSetLayout dsls[] = {dev->dslFont,dev->dslSrc,dev->dslGrad}; - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .pushConstantRangeCount = 1, - .pPushConstantRanges = (VkPushConstantRange*)&pushConstantRange, - .setLayoutCount = 3, - .pSetLayouts = dsls }; - VK_CHECK_RESULT(vkCreatePipelineLayout(dev->vkDev, &pipelineLayoutCreateInfo, NULL, &dev->pipelineLayout)); +void _device_createDescriptorSetLayout(VkvgDevice dev) { + + VkDescriptorSetLayoutBinding dsLayoutBinding = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, + VK_SHADER_STAGE_FRAGMENT_BIT, NULL}; + VkDescriptorSetLayoutCreateInfo dsLayoutCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .bindingCount = 1, .pBindings = &dsLayoutBinding}; + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslFont)); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslSrc)); + dsLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslGrad)); + + VkPushConstantRange pushConstantRange[] = { + {VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push_constants)}, + //{VK_SHADER_STAGE_FRAGMENT_BIT,0,sizeof(push_constants)} + }; + VkDescriptorSetLayout dsls[] = {dev->dslFont, dev->dslSrc, dev->dslGrad}; + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pushConstantRangeCount = 1, + .pPushConstantRanges = + (VkPushConstantRange *)&pushConstantRange, + .setLayoutCount = 3, + .pSetLayouts = dsls}; + VK_CHECK_RESULT(vkCreatePipelineLayout(dev->vkDev, &pipelineLayoutCreateInfo, NULL, &dev->pipelineLayout)); } -void _device_wait_idle (VkvgDevice dev) { - vkDeviceWaitIdle (dev->vkDev); -} -void _device_wait_and_reset_device_fence (VkvgDevice dev) { - vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); - ResetFences (dev->vkDev, 1, &dev->fence); +void _device_wait_idle(VkvgDevice dev) { vkDeviceWaitIdle(dev->vkDev); } +void _device_wait_and_reset_device_fence(VkvgDevice dev) { + vkWaitForFences(dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); + ResetFences(dev->vkDev, 1, &dev->fence); } -bool _device_try_get_cached_context (VkvgDevice dev, VkvgContext* pCtx) { - LOCK_DEVICE - - if (dev->cachedContextCount) { - thrd_t curThread = thrd_current (); - _cached_ctx* prev = NULL; - _cached_ctx* cur = dev->cachedContextLast; - while (cur) { - if (thrd_equal (cur->thread, curThread)) { - if (prev) - prev->pNext = cur->pNext; - else - dev->cachedContextLast = cur->pNext; - - dev->cachedContextCount--; - - LOG(VKVG_LOG_THREAD,"get cached context: %p, thd:%lu cached ctx: %d\n", cur->ctx, cur->thread, dev->cachedContextCount); - - *pCtx = cur->ctx; - free (cur); - UNLOCK_DEVICE - return true; - } - prev = cur; - cur = cur->pNext; - } - } - *pCtx = NULL; - UNLOCK_DEVICE - return false; +bool _device_try_get_cached_context(VkvgDevice dev, VkvgContext *pCtx) { + LOCK_DEVICE + + if (dev->cachedContextCount) { + thrd_t curThread = thrd_current(); + _cached_ctx *prev = NULL; + _cached_ctx *cur = dev->cachedContextLast; + while (cur) { + if (thrd_equal(cur->thread, curThread)) { + if (prev) + prev->pNext = cur->pNext; + else + dev->cachedContextLast = cur->pNext; + + dev->cachedContextCount--; + + LOG(VKVG_LOG_THREAD, "get cached context: %p, thd:%lu cached ctx: %d\n", cur->ctx, cur->thread, + dev->cachedContextCount); + + *pCtx = cur->ctx; + free(cur); + UNLOCK_DEVICE + return true; + } + prev = cur; + cur = cur->pNext; + } + } + *pCtx = NULL; + UNLOCK_DEVICE + return false; } -void _device_store_context (VkvgContext ctx) { - VkvgDevice dev = ctx->dev; +void _device_store_context(VkvgContext ctx) { + VkvgDevice dev = ctx->dev; - LOCK_DEVICE + LOCK_DEVICE - _cached_ctx* cur = (_cached_ctx*)calloc(1, sizeof(_cached_ctx)); - cur->ctx = ctx; - cur->thread = thrd_current (); - cur->pNext = dev->cachedContextLast; + _cached_ctx *cur = (_cached_ctx *)calloc(1, sizeof(_cached_ctx)); + cur->ctx = ctx; + cur->thread = thrd_current(); + cur->pNext = dev->cachedContextLast; - dev->cachedContextLast = cur; - dev->cachedContextCount++; + dev->cachedContextLast = cur; + dev->cachedContextCount++; - LOG(VKVG_LOG_THREAD,"store context: %p, thd:%lu cached ctx: %d\n", cur->ctx, cur->thread, dev->cachedContextCount); + LOG(VKVG_LOG_THREAD, "store context: %p, thd:%lu cached ctx: %d\n", cur->ctx, cur->thread, dev->cachedContextCount); - ctx->references++; + ctx->references++; - UNLOCK_DEVICE + UNLOCK_DEVICE } -void _device_submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, VkFence fence) { - LOCK_DEVICE - vkh_cmd_submit (dev->gQueue, cmd, fence); - UNLOCK_DEVICE +void _device_submit_cmd(VkvgDevice dev, VkCommandBuffer *cmd, VkFence fence) { + LOCK_DEVICE + vkh_cmd_submit(dev->gQueue, cmd, fence); + UNLOCK_DEVICE } -bool _device_init_function_pointers (VkvgDevice dev) { -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - if (vkGetInstanceProcAddr(dev->instance, "vkSetDebugUtilsObjectNameEXT")==VK_NULL_HANDLE){ - LOG(VKVG_LOG_ERR, "vkvg create device failed: 'VK_EXT_debug_utils' has to be loaded for Debug build\n"); - return false; - } - vkh_device_init_debug_utils ((VkhDevice)dev); +bool _device_init_function_pointers(VkvgDevice dev) { +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + if (vkGetInstanceProcAddr(dev->instance, "vkSetDebugUtilsObjectNameEXT") == VK_NULL_HANDLE) { + LOG(VKVG_LOG_ERR, "vkvg create device failed: 'VK_EXT_debug_utils' has to be loaded for Debug build\n"); + return false; + } + vkh_device_init_debug_utils((VkhDevice)dev); #endif - CmdBindPipeline = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindPipeline); - CmdBindDescriptorSets = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindDescriptorSets); - CmdBindIndexBuffer = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindIndexBuffer); - CmdBindVertexBuffers = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindVertexBuffers); - CmdDrawIndexed = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdDrawIndexed); - CmdDraw = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdDraw); - CmdSetStencilCompareMask= GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilCompareMask); - CmdSetStencilReference = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilReference); - CmdSetStencilWriteMask = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilWriteMask); - CmdBeginRenderPass = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBeginRenderPass); - CmdEndRenderPass = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdEndRenderPass); - CmdSetViewport = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetViewport); - CmdSetScissor = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetScissor); - CmdPushConstants = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdPushConstants); - WaitForFences = GetVkProcAddress(dev->vkDev, dev->instance, vkWaitForFences); - ResetFences = GetVkProcAddress(dev->vkDev, dev->instance, vkResetFences); - ResetCommandBuffer = GetVkProcAddress(dev->vkDev, dev->instance, vkResetCommandBuffer); - return true; + CmdBindPipeline = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindPipeline); + CmdBindDescriptorSets = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindDescriptorSets); + CmdBindIndexBuffer = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindIndexBuffer); + CmdBindVertexBuffers = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindVertexBuffers); + CmdDrawIndexed = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdDrawIndexed); + CmdDraw = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdDraw); + CmdSetStencilCompareMask = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilCompareMask); + CmdSetStencilReference = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilReference); + CmdSetStencilWriteMask = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilWriteMask); + CmdBeginRenderPass = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBeginRenderPass); + CmdEndRenderPass = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdEndRenderPass); + CmdSetViewport = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetViewport); + CmdSetScissor = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetScissor); + CmdPushConstants = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdPushConstants); + WaitForFences = GetVkProcAddress(dev->vkDev, dev->instance, vkWaitForFences); + ResetFences = GetVkProcAddress(dev->vkDev, dev->instance, vkResetFences); + ResetCommandBuffer = GetVkProcAddress(dev->vkDev, dev->instance, vkResetCommandBuffer); + return true; } -void _device_create_empty_texture (VkvgDevice dev, VkFormat format, VkImageTiling tiling) { - //create empty image to bind to context source descriptor when not in use - dev->emptyImg = vkh_image_create((VkhDevice)dev,format,16,16,tiling,VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - vkh_image_create_descriptor(dev->emptyImg, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); - - _device_wait_and_reset_device_fence (dev); - - vkh_cmd_begin (dev->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (dev->cmd, dev->emptyImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - vkh_cmd_end (dev->cmd); - _device_submit_cmd (dev, &dev->cmd, dev->fence); +void _device_create_empty_texture(VkvgDevice dev, VkFormat format, VkImageTiling tiling) { + // create empty image to bind to context source descriptor when not in use + dev->emptyImg = vkh_image_create((VkhDevice)dev, format, 16, 16, tiling, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + vkh_image_create_descriptor(dev->emptyImg, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); + + _device_wait_and_reset_device_fence(dev); + + vkh_cmd_begin(dev->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(dev->cmd, dev->emptyImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + vkh_cmd_end(dev->cmd); + _device_submit_cmd(dev, &dev->cmd, dev->fence); } -void _device_check_best_image_tiling (VkvgDevice dev, VkFormat format) { - VkFlags stencilFormats[] = { VK_FORMAT_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT }; - VkFormatProperties phyStencilProps = { 0 }, phyImgProps = { 0 }; - - //check png blit format - VkFlags pngBlitFormats[] = { VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_R8G8B8A8_UNORM}; - dev->pngStagFormat = VK_FORMAT_UNDEFINED; - for (int i = 0; i < 2; i++) - { - vkGetPhysicalDeviceFormatProperties(dev->phy, pngBlitFormats[i], &phyImgProps); - if ((phyImgProps.linearTilingFeatures & VKVG_PNG_WRITE_IMG_REQUIREMENTS) == VKVG_PNG_WRITE_IMG_REQUIREMENTS) { - dev->pngStagFormat = pngBlitFormats[i]; - dev->pngStagTiling = VK_IMAGE_TILING_LINEAR; - break; - } else if ((phyImgProps.optimalTilingFeatures & VKVG_PNG_WRITE_IMG_REQUIREMENTS) == VKVG_PNG_WRITE_IMG_REQUIREMENTS) { - dev->pngStagFormat = pngBlitFormats[i]; - dev->pngStagTiling = VK_IMAGE_TILING_OPTIMAL; - break; - } - } - - if (dev->pngStagFormat == VK_FORMAT_UNDEFINED) - LOG(VKVG_LOG_DEBUG, "vkvg create device failed: no suitable image format for png write\n"); - - dev->stencilFormat = VK_FORMAT_UNDEFINED; - dev->stencilAspectFlag = VK_IMAGE_ASPECT_STENCIL_BIT; - dev->supportedTiling = 0xff; - - vkGetPhysicalDeviceFormatProperties(dev->phy, format, &phyImgProps); - - if ((phyImgProps.optimalTilingFeatures & VKVG_SURFACE_IMGS_REQUIREMENTS) == VKVG_SURFACE_IMGS_REQUIREMENTS) { - for (int i = 0; i < 4; i++) - { - vkGetPhysicalDeviceFormatProperties(dev->phy, stencilFormats[i], &phyStencilProps); - if (phyStencilProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { - dev->stencilFormat = stencilFormats[i]; - if (i > 0) - dev->stencilAspectFlag |= VK_IMAGE_ASPECT_DEPTH_BIT; - dev->supportedTiling = VK_IMAGE_TILING_OPTIMAL; - return; - } - } - } - if ((phyImgProps.linearTilingFeatures & VKVG_SURFACE_IMGS_REQUIREMENTS) == VKVG_SURFACE_IMGS_REQUIREMENTS) { - for (int i = 0; i < 4; i++) - { - vkGetPhysicalDeviceFormatProperties(dev->phy, stencilFormats[i], &phyStencilProps); - if (phyStencilProps.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { - dev->stencilFormat = stencilFormats[i]; - if (i > 0) - dev->stencilAspectFlag |= VK_IMAGE_ASPECT_DEPTH_BIT; - dev->supportedTiling = VK_IMAGE_TILING_LINEAR; - return; - } - } - } - dev->status = VKVG_STATUS_INVALID_FORMAT; - LOG(VKVG_LOG_ERR, "vkvg create device failed: image format not supported: %d\n", format); +void _device_check_best_image_tiling(VkvgDevice dev, VkFormat format) { + VkFlags stencilFormats[] = {VK_FORMAT_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D32_SFLOAT_S8_UINT}; + VkFormatProperties phyStencilProps = {0}, phyImgProps = {0}; + + // check png blit format + VkFlags pngBlitFormats[] = {VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_R8G8B8A8_UNORM}; + dev->pngStagFormat = VK_FORMAT_UNDEFINED; + for (int i = 0; i < 2; i++) { + vkGetPhysicalDeviceFormatProperties(dev->phy, pngBlitFormats[i], &phyImgProps); + if ((phyImgProps.linearTilingFeatures & VKVG_PNG_WRITE_IMG_REQUIREMENTS) == VKVG_PNG_WRITE_IMG_REQUIREMENTS) { + dev->pngStagFormat = pngBlitFormats[i]; + dev->pngStagTiling = VK_IMAGE_TILING_LINEAR; + break; + } else if ((phyImgProps.optimalTilingFeatures & VKVG_PNG_WRITE_IMG_REQUIREMENTS) == + VKVG_PNG_WRITE_IMG_REQUIREMENTS) { + dev->pngStagFormat = pngBlitFormats[i]; + dev->pngStagTiling = VK_IMAGE_TILING_OPTIMAL; + break; + } + } + + if (dev->pngStagFormat == VK_FORMAT_UNDEFINED) + LOG(VKVG_LOG_DEBUG, "vkvg create device failed: no suitable image format for png write\n"); + + dev->stencilFormat = VK_FORMAT_UNDEFINED; + dev->stencilAspectFlag = VK_IMAGE_ASPECT_STENCIL_BIT; + dev->supportedTiling = 0xff; + + vkGetPhysicalDeviceFormatProperties(dev->phy, format, &phyImgProps); + + if ((phyImgProps.optimalTilingFeatures & VKVG_SURFACE_IMGS_REQUIREMENTS) == VKVG_SURFACE_IMGS_REQUIREMENTS) { + for (int i = 0; i < 4; i++) { + vkGetPhysicalDeviceFormatProperties(dev->phy, stencilFormats[i], &phyStencilProps); + if (phyStencilProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { + dev->stencilFormat = stencilFormats[i]; + if (i > 0) + dev->stencilAspectFlag |= VK_IMAGE_ASPECT_DEPTH_BIT; + dev->supportedTiling = VK_IMAGE_TILING_OPTIMAL; + return; + } + } + } + if ((phyImgProps.linearTilingFeatures & VKVG_SURFACE_IMGS_REQUIREMENTS) == VKVG_SURFACE_IMGS_REQUIREMENTS) { + for (int i = 0; i < 4; i++) { + vkGetPhysicalDeviceFormatProperties(dev->phy, stencilFormats[i], &phyStencilProps); + if (phyStencilProps.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { + dev->stencilFormat = stencilFormats[i]; + if (i > 0) + dev->stencilAspectFlag |= VK_IMAGE_ASPECT_DEPTH_BIT; + dev->supportedTiling = VK_IMAGE_TILING_LINEAR; + return; + } + } + } + dev->status = VKVG_STATUS_INVALID_FORMAT; + LOG(VKVG_LOG_ERR, "vkvg create device failed: image format not supported: %d\n", format); } -void _dump_image_format_properties (VkvgDevice dev, VkFormat format) { - /*VkImageFormatProperties imgProps; - VK_CHECK_RESULT(vkGetPhysicalDeviceImageFormatProperties(dev->phy, - format, VK_IMAGE_TYPE_2D, VKVG_TILING, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT, - 0, &imgProps)); - printf ("tiling = %d\n", VKVG_TILING); - printf ("max extend = (%d, %d, %d)\n", imgProps.maxExtent.width, imgProps.maxExtent.height, imgProps.maxExtent.depth); - printf ("max mip levels = %d\n", imgProps.maxMipLevels); - printf ("max array layers = %d\n", imgProps.maxArrayLayers); - printf ("sample counts = "); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_1_BIT) - printf ("1,"); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_2_BIT) - printf ("2,"); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_4_BIT) - printf ("4,"); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_8_BIT) - printf ("8,"); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_16_BIT) - printf ("16,"); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_32_BIT) - printf ("32,"); - printf ("\n"); - printf ("max resource size= %lu\n", imgProps.maxResourceSize); +void _dump_image_format_properties(VkvgDevice dev, VkFormat format) { + /*VkImageFormatProperties imgProps; + VK_CHECK_RESULT(vkGetPhysicalDeviceImageFormatProperties(dev->phy, + format, VK_IMAGE_TYPE_2D, VKVG_TILING, + VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT, + 0, &imgProps)); + printf ("tiling = %d\n", VKVG_TILING); + printf ("max extend = (%d, %d, %d)\n", imgProps.maxExtent.width, imgProps.maxExtent.height, + imgProps.maxExtent.depth); printf ("max mip levels = %d\n", imgProps.maxMipLevels); printf ("max array layers = + %d\n", imgProps.maxArrayLayers); printf ("sample counts = "); if (imgProps.sampleCounts & VK_SAMPLE_COUNT_1_BIT) + printf ("1,"); + if (imgProps.sampleCounts & VK_SAMPLE_COUNT_2_BIT) + printf ("2,"); + if (imgProps.sampleCounts & VK_SAMPLE_COUNT_4_BIT) + printf ("4,"); + if (imgProps.sampleCounts & VK_SAMPLE_COUNT_8_BIT) + printf ("8,"); + if (imgProps.sampleCounts & VK_SAMPLE_COUNT_16_BIT) + printf ("16,"); + if (imgProps.sampleCounts & VK_SAMPLE_COUNT_32_BIT) + printf ("32,"); + printf ("\n"); + printf ("max resource size= %lu\n", imgProps.maxResourceSize); */ - } diff --git a/src/vkvg_device_internal.h b/src/vkvg_device_internal.h index ef8c95f..d17eae1 100644 --- a/src/vkvg_device_internal.h +++ b/src/vkvg_device_internal.h @@ -25,128 +25,132 @@ #include "vkvg_internal.h" #include "vkvg_fonts.h" -#define STENCIL_FILL_BIT 0x1 -#define STENCIL_CLIP_BIT 0x2 -#define STENCIL_ALL_BIT 0x3 +#define STENCIL_FILL_BIT 0x1 +#define STENCIL_CLIP_BIT 0x2 +#define STENCIL_ALL_BIT 0x3 #define VKVG_MAX_CACHED_CONTEXT_COUNT 2 -extern PFN_vkCmdBindPipeline CmdBindPipeline; -extern PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets; -extern PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer; -extern PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers; - -extern PFN_vkCmdDrawIndexed CmdDrawIndexed; -extern PFN_vkCmdDraw CmdDraw; - -extern PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask; -extern PFN_vkCmdSetStencilReference CmdSetStencilReference; -extern PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask; -extern PFN_vkCmdBeginRenderPass CmdBeginRenderPass; -extern PFN_vkCmdEndRenderPass CmdEndRenderPass; -extern PFN_vkCmdSetViewport CmdSetViewport; -extern PFN_vkCmdSetScissor CmdSetScissor; - -extern PFN_vkCmdPushConstants CmdPushConstants; -extern PFN_vkWaitForFences WaitForFences; -extern PFN_vkResetFences ResetFences; -extern PFN_vkResetCommandBuffer ResetCommandBuffer; - -typedef struct _cached_ctx{ - thrd_t thread; - VkvgContext ctx; - struct _cached_ctx* pNext; +extern PFN_vkCmdBindPipeline CmdBindPipeline; +extern PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets; +extern PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer; +extern PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers; + +extern PFN_vkCmdDrawIndexed CmdDrawIndexed; +extern PFN_vkCmdDraw CmdDraw; + +extern PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask; +extern PFN_vkCmdSetStencilReference CmdSetStencilReference; +extern PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask; +extern PFN_vkCmdBeginRenderPass CmdBeginRenderPass; +extern PFN_vkCmdEndRenderPass CmdEndRenderPass; +extern PFN_vkCmdSetViewport CmdSetViewport; +extern PFN_vkCmdSetScissor CmdSetScissor; + +extern PFN_vkCmdPushConstants CmdPushConstants; +extern PFN_vkWaitForFences WaitForFences; +extern PFN_vkResetFences ResetFences; +extern PFN_vkResetCommandBuffer ResetCommandBuffer; + +typedef struct _cached_ctx { + thrd_t thread; + VkvgContext ctx; + struct _cached_ctx *pNext; } _cached_ctx; typedef struct _vkvg_device_t { - VkDevice vkDev; /**< Vulkan Logical Device */ - VkPhysicalDeviceMemoryProperties phyMemProps; /**< Vulkan Physical device memory properties */ - VkPhysicalDevice phy; /**< Vulkan Physical device */ - VkInstance instance; /**< Vulkan instance */ + VkDevice vkDev; /**< Vulkan Logical Device */ + VkPhysicalDeviceMemoryProperties phyMemProps; /**< Vulkan Physical device memory properties */ + VkPhysicalDevice phy; /**< Vulkan Physical device */ + VkInstance instance; /**< Vulkan instance */ #ifdef VKH_USE_VMA - void* allocator; /**< Vulkan Memory allocator */ + void *allocator; /**< Vulkan Memory allocator */ #endif - VkImageTiling supportedTiling; /**< Supported image tiling for surface, 0xFF=no support */ - VkFormat stencilFormat; /**< Supported vulkan image format for stencil */ - VkImageAspectFlags stencilAspectFlag; /**< stencil only or depth stencil, could be solved by VK_KHR_separate_depth_stencil_layouts*/ - VkFormat pngStagFormat; /**< Supported vulkan image format png write staging img */ - VkImageTiling pngStagTiling; /**< tiling for the blit operation */ + VkImageTiling supportedTiling; /**< Supported image tiling for surface, 0xFF=no support */ + VkFormat stencilFormat; /**< Supported vulkan image format for stencil */ + VkImageAspectFlags stencilAspectFlag; /**< stencil only or depth stencil, could be solved by + VK_KHR_separate_depth_stencil_layouts*/ + VkFormat pngStagFormat; /**< Supported vulkan image format png write staging img */ + VkImageTiling pngStagTiling; /**< tiling for the blit operation */ - mtx_t mutex; /**< protect device access (queue, cahes, ...)from ctxs in separate threads */ - bool threadAware; /**< if true, mutex is created and guard device queue and caches access */ - VkhQueue gQueue; /**< Vulkan Queue with Graphic flag */ + mtx_t mutex; /**< protect device access (queue, cahes, ...)from ctxs in separate threads */ + bool threadAware; /**< if true, mutex is created and guard device queue and caches access */ + VkhQueue gQueue; /**< Vulkan Queue with Graphic flag */ - VkRenderPass renderPass; /**< Vulkan render pass, common for all surfaces */ - VkRenderPass renderPass_ClearStencil;/**< Vulkan render pass for first draw with context, stencil has to be cleared */ - VkRenderPass renderPass_ClearAll; /**< Vulkan render pass for new surface, clear all attacments*/ + VkRenderPass renderPass; /**< Vulkan render pass, common for all surfaces */ + VkRenderPass + renderPass_ClearStencil; /**< Vulkan render pass for first draw with context, stencil has to be cleared */ + VkRenderPass renderPass_ClearAll; /**< Vulkan render pass for new surface, clear all attacments*/ - uint32_t references; /**< Reference count, prevent destroying device if still in use */ - VkCommandPool cmdPool; /**< Global command pool for processing on surfaces without context */ - VkCommandBuffer cmd; /**< Global command buffer */ - VkFence fence; /**< this fence is kept signaled when idle, wait and reset are called before each recording. */ + uint32_t references; /**< Reference count, prevent destroying device if still in use */ + VkCommandPool cmdPool; /**< Global command pool for processing on surfaces without context */ + VkCommandBuffer cmd; /**< Global command buffer */ + VkFence fence; /**< this fence is kept signaled when idle, wait and reset are called before each recording. */ - VkPipeline pipe_OVER; /**< default operator */ - VkPipeline pipe_SUB; - VkPipeline pipe_CLEAR; /**< clear operator */ + VkPipeline pipe_OVER; /**< default operator */ + VkPipeline pipe_SUB; + VkPipeline pipe_CLEAR; /**< clear operator */ - VkPipeline pipelinePolyFill; /**< even-odd polygon filling first step */ - VkPipeline pipelineClipping; /**< draw on stencil to update clipping regions */ + VkPipeline pipelinePolyFill; /**< even-odd polygon filling first step */ + VkPipeline pipelineClipping; /**< draw on stencil to update clipping regions */ - VkPipelineCache pipelineCache; /**< speed up startup by caching configured pipelines on disk */ - VkPipelineLayout pipelineLayout; /**< layout common to all pipelines */ - VkDescriptorSetLayout dslFont; /**< font cache descriptors layout */ - VkDescriptorSetLayout dslSrc; /**< context source surface descriptors layout */ - VkDescriptorSetLayout dslGrad; /**< context gradient descriptors layout */ + VkPipelineCache pipelineCache; /**< speed up startup by caching configured pipelines on disk */ + VkPipelineLayout pipelineLayout; /**< layout common to all pipelines */ + VkDescriptorSetLayout dslFont; /**< font cache descriptors layout */ + VkDescriptorSetLayout dslSrc; /**< context source surface descriptors layout */ + VkDescriptorSetLayout dslGrad; /**< context gradient descriptors layout */ - int hdpi, /**< only used for FreeType fonts and svg loading */ - vdpi; + int hdpi, /**< only used for FreeType fonts and svg loading */ + vdpi; - VkhDevice vkhDev; /**< old VkhDev created during vulkan context creation by @ref vkvg_device_create. */ + VkhDevice vkhDev; /**< old VkhDev created during vulkan context creation by @ref vkvg_device_create. */ - VkhImage emptyImg; /**< prevent unbound descriptor to trigger Validation error 61 */ - VkSampleCountFlags samples; /**< samples count common to all surfaces */ - bool deferredResolve; /**< if true, resolve only on context destruction and set as source */ - vkvg_status_t status; /**< Current status of device, affected by last operation */ + VkhImage emptyImg; /**< prevent unbound descriptor to trigger Validation error 61 */ + VkSampleCountFlags samples; /**< samples count common to all surfaces */ + bool deferredResolve; /**< if true, resolve only on context destruction and set as source */ + vkvg_status_t status; /**< Current status of device, affected by last operation */ - _font_cache_t* fontCache; /**< Store everything relative to common font caching system */ + _font_cache_t *fontCache; /**< Store everything relative to common font caching system */ - VkvgContext lastCtx; /**< last element of double linked list of context, used to trigger font caching system update on all contexts*/ + VkvgContext lastCtx; /**< last element of double linked list of context, used to trigger font caching system update + on all contexts*/ - int32_t cachedContextMaxCount; /**< Maximum context cache element count.*/ - int32_t cachedContextCount; /**< Current context cache element count.*/ - _cached_ctx* cachedContextLast; /**< Last element of single linked list of saved context for fast reuse.*/ + int32_t cachedContextMaxCount; /**< Maximum context cache element count.*/ + int32_t cachedContextCount; /**< Current context cache element count.*/ + _cached_ctx *cachedContextLast; /**< Last element of single linked list of saved context for fast reuse.*/ #ifdef VKVG_WIRED_DEBUG - VkPipeline pipelineWired; - VkPipeline pipelineLineList; + VkPipeline pipelineWired; + VkPipeline pipelineLineList; #endif #if VKVG_DBG_STATS - vkvg_debug_stats_t debug_stats; /**< debug statistics on memory usage and vulkan ressources */ + vkvg_debug_stats_t debug_stats; /**< debug statistics on memory usage and vulkan ressources */ #endif -}vkvg_device; - -#define LOCK_DEVICE \ - if (dev->threadAware)\ - mtx_lock (&dev->mutex); -#define UNLOCK_DEVICE \ - if (dev->threadAware)\ - mtx_unlock (&dev->mutex); - -bool _device_try_get_phyinfo (VkhPhyInfo* phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo* phy); -bool _device_init_function_pointers (VkvgDevice dev); -void _device_create_empty_texture (VkvgDevice dev, VkFormat format, VkImageTiling tiling); -void _device_get_best_image_tiling (VkvgDevice dev, VkFormat format, VkImageTiling* pTiling); -void _device_check_best_image_tiling (VkvgDevice dev, VkFormat format); -void _device_create_pipeline_cache (VkvgDevice dev); -VkRenderPass _device_createRenderPassMS (VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp); -VkRenderPass _device_createRenderPassNoResolve(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp); -void _device_setupPipelines (VkvgDevice dev); -void _device_createDescriptorSetLayout (VkvgDevice dev); -void _device_wait_idle (VkvgDevice dev); -void _device_wait_and_reset_device_fence(VkvgDevice dev); -void _device_submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, VkFence fence); - -bool _device_try_get_cached_context (VkvgDevice dev, VkvgContext* pCtx); -void _device_store_context (VkvgContext ctx); +} vkvg_device; + +#define LOCK_DEVICE \ + if (dev->threadAware) \ + mtx_lock(&dev->mutex); +#define UNLOCK_DEVICE \ + if (dev->threadAware) \ + mtx_unlock(&dev->mutex); + +bool _device_try_get_phyinfo(VkhPhyInfo *phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo *phy); +bool _device_init_function_pointers(VkvgDevice dev); +void _device_create_empty_texture(VkvgDevice dev, VkFormat format, VkImageTiling tiling); +void _device_get_best_image_tiling(VkvgDevice dev, VkFormat format, VkImageTiling *pTiling); +void _device_check_best_image_tiling(VkvgDevice dev, VkFormat format); +void _device_create_pipeline_cache(VkvgDevice dev); +VkRenderPass _device_createRenderPassMS(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp); +VkRenderPass _device_createRenderPassNoResolve(VkvgDevice dev, VkAttachmentLoadOp loadOp, + VkAttachmentLoadOp stencilLoadOp); +void _device_setupPipelines(VkvgDevice dev); +void _device_createDescriptorSetLayout(VkvgDevice dev); +void _device_wait_idle(VkvgDevice dev); +void _device_wait_and_reset_device_fence(VkvgDevice dev); +void _device_submit_cmd(VkvgDevice dev, VkCommandBuffer *cmd, VkFence fence); + +bool _device_try_get_cached_context(VkvgDevice dev, VkvgContext *pCtx); +void _device_store_context(VkvgContext ctx); #endif diff --git a/src/vkvg_experimental.c b/src/vkvg_experimental.c index 3e3e022..31679c0 100644 --- a/src/vkvg_experimental.c +++ b/src/vkvg_experimental.c @@ -23,6 +23,3 @@ #include #include "vkvg_experimental.h" #include "vkvg_context_internal.h" - - - diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index 35858f3..868f42b 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -32,794 +32,792 @@ #include #ifndef VKVG_USE_FREETYPE - #define STB_TRUETYPE_IMPLEMENTATION - #include "stb_truetype.h" +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb_truetype.h" #endif -static int defaultFontCharSize = 12<<6; +static int defaultFontCharSize = 12 << 6; -void _fonts_cache_create (VkvgDevice dev){ - _font_cache_t* cache = (_font_cache_t*)calloc(1, sizeof(_font_cache_t)); +void _fonts_cache_create(VkvgDevice dev) { + _font_cache_t *cache = (_font_cache_t *)calloc(1, sizeof(_font_cache_t)); - if (dev->threadAware) - mtx_init (&cache->mutex, mtx_plain); + if (dev->threadAware) + mtx_init(&cache->mutex, mtx_plain); #ifdef VKVG_USE_FONTCONFIG - cache->config = FcInitLoadConfigAndFonts (); - if (!cache->config) { - LOG(VKVG_LOG_DEBUG, "Font config initialisation failed, consider using 'FONTCONFIG_PATH' and 'FONTCONFIG_FILE' environmane\ + cache->config = FcInitLoadConfigAndFonts(); + if (!cache->config) { + LOG(VKVG_LOG_DEBUG, + "Font config initialisation failed, consider using 'FONTCONFIG_PATH' and 'FONTCONFIG_FILE' environmane\ variables to point to 'fonts.conf' needed for FontConfig startup"); - assert(cache->config); - } + assert(cache->config); + } #endif #ifdef VKVG_USE_FREETYPE - FT_CHECK_RESULT(FT_Init_FreeType(&cache->library)); + FT_CHECK_RESULT(FT_Init_FreeType(&cache->library)); #endif #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - FT_CHECK_RESULT(FT_Library_SetLcdFilter (cache->library, FT_LCD_FILTER_LIGHT)); - cache->texFormat = FB_COLOR_FORMAT; - cache->texPixelSize = 4; + FT_CHECK_RESULT(FT_Library_SetLcdFilter(cache->library, FT_LCD_FILTER_LIGHT)); + cache->texFormat = FB_COLOR_FORMAT; + cache->texPixelSize = 4; #else - cache->texFormat = VK_FORMAT_R8_UNORM; - cache->texPixelSize = 1; + cache->texFormat = VK_FORMAT_R8_UNORM; + cache->texPixelSize = 1; #endif - cache->texLength = FONT_CACHE_INIT_LAYERS; - cache->texture = vkh_tex2d_array_create ((VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, - cache->texLength ,VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - vkh_image_create_descriptor (cache->texture, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, - VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + cache->texLength = FONT_CACHE_INIT_LAYERS; + cache->texture = vkh_tex2d_array_create( + (VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, cache->texLength, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + vkh_image_create_descriptor(cache->texture, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, + VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); - cache->uploadFence = vkh_fence_create((VkhDevice)dev); + cache->uploadFence = vkh_fence_create((VkhDevice)dev); - const uint32_t buffLength = FONT_PAGE_SIZE*FONT_PAGE_SIZE*cache->texPixelSize; + const uint32_t buffLength = FONT_PAGE_SIZE * FONT_PAGE_SIZE * cache->texPixelSize; - vkh_buffer_init ((VkhDevice)dev, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VKH_MEMORY_USAGE_CPU_TO_GPU, - buffLength, &cache->buff, true); + vkh_buffer_init((VkhDevice)dev, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VKH_MEMORY_USAGE_CPU_TO_GPU, buffLength, + &cache->buff, true); - cache->cmd = vkh_cmd_buff_create((VkhDevice)dev,dev->cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY); + cache->cmd = vkh_cmd_buff_create((VkhDevice)dev, dev->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); - //Set texture cache initial layout to shaderReadOnly to prevent error msg if cache is not fill - const VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,cache->texLength}; - vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _device_submit_cmd (dev, &cache->cmd, cache->uploadFence); + // Set texture cache initial layout to shaderReadOnly to prevent error msg if cache is not fill + const VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, cache->texLength}; + vkh_cmd_begin(cache->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); + _device_submit_cmd(dev, &cache->cmd, cache->uploadFence); - cache->hostBuff = (uint8_t*)malloc(buffLength); - cache->pensY = (int*)calloc(cache->texLength, sizeof(int)); + cache->hostBuff = (uint8_t *)malloc(buffLength); + cache->pensY = (int *)calloc(cache->texLength, sizeof(int)); - dev->fontCache = cache; + dev->fontCache = cache; } -///increase layer count of 2d texture array used as font cache. -void _increase_font_tex_array (VkvgDevice dev){ - LOG(VKVG_LOG_INFO, "_increase_font_tex_array\n"); +/// increase layer count of 2d texture array used as font cache. +void _increase_font_tex_array(VkvgDevice dev) { + LOG(VKVG_LOG_INFO, "_increase_font_tex_array\n"); - _font_cache_t* cache = dev->fontCache; + _font_cache_t *cache = dev->fontCache; - vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); - ResetFences (dev->vkDev, 1, &cache->uploadFence); + vkWaitForFences(dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); + ResetFences(dev->vkDev, 1, &cache->uploadFence); - vkResetCommandBuffer(cache->cmd, 0); + vkResetCommandBuffer(cache->cmd, 0); - uint8_t newSize = cache->texLength + FONT_CACHE_INIT_LAYERS; - VkhImage newImg = vkh_tex2d_array_create ((VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, - newSize ,VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - vkh_image_create_descriptor (newImg, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, - VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + uint8_t newSize = cache->texLength + FONT_CACHE_INIT_LAYERS; + VkhImage newImg = vkh_tex2d_array_create( + (VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, newSize, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + vkh_image_create_descriptor(newImg, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); - VkImageSubresourceRange subresNew = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,newSize}; - VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,cache->texLength}; + VkImageSubresourceRange subresNew = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, newSize}; + VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, cache->texLength}; - vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_cmd_begin(cache->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - VkImageCopy cregion = { .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, - .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, - .extent = {FONT_PAGE_SIZE,FONT_PAGE_SIZE,1}}; + VkImageCopy cregion = {.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, + .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, + .extent = {FONT_PAGE_SIZE, FONT_PAGE_SIZE, 1}}; - vkCmdCopyImage (cache->cmd, vkh_image_get_vkimage (cache->texture), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (newImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); + vkCmdCopyImage(cache->cmd, vkh_image_get_vkimage(cache->texture), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(newImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); - vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); + VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _device_submit_cmd (dev, &cache->cmd, cache->uploadFence); - vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); + _device_submit_cmd(dev, &cache->cmd, cache->uploadFence); + vkWaitForFences(dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); - cache->pensY = (int*)realloc(cache->pensY, newSize * sizeof(int)); - void* tmp = memset (&cache->pensY[cache->texLength],0,FONT_CACHE_INIT_LAYERS*sizeof(int)); + cache->pensY = (int *)realloc(cache->pensY, newSize * sizeof(int)); + void *tmp = memset(&cache->pensY[cache->texLength], 0, FONT_CACHE_INIT_LAYERS * sizeof(int)); - vkh_image_destroy (cache->texture); + vkh_image_destroy(cache->texture); - cache->texLength = newSize; - cache->texture = newImg; + cache->texLength = newSize; + cache->texture = newImg; - _device_wait_idle(dev); + _device_wait_idle(dev); } -//flush font stagging buffer to cache texture array -//Trigger stagging buffer to be uploaded in font cache. Groupping upload improve performances. -void _flush_chars_to_tex (VkvgDevice dev, _vkvg_font_t* f) { +// flush font stagging buffer to cache texture array +// Trigger stagging buffer to be uploaded in font cache. Groupping upload improve performances. +void _flush_chars_to_tex(VkvgDevice dev, _vkvg_font_t *f) { - _font_cache_t* cache = dev->fontCache; - if (cache->stagingX == 0)//no char in stagging buff to flush - return; + _font_cache_t *cache = dev->fontCache; + if (cache->stagingX == 0) // no char in stagging buff to flush + return; - LOG(VKVG_LOG_INFO, "_flush_chars_to_tex pen(%d, %d)\n",f->curLine.penX, f->curLine.penY); - vkWaitForFences (dev->vkDev,1,&cache->uploadFence,VK_TRUE,UINT64_MAX); - ResetFences (dev->vkDev, 1, &cache->uploadFence); + LOG(VKVG_LOG_INFO, "_flush_chars_to_tex pen(%d, %d)\n", f->curLine.penX, f->curLine.penY); + vkWaitForFences(dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); + ResetFences(dev->vkDev, 1, &cache->uploadFence); - vkResetCommandBuffer(cache->cmd,0); + vkResetCommandBuffer(cache->cmd, 0); - memcpy(vkh_buffer_get_mapped_pointer (&cache->buff), cache->hostBuff, (uint64_t)f->curLine.height * FONT_PAGE_SIZE * cache->texPixelSize); + memcpy(vkh_buffer_get_mapped_pointer(&cache->buff), cache->hostBuff, + (uint64_t)f->curLine.height * FONT_PAGE_SIZE * cache->texPixelSize); - vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_cmd_begin(cache->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,f->curLine.pageIdx,1}; - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, f->curLine.pageIdx, 1}; + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - VkBufferImageCopy bufferCopyRegion = { .imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,f->curLine.pageIdx,1}, - .bufferRowLength = FONT_PAGE_SIZE, - .bufferImageHeight = f->curLine.height, - .imageOffset = {f->curLine.penX,f->curLine.penY,0}, - .imageExtent = {FONT_PAGE_SIZE-f->curLine.penX,f->curLine.height,1}}; + VkBufferImageCopy bufferCopyRegion = {.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, f->curLine.pageIdx, 1}, + .bufferRowLength = FONT_PAGE_SIZE, + .bufferImageHeight = f->curLine.height, + .imageOffset = {f->curLine.penX, f->curLine.penY, 0}, + .imageExtent = {FONT_PAGE_SIZE - f->curLine.penX, f->curLine.height, 1}}; - vkCmdCopyBufferToImage(cache->cmd, cache->buff.buffer, - vkh_image_get_vkimage (cache->texture), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); + vkCmdCopyBufferToImage(cache->cmd, cache->buff.buffer, vkh_image_get_vkimage(cache->texture), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); + VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _device_submit_cmd (dev, &cache->cmd, cache->uploadFence); + _device_submit_cmd(dev, &cache->cmd, cache->uploadFence); - f->curLine.penX += cache->stagingX; - cache->stagingX = 0; - memset(cache->hostBuff, 0, (uint64_t)FONT_PAGE_SIZE * FONT_PAGE_SIZE * cache->texPixelSize); + f->curLine.penX += cache->stagingX; + cache->stagingX = 0; + memset(cache->hostBuff, 0, (uint64_t)FONT_PAGE_SIZE * FONT_PAGE_SIZE * cache->texPixelSize); } -///Start a new line in font cache, increase texture layer count if needed. -void _init_next_line_in_tex_cache (VkvgDevice dev, _vkvg_font_t* f){ - _font_cache_t* cache = dev->fontCache; - int i; - for (i = 0; i < cache->texLength; ++i) { - if (cache->pensY[i] + f->curLine.height >= FONT_PAGE_SIZE) - continue; - f->curLine.pageIdx = (unsigned char)i; - f->curLine.penX = 0; - f->curLine.penY = cache->pensY[i]; - cache->pensY[i] += f->curLine.height; - return; - } - _flush_chars_to_tex (dev, f); - _increase_font_tex_array (dev); - _init_next_line_in_tex_cache(dev, f); +/// Start a new line in font cache, increase texture layer count if needed. +void _init_next_line_in_tex_cache(VkvgDevice dev, _vkvg_font_t *f) { + _font_cache_t *cache = dev->fontCache; + int i; + for (i = 0; i < cache->texLength; ++i) { + if (cache->pensY[i] + f->curLine.height >= FONT_PAGE_SIZE) + continue; + f->curLine.pageIdx = (unsigned char)i; + f->curLine.penX = 0; + f->curLine.penY = cache->pensY[i]; + cache->pensY[i] += f->curLine.height; + return; + } + _flush_chars_to_tex(dev, f); + _increase_font_tex_array(dev); + _init_next_line_in_tex_cache(dev, f); } -void _font_cache_destroy (VkvgDevice dev){ - _font_cache_t* cache = (_font_cache_t*)dev->fontCache; +void _font_cache_destroy(VkvgDevice dev) { + _font_cache_t *cache = (_font_cache_t *)dev->fontCache; - free (cache->hostBuff); + free(cache->hostBuff); - for (int i = 0; i < cache->fontsCount; ++i) { - _vkvg_font_identity_t* f = &cache->fonts[i]; - for (uint32_t j = 0; j < f->sizeCount; j++) { - _vkvg_font_t* s = &f->sizes[j]; + for (int i = 0; i < cache->fontsCount; ++i) { + _vkvg_font_identity_t *f = &cache->fonts[i]; + for (uint32_t j = 0; j < f->sizeCount; j++) { + _vkvg_font_t *s = &f->sizes[j]; #ifdef VKVG_USE_FREETYPE - for (int g = 0; g < s->face->num_glyphs; ++g) { - if (s->charLookup[g]!=NULL) - free(s->charLookup[g]); - } - FT_Done_Face (s->face); + for (int g = 0; g < s->face->num_glyphs; ++g) { + if (s->charLookup[g] != NULL) + free(s->charLookup[g]); + } + FT_Done_Face(s->face); #else - for (int g = 0; g < f->stbInfo.numGlyphs; ++g) { - if (s->charLookup[g]!=NULL) - free(s->charLookup[g]); - } + for (int g = 0; g < f->stbInfo.numGlyphs; ++g) { + if (s->charLookup[g] != NULL) + free(s->charLookup[g]); + } #endif #ifdef VKVG_USE_HARFBUZZ - hb_font_destroy (s->hb_font); + hb_font_destroy(s->hb_font); #endif - free(s->charLookup); - } - free (f->sizes); - free(f->fontFile); - for (uint32_t j = 0; j < f->namesCount; j++) - free (f->names[j]); - if (f->namesCount > 0) - free (f->names); - free (f->fontBuffer); - } - - free(cache->fonts); - free(cache->pensY); - - vkh_buffer_reset (&cache->buff); - vkh_image_destroy (cache->texture); - //vkFreeCommandBuffers(dev->vkDev,dev->cmdPool, 1, &cache->cmd); - vkDestroyFence (dev->vkDev,cache->uploadFence,NULL); + free(s->charLookup); + } + free(f->sizes); + free(f->fontFile); + for (uint32_t j = 0; j < f->namesCount; j++) + free(f->names[j]); + if (f->namesCount > 0) + free(f->names); + free(f->fontBuffer); + } + + free(cache->fonts); + free(cache->pensY); + + vkh_buffer_reset(&cache->buff); + vkh_image_destroy(cache->texture); + // vkFreeCommandBuffers(dev->vkDev,dev->cmdPool, 1, &cache->cmd); + vkDestroyFence(dev->vkDev, cache->uploadFence, NULL); #ifdef VKVG_USE_FREETYPE - FT_Done_FreeType(cache->library); + FT_Done_FreeType(cache->library); #endif #ifdef VKVG_USE_FONTCONFIG - FcConfigDestroy(cache->config); - FcFini(); + FcConfigDestroy(cache->config); + FcFini(); #endif - if (dev->threadAware) - mtx_destroy (&cache->mutex); - - free (dev->fontCache); + if (dev->threadAware) + mtx_destroy(&cache->mutex); + free(dev->fontCache); } -void _font_cache_update_context_descset (VkvgContext ctx) { - if (ctx->fontCacheImg) - vkh_image_destroy (ctx->fontCacheImg); +void _font_cache_update_context_descset(VkvgContext ctx) { + if (ctx->fontCacheImg) + vkh_image_destroy(ctx->fontCacheImg); - LOCK_FONTCACHE (ctx->dev) + LOCK_FONTCACHE(ctx->dev) - ctx->fontCacheImg = ctx->dev->fontCache->texture; - vkh_image_reference (ctx->fontCacheImg); + ctx->fontCacheImg = ctx->dev->fontCache->texture; + vkh_image_reference(ctx->fontCacheImg); - _update_descriptor_set (ctx, ctx->fontCacheImg, ctx->dsFont); + _update_descriptor_set(ctx, ctx->fontCacheImg, ctx->dsFont); - UNLOCK_FONTCACHE (ctx->dev) + UNLOCK_FONTCACHE(ctx->dev) } -//create a new char entry and put glyph in stagging buffer, ready for upload. -_char_ref* _prepare_char (VkvgDevice dev, VkvgText tr, uint32_t gindex){ - _vkvg_font_t* f = tr->font; +// create a new char entry and put glyph in stagging buffer, ready for upload. +_char_ref *_prepare_char(VkvgDevice dev, VkvgText tr, uint32_t gindex) { + _vkvg_font_t *f = tr->font; #ifdef VKVG_USE_FREETYPE - #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_TARGET_NORMAL)); - FT_CHECK_RESULT(FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LCD)); - #else - FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_RENDER)); - #endif - - FT_GlyphSlot slot = f->face->glyph; - FT_Bitmap bmp = slot->bitmap; - uint32_t bmpByteWidth = bmp.width; - uint32_t bmpPixelWidth = bmp.width; - uint32_t bmpRows = bmp.rows; - unsigned char* buffer = bmp.buffer; +#if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) + FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_TARGET_NORMAL)); + FT_CHECK_RESULT(FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LCD)); +#else + FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_RENDER)); +#endif + + FT_GlyphSlot slot = f->face->glyph; + FT_Bitmap bmp = slot->bitmap; + uint32_t bmpByteWidth = bmp.width; + uint32_t bmpPixelWidth = bmp.width; + uint32_t bmpRows = bmp.rows; + unsigned char *buffer = bmp.buffer; #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - bmpPixelWidth /= 3; + bmpPixelWidth /= 3; #endif #else - stbtt_fontinfo* pStbInfo = &tr->fontId->stbInfo; - int c_x1, c_y1, c_x2, c_y2; - stbtt_GetGlyphBitmapBox (pStbInfo, gindex, f->scale, f->scale, &c_x1, &c_y1, &c_x2, &c_y2); - uint32_t bmpByteWidth = c_x2 - c_x1; - uint32_t bmpPixelWidth = bmpByteWidth; - uint32_t bmpRows = c_y2 - c_y1; + stbtt_fontinfo *pStbInfo = &tr->fontId->stbInfo; + int c_x1, c_y1, c_x2, c_y2; + stbtt_GetGlyphBitmapBox(pStbInfo, gindex, f->scale, f->scale, &c_x1, &c_y1, &c_x2, &c_y2); + uint32_t bmpByteWidth = c_x2 - c_x1; + uint32_t bmpPixelWidth = bmpByteWidth; + uint32_t bmpRows = c_y2 - c_y1; #endif - uint8_t* data = dev->fontCache->hostBuff; + uint8_t *data = dev->fontCache->hostBuff; - if (dev->fontCache->stagingX + f->curLine.penX + bmpPixelWidth > FONT_PAGE_SIZE){ - _flush_chars_to_tex (dev, f); - _init_next_line_in_tex_cache (dev, f); - } + if (dev->fontCache->stagingX + f->curLine.penX + bmpPixelWidth > FONT_PAGE_SIZE) { + _flush_chars_to_tex(dev, f); + _init_next_line_in_tex_cache(dev, f); + } - _char_ref* cr = (_char_ref*)malloc(sizeof(_char_ref)); - int penX = dev->fontCache->stagingX; + _char_ref *cr = (_char_ref *)malloc(sizeof(_char_ref)); + int penX = dev->fontCache->stagingX; #ifdef VKVG_USE_FREETYPE - for(uint32_t y=0; y < bmpRows; y++) { - for(uint32_t x=0; x < bmpPixelWidth; x++) { + for (uint32_t y = 0; y < bmpRows; y++) { + for (uint32_t x = 0; x < bmpPixelWidth; x++) { #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - unsigned char r = buffer[y * bmp.pitch + x * 3]; - unsigned char g = buffer[y * bmp.pitch + x * 3 + 1]; - unsigned char b = buffer[y * bmp.pitch + x * 3 + 2]; - - data[(penX + x + y * FONT_PAGE_SIZE) * 4] = b; - data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 1] = g; - data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 2] = r; - data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 3] = (r+g+b)/3; + unsigned char r = buffer[y * bmp.pitch + x * 3]; + unsigned char g = buffer[y * bmp.pitch + x * 3 + 1]; + unsigned char b = buffer[y * bmp.pitch + x * 3 + 2]; + + data[(penX + x + y * FONT_PAGE_SIZE) * 4] = b; + data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 1] = g; + data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 2] = r; + data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 3] = (r + g + b) / 3; #else - data[penX + x + y * FONT_PAGE_SIZE ] = buffer[x + y * bmpPixelWidth]; + data[penX + x + y * FONT_PAGE_SIZE] = buffer[x + y * bmpPixelWidth]; #endif - } - } - cr->bmpDiff.x = (int16_t)slot->bitmap_left; - cr->bmpDiff.y = (int16_t)slot->bitmap_top; - cr->advance = slot->advance; + } + } + cr->bmpDiff.x = (int16_t)slot->bitmap_left; + cr->bmpDiff.y = (int16_t)slot->bitmap_top; + cr->advance = slot->advance; #else - int advance; - int lsb; - stbtt_GetGlyphHMetrics(pStbInfo, gindex, &advance, &lsb); - stbtt_MakeGlyphBitmap (pStbInfo, data + penX, bmpPixelWidth, bmpRows, FONT_PAGE_SIZE, f->scale, f->scale, gindex); - cr->bmpDiff.x = (int16_t)c_x1; - cr->bmpDiff.y = (int16_t)-c_y1; - cr->advance = (vec2) {(uint32_t)roundf (f->scale * advance) << 6, 0}; + int advance; + int lsb; + stbtt_GetGlyphHMetrics(pStbInfo, gindex, &advance, &lsb); + stbtt_MakeGlyphBitmap(pStbInfo, data + penX, bmpPixelWidth, bmpRows, FONT_PAGE_SIZE, f->scale, f->scale, gindex); + cr->bmpDiff.x = (int16_t)c_x1; + cr->bmpDiff.y = (int16_t)-c_y1; + cr->advance = (vec2){(uint32_t)roundf(f->scale * advance) << 6, 0}; #endif - vec4 uvBounds = { - {(float)(penX + f->curLine.penX) / (float)FONT_PAGE_SIZE}, - {(float)f->curLine.penY / (float)FONT_PAGE_SIZE}, - {(float)bmpPixelWidth}, - {(float)bmpRows}}; - cr->bounds = uvBounds; - cr->pageIdx = f->curLine.pageIdx; - - f->charLookup[gindex] = cr; - dev->fontCache->stagingX += bmpPixelWidth; - return cr; + vec4 uvBounds = {{(float)(penX + f->curLine.penX) / (float)FONT_PAGE_SIZE}, + {(float)f->curLine.penY / (float)FONT_PAGE_SIZE}, + {(float)bmpPixelWidth}, + {(float)bmpRows}}; + cr->bounds = uvBounds; + cr->pageIdx = f->curLine.pageIdx; + + f->charLookup[gindex] = cr; + dev->fontCache->stagingX += bmpPixelWidth; + return cr; } -void _font_add_name (_vkvg_font_identity_t* font, const char* name) { - if (++font->namesCount == 1) - font->names = (char**) malloc (sizeof(char*)); - else - font->names = (char**) realloc (font->names, font->namesCount * sizeof(char*)); - font->names[font->namesCount-1] = (char*)calloc(strlen(name)+1, sizeof (char)); - strcpy (font->names[font->namesCount-1], name); +void _font_add_name(_vkvg_font_identity_t *font, const char *name) { + if (++font->namesCount == 1) + font->names = (char **)malloc(sizeof(char *)); + else + font->names = (char **)realloc(font->names, font->namesCount * sizeof(char *)); + font->names[font->namesCount - 1] = (char *)calloc(strlen(name) + 1, sizeof(char)); + strcpy(font->names[font->namesCount - 1], name); } -bool _font_cache_load_font_file_in_memory (_vkvg_font_identity_t* fontId) { - FILE* fontFile = fopen(fontId->fontFile, "rb"); - if (!fontFile) - return false; - fseek(fontFile, 0, SEEK_END); - fontId->fontBufSize = ftell(fontFile); /* how long is the file ? */ - fseek(fontFile, 0, SEEK_SET); /* reset */ - fontId->fontBuffer = malloc(fontId->fontBufSize); - fread(fontId->fontBuffer, fontId->fontBufSize, 1, fontFile); - fclose(fontFile); - return true; +bool _font_cache_load_font_file_in_memory(_vkvg_font_identity_t *fontId) { + FILE *fontFile = fopen(fontId->fontFile, "rb"); + if (!fontFile) + return false; + fseek(fontFile, 0, SEEK_END); + fontId->fontBufSize = ftell(fontFile); /* how long is the file ? */ + fseek(fontFile, 0, SEEK_SET); /* reset */ + fontId->fontBuffer = malloc(fontId->fontBufSize); + fread(fontId->fontBuffer, fontId->fontBufSize, 1, fontFile); + fclose(fontFile); + return true; } -_vkvg_font_identity_t* _font_cache_add_font_identity (VkvgContext ctx, const char* fontFilePath, const char* name){ - _font_cache_t* cache = (_font_cache_t*)ctx->dev->fontCache; - if (++cache->fontsCount == 1) - cache->fonts = (_vkvg_font_identity_t*) malloc (cache->fontsCount * sizeof(_vkvg_font_identity_t)); - else - cache->fonts = (_vkvg_font_identity_t*) realloc (cache->fonts, cache->fontsCount * sizeof(_vkvg_font_identity_t)); - _vkvg_font_identity_t nf = {0}; - - if (fontFilePath) { - int fflength = strlen (fontFilePath) + 1; - nf.fontFile = (char*)malloc (fflength * sizeof(char)); - strcpy (nf.fontFile, fontFilePath); - } - - _font_add_name (&nf, name); - - cache->fonts[cache->fontsCount-1] = nf; - return &cache->fonts[cache->fontsCount-1]; +_vkvg_font_identity_t *_font_cache_add_font_identity(VkvgContext ctx, const char *fontFilePath, const char *name) { + _font_cache_t *cache = (_font_cache_t *)ctx->dev->fontCache; + if (++cache->fontsCount == 1) + cache->fonts = (_vkvg_font_identity_t *)malloc(cache->fontsCount * sizeof(_vkvg_font_identity_t)); + else + cache->fonts = + (_vkvg_font_identity_t *)realloc(cache->fonts, cache->fontsCount * sizeof(_vkvg_font_identity_t)); + _vkvg_font_identity_t nf = {0}; + + if (fontFilePath) { + int fflength = strlen(fontFilePath) + 1; + nf.fontFile = (char *)malloc(fflength * sizeof(char)); + strcpy(nf.fontFile, fontFilePath); + } + + _font_add_name(&nf, name); + + cache->fonts[cache->fontsCount - 1] = nf; + return &cache->fonts[cache->fontsCount - 1]; } -//select current font for context -_vkvg_font_t* _find_or_create_font_size (VkvgContext ctx) { - _vkvg_font_identity_t* font = ctx->currentFont; - - for (uint32_t i = 0; i < font->sizeCount; ++i) { - if (font->sizes[i].charSize == ctx->selectedCharSize) - return &font->sizes[i]; - } - //if not found, create a new font size structure - if (++font->sizeCount == 1) - font->sizes = (_vkvg_font_t*) malloc (sizeof(_vkvg_font_t)); - else - font->sizes = (_vkvg_font_t*) realloc (font->sizes, font->sizeCount * sizeof(_vkvg_font_t)); - _vkvg_font_t newSize = {.charSize = ctx->selectedCharSize}; - - VkvgDevice dev = ctx->dev; +// select current font for context +_vkvg_font_t *_find_or_create_font_size(VkvgContext ctx) { + _vkvg_font_identity_t *font = ctx->currentFont; + + for (uint32_t i = 0; i < font->sizeCount; ++i) { + if (font->sizes[i].charSize == ctx->selectedCharSize) + return &font->sizes[i]; + } + // if not found, create a new font size structure + if (++font->sizeCount == 1) + font->sizes = (_vkvg_font_t *)malloc(sizeof(_vkvg_font_t)); + else + font->sizes = (_vkvg_font_t *)realloc(font->sizes, font->sizeCount * sizeof(_vkvg_font_t)); + _vkvg_font_t newSize = {.charSize = ctx->selectedCharSize}; + + VkvgDevice dev = ctx->dev; #ifdef VKVG_USE_FREETYPE - _font_cache_t* cache = (_font_cache_t*)ctx->dev->fontCache; - FT_CHECK_RESULT(FT_New_Memory_Face (cache->library, font->fontBuffer, font->fontBufSize, 0, &newSize.face)); - FT_CHECK_RESULT(FT_Set_Char_Size(newSize.face, 0, newSize.charSize, dev->hdpi, dev->vdpi )); + _font_cache_t *cache = (_font_cache_t *)ctx->dev->fontCache; + FT_CHECK_RESULT(FT_New_Memory_Face(cache->library, font->fontBuffer, font->fontBufSize, 0, &newSize.face)); + FT_CHECK_RESULT(FT_Set_Char_Size(newSize.face, 0, newSize.charSize, dev->hdpi, dev->vdpi)); - newSize.charLookup = (_char_ref**)calloc (newSize.face->num_glyphs, sizeof(_char_ref*)); + newSize.charLookup = (_char_ref **)calloc(newSize.face->num_glyphs, sizeof(_char_ref *)); - if (FT_IS_SCALABLE(newSize.face)) - newSize.curLine.height = newSize.face->size->metrics.height >> 6; - else - newSize.curLine.height = newSize.face->height >> 6; + if (FT_IS_SCALABLE(newSize.face)) + newSize.curLine.height = newSize.face->size->metrics.height >> 6; + else + newSize.curLine.height = newSize.face->height >> 6; #else - int result = stbtt_InitFont(&font->stbInfo, font->fontBuffer, 0); - assert(result && "stbtt_initFont failed"); - if (!result) { - ctx->status = VKVG_STATUS_INVALID_FONT; - return NULL; - } - stbtt_GetFontVMetrics(&font->stbInfo, &font->ascent, &font->descent, &font->lineGap); - newSize.charLookup = (_char_ref**)calloc (font->stbInfo.numGlyphs, sizeof(_char_ref*)); - //newSize.scale = stbtt_ScaleForPixelHeight(&font->stbInfo, newSize.charSize); - newSize.scale = stbtt_ScaleForMappingEmToPixels(&font->stbInfo, newSize.charSize); - newSize.curLine.height = roundf (newSize.scale * (font->ascent - font->descent + font->lineGap)); - newSize.ascent = roundf (newSize.scale * font->ascent); - newSize.descent = roundf (newSize.scale * font->descent); - newSize.lineGap = roundf (newSize.scale * font->lineGap); + int result = stbtt_InitFont(&font->stbInfo, font->fontBuffer, 0); + assert(result && "stbtt_initFont failed"); + if (!result) { + ctx->status = VKVG_STATUS_INVALID_FONT; + return NULL; + } + stbtt_GetFontVMetrics(&font->stbInfo, &font->ascent, &font->descent, &font->lineGap); + newSize.charLookup = (_char_ref **)calloc(font->stbInfo.numGlyphs, sizeof(_char_ref *)); + // newSize.scale = stbtt_ScaleForPixelHeight(&font->stbInfo, newSize.charSize); + newSize.scale = stbtt_ScaleForMappingEmToPixels(&font->stbInfo, newSize.charSize); + newSize.curLine.height = roundf(newSize.scale * (font->ascent - font->descent + font->lineGap)); + newSize.ascent = roundf(newSize.scale * font->ascent); + newSize.descent = roundf(newSize.scale * font->descent); + newSize.lineGap = roundf(newSize.scale * font->lineGap); #endif #ifdef VKVG_USE_HARFBUZZ - newSize.hb_font = hb_ft_font_create(newSize.face, NULL); + newSize.hb_font = hb_ft_font_create(newSize.face, NULL); #endif - _init_next_line_in_tex_cache (dev, &newSize); + _init_next_line_in_tex_cache(dev, &newSize); - font->sizes[font->sizeCount-1] = newSize; - return &font->sizes[font->sizeCount-1]; + font->sizes[font->sizeCount - 1] = newSize; + return &font->sizes[font->sizeCount - 1]; } -//try find font already resolved with fontconfig by font name -bool _tryFindFontByName (VkvgContext ctx, _vkvg_font_identity_t** font){ - _font_cache_t* cache = ctx->dev->fontCache; - for (int i = 0; i < cache->fontsCount; ++i) { - for (uint32_t j = 0; j < cache->fonts[i].namesCount; j++) { - if (strcmp (cache->fonts[i].names[j], ctx->selectedFontName) == 0) { - *font = &cache->fonts[i]; - return true; - } - } - } - return false; +// try find font already resolved with fontconfig by font name +bool _tryFindFontByName(VkvgContext ctx, _vkvg_font_identity_t **font) { + _font_cache_t *cache = ctx->dev->fontCache; + for (int i = 0; i < cache->fontsCount; ++i) { + for (uint32_t j = 0; j < cache->fonts[i].namesCount; j++) { + if (strcmp(cache->fonts[i].names[j], ctx->selectedFontName) == 0) { + *font = &cache->fonts[i]; + return true; + } + } + } + return false; } #ifdef VKVG_USE_FONTCONFIG -bool _tryResolveFontNameWithFontConfig (VkvgContext ctx, _vkvg_font_identity_t** resolvedFont) { - _font_cache_t* cache = (_font_cache_t*)ctx->dev->fontCache; - char* fontFile = NULL; - - FcPattern* pat = FcNameParse((const FcChar8*)ctx->selectedFontName); - FcConfigSubstitute(cache->config, pat, FcMatchPattern); - FcDefaultSubstitute(pat); - FcResult result; - FcPattern* font = FcFontMatch(cache->config, pat, &result); - if (font) - FcPatternGetString(font, FC_FILE, 0, (FcChar8 **)&fontFile); - *resolvedFont = NULL; - if (fontFile) { - //try find font in cache by path - for (int i = 0; i < cache->fontsCount; ++i) { - if (cache->fonts[i].fontFile && strcmp (cache->fonts[i].fontFile, fontFile) == 0) { - _font_add_name (&cache->fonts[i], ctx->selectedFontName); - *resolvedFont = &cache->fonts[i]; - break; - } - } - if (!*resolvedFont) { - //if not found, create a new vkvg_font - _vkvg_font_identity_t* fid = _font_cache_add_font_identity(ctx, fontFile, ctx->selectedFontName); - _font_cache_load_font_file_in_memory (fid); - *resolvedFont = &cache->fonts[cache->fontsCount-1]; - } - } - - FcPatternDestroy(pat); - FcPatternDestroy(font); - - return (fontFile != NULL); +bool _tryResolveFontNameWithFontConfig(VkvgContext ctx, _vkvg_font_identity_t **resolvedFont) { + _font_cache_t *cache = (_font_cache_t *)ctx->dev->fontCache; + char *fontFile = NULL; + + FcPattern *pat = FcNameParse((const FcChar8 *)ctx->selectedFontName); + FcConfigSubstitute(cache->config, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + FcResult result; + FcPattern *font = FcFontMatch(cache->config, pat, &result); + if (font) + FcPatternGetString(font, FC_FILE, 0, (FcChar8 **)&fontFile); + *resolvedFont = NULL; + if (fontFile) { + // try find font in cache by path + for (int i = 0; i < cache->fontsCount; ++i) { + if (cache->fonts[i].fontFile && strcmp(cache->fonts[i].fontFile, fontFile) == 0) { + _font_add_name(&cache->fonts[i], ctx->selectedFontName); + *resolvedFont = &cache->fonts[i]; + break; + } + } + if (!*resolvedFont) { + // if not found, create a new vkvg_font + _vkvg_font_identity_t *fid = _font_cache_add_font_identity(ctx, fontFile, ctx->selectedFontName); + _font_cache_load_font_file_in_memory(fid); + *resolvedFont = &cache->fonts[cache->fontsCount - 1]; + } + } + + FcPatternDestroy(pat); + FcPatternDestroy(font); + + return (fontFile != NULL); } #endif +// try to find corresponding font in cache (defined by context selectedFont) and create a new font entry if not found. +void _update_current_font(VkvgContext ctx) { + if (ctx->currentFont == NULL) { + LOCK_FONTCACHE(ctx->dev) + if (ctx->selectedFontName[0] == 0) + _select_font_face(ctx, "sans"); -//try to find corresponding font in cache (defined by context selectedFont) and create a new font entry if not found. -void _update_current_font (VkvgContext ctx) { - if (ctx->currentFont == NULL){ - LOCK_FONTCACHE(ctx->dev) - if (ctx->selectedFontName[0] == 0) - _select_font_face (ctx, "sans"); - - if (!_tryFindFontByName (ctx, &ctx->currentFont)) { + if (!_tryFindFontByName(ctx, &ctx->currentFont)) { #ifdef VKVG_USE_FONTCONFIG - _tryResolveFontNameWithFontConfig (ctx, &ctx->currentFont); + _tryResolveFontNameWithFontConfig(ctx, &ctx->currentFont); #else - LOG(VKVG_LOG_ERR, "Unresolved font: %s\n", ctx->selectedFontName); - UNLOCK_FONTCACHE(ctx->dev) - ctx->status = VKVG_STATUS_INVALID_FONT; - return; + LOG(VKVG_LOG_ERR, "Unresolved font: %s\n", ctx->selectedFontName); + UNLOCK_FONTCACHE(ctx->dev) + ctx->status = VKVG_STATUS_INVALID_FONT; + return; #endif - } + } - ctx->currentFontSize = _find_or_create_font_size (ctx); - UNLOCK_FONTCACHE(ctx->dev) - } + ctx->currentFontSize = _find_or_create_font_size(ctx); + UNLOCK_FONTCACHE(ctx->dev) + } } #ifdef VKVG_USE_HARFBUZZ -//Get harfBuzz buffer for provided text. -hb_buffer_t * _get_hb_buffer (_vkvg_font_t* font, const char* text, int length) { - hb_buffer_t *buf = hb_buffer_create(); +// Get harfBuzz buffer for provided text. +hb_buffer_t *_get_hb_buffer(_vkvg_font_t *font, const char *text, int length) { + hb_buffer_t *buf = hb_buffer_create(); - hb_script_t script = HB_SCRIPT_LATIN; - hb_unicode_funcs_t* ucfunc = hb_unicode_funcs_get_default (); - wchar_t firstChar = 0; - if (mbstowcs (&firstChar, text, 1)) - script = hb_unicode_script (ucfunc, firstChar); + hb_script_t script = HB_SCRIPT_LATIN; + hb_unicode_funcs_t *ucfunc = hb_unicode_funcs_get_default(); + wchar_t firstChar = 0; + if (mbstowcs(&firstChar, text, 1)) + script = hb_unicode_script(ucfunc, firstChar); - hb_direction_t dir = hb_script_get_horizontal_direction(script); - hb_buffer_set_direction (buf, dir); - hb_buffer_set_script (buf, script); - //hb_buffer_set_language (buf, hb_language_from_string (lng, (int)strlen(lng))); - hb_buffer_add_utf8 (buf, text, length, 0, length); + hb_direction_t dir = hb_script_get_horizontal_direction(script); + hb_buffer_set_direction(buf, dir); + hb_buffer_set_script(buf, script); + // hb_buffer_set_language (buf, hb_language_from_string (lng, (int)strlen(lng))); + hb_buffer_add_utf8(buf, text, length, 0, length); - hb_shape (font->hb_font, buf, NULL, 0); + hb_shape(font->hb_font, buf, NULL, 0); - return buf; + return buf; } #endif -//retrieve global font extends of context's current font as defined by FreeType -void _font_cache_font_extents (VkvgContext ctx, vkvg_font_extents_t *extents) { - _update_current_font (ctx); +// retrieve global font extends of context's current font as defined by FreeType +void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t *extents) { + _update_current_font(ctx); - if (ctx->status) - return; + if (ctx->status) + return; - //TODO: ensure correct metrics are returned (scalled/unscalled, etc..) - _vkvg_font_t* font = ctx->currentFontSize; + // TODO: ensure correct metrics are returned (scalled/unscalled, etc..) + _vkvg_font_t *font = ctx->currentFontSize; #ifdef VKVG_USE_FREETYPE - FT_BBox* bbox = &font->face->bbox; - FT_Size_Metrics* metrics = &font->face->size->metrics; - - extents->ascent = (float)(FT_MulFix(font->face->ascender, metrics->y_scale) >> 6);//metrics->ascender >> 6; - extents->descent =-(float)(FT_MulFix(font->face->descender, metrics->y_scale) >> 6);//metrics->descender >> 6; - extents->height = (float)(FT_MulFix(font->face->height, metrics->y_scale) >> 6);//metrics->height >> 6; - extents->max_x_advance = (float)(bbox->xMax >> 6); - extents->max_y_advance = (float)(bbox->yMax >> 6); + FT_BBox *bbox = &font->face->bbox; + FT_Size_Metrics *metrics = &font->face->size->metrics; + + extents->ascent = (float)(FT_MulFix(font->face->ascender, metrics->y_scale) >> 6); // metrics->ascender >> 6; + extents->descent = -(float)(FT_MulFix(font->face->descender, metrics->y_scale) >> 6); // metrics->descender >> 6; + extents->height = (float)(FT_MulFix(font->face->height, metrics->y_scale) >> 6); // metrics->height >> 6; + extents->max_x_advance = (float)(bbox->xMax >> 6); + extents->max_y_advance = (float)(bbox->yMax >> 6); #else - extents->ascent = roundf (font->scale * ctx->currentFont->ascent); - extents->descent =-roundf (font->scale * ctx->currentFont->descent); - extents->height = roundf (font->scale * (ctx->currentFont->ascent - ctx->currentFont->descent + ctx->currentFont->lineGap)); - extents->max_x_advance = 0;//TODO - extents->max_y_advance = 0; + extents->ascent = roundf(font->scale * ctx->currentFont->ascent); + extents->descent = -roundf(font->scale * ctx->currentFont->descent); + extents->height = + roundf(font->scale * (ctx->currentFont->ascent - ctx->currentFont->descent + ctx->currentFont->lineGap)); + extents->max_x_advance = 0; // TODO + extents->max_y_advance = 0; #endif } -//compute text extends for provided string. -void _font_cache_text_extents (VkvgContext ctx, const char* text, int length, vkvg_text_extents_t *extents) { - if (text == NULL) { - memset(extents, 0, sizeof(vkvg_text_extents_t)); - return; - } +// compute text extends for provided string. +void _font_cache_text_extents(VkvgContext ctx, const char *text, int length, vkvg_text_extents_t *extents) { + if (text == NULL) { + memset(extents, 0, sizeof(vkvg_text_extents_t)); + return; + } - vkvg_text_run_t tr = {0}; - _font_cache_create_text_run (ctx, text, length, &tr); + vkvg_text_run_t tr = {0}; + _font_cache_create_text_run(ctx, text, length, &tr); - if (ctx->status) - return; + if (ctx->status) + return; - *extents = tr.extents; + *extents = tr.extents; - _font_cache_destroy_text_run (&tr); + _font_cache_destroy_text_run(&tr); } -//text is expected as utf8 encoded -//if length is < 0, text must be null terminated, else it contains glyph count -void _font_cache_create_text_run (VkvgContext ctx, const char* text, int length, VkvgText textRun) { +// text is expected as utf8 encoded +// if length is < 0, text must be null terminated, else it contains glyph count +void _font_cache_create_text_run(VkvgContext ctx, const char *text, int length, VkvgText textRun) { - _update_current_font (ctx); + _update_current_font(ctx); - if (ctx->status) - return; + if (ctx->status) + return; - textRun->fontId = ctx->currentFont; - textRun->font = ctx->currentFontSize; - textRun->dev = ctx->dev; + textRun->fontId = ctx->currentFont; + textRun->font = ctx->currentFontSize; + textRun->dev = ctx->dev; - LOCK_FONTCACHE (ctx->dev) + LOCK_FONTCACHE(ctx->dev) #ifdef VKVG_USE_HARFBUZZ - textRun->hbBuf = _get_hb_buffer (ctx->currentFontSize, text, length); - textRun->glyphs = hb_buffer_get_glyph_positions (textRun->hbBuf, &textRun->glyph_count); + textRun->hbBuf = _get_hb_buffer(ctx->currentFontSize, text, length); + textRun->glyphs = hb_buffer_get_glyph_positions(textRun->hbBuf, &textRun->glyph_count); #else - size_t wsize; - if (length < 0) - wsize = mbstowcs(NULL, text, 0); - else - wsize = (size_t)length; - wchar_t *tmp = (wchar_t*)malloc((wsize+1) * sizeof (wchar_t)); - textRun->glyph_count = mbstowcs (tmp, text, wsize); - textRun->glyphs = (vkvg_glyph_info_t*)malloc(textRun->glyph_count * sizeof (vkvg_glyph_info_t)); - for (unsigned int i=0; iglyph_count; i++) { + size_t wsize; + if (length < 0) + wsize = mbstowcs(NULL, text, 0); + else + wsize = (size_t)length; + wchar_t *tmp = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t)); + textRun->glyph_count = mbstowcs(tmp, text, wsize); + textRun->glyphs = (vkvg_glyph_info_t *)malloc(textRun->glyph_count * sizeof(vkvg_glyph_info_t)); + for (unsigned int i = 0; i < textRun->glyph_count; i++) { #ifdef VKVG_USE_FREETYPE - uint32_t gindex = FT_Get_Char_Index (textRun->font->face, tmp[i]); + uint32_t gindex = FT_Get_Char_Index(textRun->font->face, tmp[i]); #else - uint32_t gindex = stbtt_FindGlyphIndex (&textRun->fontId->stbInfo, tmp[i]); + uint32_t gindex = stbtt_FindGlyphIndex(&textRun->fontId->stbInfo, tmp[i]); #endif - _char_ref* cr = textRun->font->charLookup[gindex]; - if (cr==NULL) - cr = _prepare_char (textRun->dev, textRun, gindex); - textRun->glyphs[i].codepoint = gindex; - textRun->glyphs[i].x_advance = cr->advance.x; - textRun->glyphs[i].y_advance = cr->advance.y; - textRun->glyphs[i].x_offset = 0; - textRun->glyphs[i].y_offset = 0; - /*textRun->glyphs[i].x_offset = cr->bmpDiff.x; - textRun->glyphs[i].y_offset = cr->bmpDiff.y;*/ - } - free (tmp); + _char_ref *cr = textRun->font->charLookup[gindex]; + if (cr == NULL) + cr = _prepare_char(textRun->dev, textRun, gindex); + textRun->glyphs[i].codepoint = gindex; + textRun->glyphs[i].x_advance = cr->advance.x; + textRun->glyphs[i].y_advance = cr->advance.y; + textRun->glyphs[i].x_offset = 0; + textRun->glyphs[i].y_offset = 0; + /*textRun->glyphs[i].x_offset = cr->bmpDiff.x; + textRun->glyphs[i].y_offset = cr->bmpDiff.y;*/ + } + free(tmp); #endif - - UNLOCK_FONTCACHE (ctx->dev) - unsigned int string_width_in_pixels = 0; - for (uint32_t i=0; i < textRun->glyph_count; ++i) - string_width_in_pixels += textRun->glyphs[i].x_advance >> 6; + UNLOCK_FONTCACHE(ctx->dev) + + unsigned int string_width_in_pixels = 0; + for (uint32_t i = 0; i < textRun->glyph_count; ++i) + string_width_in_pixels += textRun->glyphs[i].x_advance >> 6; #ifdef VKVG_USE_FREETYPE - FT_Size_Metrics* metrics = &ctx->currentFontSize->face->size->metrics; - textRun->extents.height = (float)(FT_MulFix(ctx->currentFontSize->face->height, metrics->y_scale) >> 6);// (metrics->ascender + metrics->descender) >> 6; + FT_Size_Metrics *metrics = &ctx->currentFontSize->face->size->metrics; + textRun->extents.height = (float)(FT_MulFix(ctx->currentFontSize->face->height, metrics->y_scale) >> + 6); // (metrics->ascender + metrics->descender) >> 6; #else - textRun->extents.height = textRun->font->ascent - textRun->font->descent + textRun->font->lineGap; + textRun->extents.height = textRun->font->ascent - textRun->font->descent + textRun->font->lineGap; #endif - textRun->extents.x_advance = (float)string_width_in_pixels; - if (textRun->glyph_count > 0) { - textRun->extents.y_advance = (float)(textRun->glyphs[textRun->glyph_count-1].y_advance >> 6); - textRun->extents.x_bearing = -(float)(textRun->glyphs[0].x_offset >> 6); - textRun->extents.y_bearing = -(float)(textRun->glyphs[0].y_offset >> 6); - } - - textRun->extents.width = textRun->extents.x_advance; + textRun->extents.x_advance = (float)string_width_in_pixels; + if (textRun->glyph_count > 0) { + textRun->extents.y_advance = (float)(textRun->glyphs[textRun->glyph_count - 1].y_advance >> 6); + textRun->extents.x_bearing = -(float)(textRun->glyphs[0].x_offset >> 6); + textRun->extents.y_bearing = -(float)(textRun->glyphs[0].y_offset >> 6); + } + + textRun->extents.width = textRun->extents.x_advance; } -void _font_cache_destroy_text_run (VkvgText textRun) { +void _font_cache_destroy_text_run(VkvgText textRun) { #ifdef VKVG_USE_HARFBUZZ - hb_buffer_destroy (textRun->hbBuf); + hb_buffer_destroy(textRun->hbBuf); #else - if (textRun->glyph_count > 0) - free (textRun->glyphs); + if (textRun->glyph_count > 0) + free(textRun->glyphs); #endif } #ifdef DEBUG -void _show_texture (vkvg_context* ctx){ - Vertex vs[] = { - {{0,0}, 0, {0,0,0}}, - {{0,FONT_PAGE_SIZE}, 0, {0,1,0}}, - {{FONT_PAGE_SIZE,0}, 0, {1,0,0}}, - {{FONT_PAGE_SIZE,FONT_PAGE_SIZE}, 0, {1,1,0}} - }; - - VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; - memcpy (pVert,vs,4*sizeof(Vertex)); - ctx->vertCount+=4; - - _check_vertex_cache_size(ctx); - - _add_tri_indices_for_rect(ctx, firstIdx); +void _show_texture(vkvg_context *ctx) { + Vertex vs[] = {{{0, 0}, 0, {0, 0, 0}}, + {{0, FONT_PAGE_SIZE}, 0, {0, 1, 0}}, + {{FONT_PAGE_SIZE, 0}, 0, {1, 0, 0}}, + {{FONT_PAGE_SIZE, FONT_PAGE_SIZE}, 0, {1, 1, 0}}}; + + VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + Vertex *pVert = &ctx->vertexCache[ctx->vertCount]; + memcpy(pVert, vs, 4 * sizeof(Vertex)); + ctx->vertCount += 4; + + _check_vertex_cache_size(ctx); + + _add_tri_indices_for_rect(ctx, firstIdx); } #endif -void _font_cache_show_text_run (VkvgContext ctx, VkvgText tr) { - unsigned int glyph_count; +void _font_cache_show_text_run(VkvgContext ctx, VkvgText tr) { + unsigned int glyph_count; #ifdef VKVG_USE_HARFBUZZ - hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos (tr->hbBuf, &glyph_count); + hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(tr->hbBuf, &glyph_count); #else - vkvg_glyph_info_t* glyph_info = tr->glyphs; - glyph_count = tr->glyph_count; + vkvg_glyph_info_t *glyph_info = tr->glyphs; + glyph_count = tr->glyph_count; #endif - Vertex v = {{0},ctx->curColor,{0,0,-1}}; - vec2 pen = {0,0}; + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; + vec2 pen = {0, 0}; - if (!_current_path_is_empty(ctx)) - pen = _get_current_position(ctx); + if (!_current_path_is_empty(ctx)) + pen = _get_current_position(ctx); - LOCK_FONTCACHE (ctx->dev) + LOCK_FONTCACHE(ctx->dev) - for (uint32_t i=0; i < glyph_count; ++i) { - _char_ref* cr = tr->font->charLookup[glyph_info[i].codepoint]; + for (uint32_t i = 0; i < glyph_count; ++i) { + _char_ref *cr = tr->font->charLookup[glyph_info[i].codepoint]; #ifdef VKVG_USE_HARFBUZZ - if (cr==NULL) - cr = _prepare_char(tr->dev, tr, glyph_info[i].codepoint); + if (cr == NULL) + cr = _prepare_char(tr->dev, tr, glyph_info[i].codepoint); #endif - float uvWidth = cr->bounds.width / (float)FONT_PAGE_SIZE; - float uvHeight = cr->bounds.height / (float)FONT_PAGE_SIZE; - vec2 p0 = {pen.x + cr->bmpDiff.x + (tr->glyphs[i].x_offset >> 6), - pen.y - cr->bmpDiff.y + (tr->glyphs[i].y_offset >> 6)}; - v.pos = p0; - - VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - - - v.uv.x = cr->bounds.x; - v.uv.y = cr->bounds.y; - v.uv.z = cr->pageIdx; - _add_vertex(ctx,v); - - v.pos.y += cr->bounds.height; - v.uv.y += uvHeight; - _add_vertex(ctx,v); - - v.pos.x += cr->bounds.width; - v.pos.y = p0.y; - v.uv.x += uvWidth; - v.uv.y = cr->bounds.y; - _add_vertex(ctx,v); - - v.pos.y += cr->bounds.height; - v.uv.y += uvHeight; - _add_vertex(ctx,v); - - _add_tri_indices_for_rect (ctx, firstIdx); - - pen.x += (tr->glyphs[i].x_advance >> 6); - pen.y -= (tr->glyphs[i].y_advance >> 6); - } - - //equivalent to a moveto - _finish_path(ctx); - _add_point (ctx, pen.x, pen.y); - _flush_chars_to_tex(tr->dev, tr->font); - UNLOCK_FONTCACHE (ctx->dev) - - if (ctx->fontCacheImg != ctx->dev->fontCache->texture) { - vkvg_flush (ctx); - _font_cache_update_context_descset (ctx); - } + float uvWidth = cr->bounds.width / (float)FONT_PAGE_SIZE; + float uvHeight = cr->bounds.height / (float)FONT_PAGE_SIZE; + vec2 p0 = {pen.x + cr->bmpDiff.x + (tr->glyphs[i].x_offset >> 6), + pen.y - cr->bmpDiff.y + (tr->glyphs[i].y_offset >> 6)}; + v.pos = p0; + + VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + + v.uv.x = cr->bounds.x; + v.uv.y = cr->bounds.y; + v.uv.z = cr->pageIdx; + _add_vertex(ctx, v); + + v.pos.y += cr->bounds.height; + v.uv.y += uvHeight; + _add_vertex(ctx, v); + + v.pos.x += cr->bounds.width; + v.pos.y = p0.y; + v.uv.x += uvWidth; + v.uv.y = cr->bounds.y; + _add_vertex(ctx, v); + + v.pos.y += cr->bounds.height; + v.uv.y += uvHeight; + _add_vertex(ctx, v); + + _add_tri_indices_for_rect(ctx, firstIdx); + + pen.x += (tr->glyphs[i].x_advance >> 6); + pen.y -= (tr->glyphs[i].y_advance >> 6); + } + + // equivalent to a moveto + _finish_path(ctx); + _add_point(ctx, pen.x, pen.y); + _flush_chars_to_tex(tr->dev, tr->font); + UNLOCK_FONTCACHE(ctx->dev) + + if (ctx->fontCacheImg != ctx->dev->fontCache->texture) { + vkvg_flush(ctx); + _font_cache_update_context_descset(ctx); + } } -void _font_cache_show_text (VkvgContext ctx, const char* text){ +void _font_cache_show_text(VkvgContext ctx, const char *text) { - vkvg_text_run_t tr = {0}; - _font_cache_create_text_run (ctx, text, -1, &tr); + vkvg_text_run_t tr = {0}; + _font_cache_create_text_run(ctx, text, -1, &tr); - if (ctx->status) - return; + if (ctx->status) + return; - _font_cache_show_text_run (ctx, &tr); + _font_cache_show_text_run(ctx, &tr); - _font_cache_destroy_text_run (&tr); + _font_cache_destroy_text_run(&tr); - //_show_texture(ctx); return; + //_show_texture(ctx); return; } - /*void testfonts(){ - FT_Library library; - FT_Face face; - FT_GlyphSlot slot; + FT_Library library; + FT_Face face; + FT_GlyphSlot slot; - assert(!FT_Init_FreeType(&library)); - assert(!FT_New_Face(library, "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 0, &face)); - assert(!FT_Set_Char_Size(face, 0, ptSize, device_hdpi, device_vdpi )); + assert(!FT_Init_FreeType(&library)); + assert(!FT_New_Face(library, "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 0, &face)); + assert(!FT_Set_Char_Size(face, 0, ptSize, device_hdpi, device_vdpi )); - //_build_face_tex(face); + //_build_face_tex(face); - hb_font_t *hb_font = hb_ft_font_create(face, NULL); - hb_buffer_t *buf = hb_buffer_create(); + hb_font_t *hb_font = hb_ft_font_create(face, NULL); + hb_buffer_t *buf = hb_buffer_create(); - const char *text = "Ленивый рыжий кот"; - const char *lng = "en"; - //"كسول الزنجبيل القط","懶惰的姜貓", + const char *text = "Ленивый рыжий кот"; + const char *lng = "en"; + //"كسول الزنجبيل القط","懶惰的姜貓", - hb_buffer_set_direction (buf, HB_DIRECTION_LTR); - hb_buffer_set_script (buf, HB_SCRIPT_LATIN); - hb_buffer_set_language (buf, hb_language_from_string(lng,strlen(lng))); - hb_buffer_add_utf8 (buf, text, strlen(text), 0, strlen(text)); + hb_buffer_set_direction (buf, HB_DIRECTION_LTR); + hb_buffer_set_script (buf, HB_SCRIPT_LATIN); + hb_buffer_set_language (buf, hb_language_from_string(lng,strlen(lng))); + hb_buffer_add_utf8 (buf, text, strlen(text), 0, strlen(text)); - hb_unicode_funcs_t * unifc = hb_unicode_funcs_get_default(); - hb_script_t sc = hb_buffer_get_script(buf); + hb_unicode_funcs_t * unifc = hb_unicode_funcs_get_default(); + hb_script_t sc = hb_buffer_get_script(buf); - sc = hb_unicode_script(unifc,0x0260); + sc = hb_unicode_script(unifc,0x0260); - FT_CharMap* cm = face->charmap; + FT_CharMap* cm = face->charmap; - //hb_script_to_iso15924_tag() + //hb_script_to_iso15924_tag() - FT_Done_Face ( face ); - FT_Done_FreeType( library ); + FT_Done_Face ( face ); + FT_Done_FreeType( library ); }*/ diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h index 959c5c8..5e06344 100644 --- a/src/vkvg_fonts.h +++ b/src/vkvg_fonts.h @@ -22,173 +22,175 @@ #ifndef VKVG_FONTS_H #define VKVG_FONTS_H - //disable warning on iostream functions on windows +// disable warning on iostream functions on windows #define _CRT_SECURE_NO_WARNINGS #ifdef VKVG_USE_FREETYPE - #include - #include FT_FREETYPE_H - #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - #include - #endif - #define FT_CHECK_RESULT(f) \ - { \ - FT_Error res = (f); \ - if (res != 0) \ - { \ - fprintf(stderr,"Fatal : FreeType error is %d in %s at line %d\n", res, __FILE__, __LINE__); \ - assert(res == 0); \ - } \ - } +#include +#include FT_FREETYPE_H +#if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) +#include +#endif +#define FT_CHECK_RESULT(f) \ + { \ + FT_Error res = (f); \ + if (res != 0) { \ + fprintf(stderr, "Fatal : FreeType error is %d in %s at line %d\n", res, __FILE__, __LINE__); \ + assert(res == 0); \ + } \ + } #else - #include "stb_truetype.h" +#include "stb_truetype.h" #endif #ifdef VKVG_USE_HARFBUZZ - #include - #include +#include +#include #else #endif #ifdef VKVG_USE_FONTCONFIG - #include +#include #endif -#define FONT_PAGE_SIZE 1024 -#define FONT_CACHE_INIT_LAYERS 1 +#define FONT_PAGE_SIZE 1024 +#define FONT_CACHE_INIT_LAYERS 1 #define FONT_FILE_NAME_MAX_SIZE 1024 -#define FONT_NAME_MAX_SIZE 128 +#define FONT_NAME_MAX_SIZE 128 #include "vkvg_internal.h" #include "vkh_buffer.h" -//texture coordinates of one character in font cache array texture. +// texture coordinates of one character in font cache array texture. typedef struct { - vec4 bounds; /* normalized float bounds of character bitmap in font cache texture. */ - vec2i16 bmpDiff; /* Difference in pixel between char bitmap top left corner and char glyph*/ - uint8_t pageIdx; /* Page index in font cache texture array */ + vec4 bounds; /* normalized float bounds of character bitmap in font cache texture. */ + vec2i16 bmpDiff; /* Difference in pixel between char bitmap top left corner and char glyph*/ + uint8_t pageIdx; /* Page index in font cache texture array */ #ifdef VKVG_USE_FREETYPE - FT_Vector advance; /* horizontal or vertical advance */ + FT_Vector advance; /* horizontal or vertical advance */ #else - vec2 advance; + vec2 advance; #endif -}_char_ref; +} _char_ref; // Current location in font cache texture array for new character addition. Each font holds such structure to locate // where to upload new chars. typedef struct { - uint8_t pageIdx; /* Current page number in font cache */ - int penX; /* Current X in cache for next char addition */ - int penY; /* Current Y in cache for next char addition */ - int height; /* Height of current line pointed by this structure */ -}_tex_ref_t; - -// Loaded font structure, one per size, holds informations for glyphes upload in cache and the lookup table of characters. + uint8_t pageIdx; /* Current page number in font cache */ + int penX; /* Current X in cache for next char addition */ + int penY; /* Current Y in cache for next char addition */ + int height; /* Height of current line pointed by this structure */ +} _tex_ref_t; + +// Loaded font structure, one per size, holds informations for glyphes upload in cache and the lookup table of +// characters. typedef struct { #ifdef VKVG_USE_FREETYPE - FT_F26Dot6 charSize; /* Font size*/ - FT_Face face; /* FreeType face*/ + FT_F26Dot6 charSize; /* Font size*/ + FT_Face face; /* FreeType face*/ #else - uint32_t charSize; /* Font size in pixel */ - float scale; /* scale factor for the given size */ - int ascent; /* unscalled stb font metrics */ - int descent; - int lineGap; + uint32_t charSize; /* Font size in pixel */ + float scale; /* scale factor for the given size */ + int ascent; /* unscalled stb font metrics */ + int descent; + int lineGap; #endif #ifdef VKVG_USE_HARFBUZZ - hb_font_t* hb_font; /* HarfBuzz font instance*/ + hb_font_t *hb_font; /* HarfBuzz font instance*/ #endif - _char_ref** charLookup; /* Lookup table of characteres in cache, if not found, upload is queued*/ + _char_ref **charLookup; /* Lookup table of characteres in cache, if not found, upload is queued*/ - _tex_ref_t curLine; /* tex coord where to add new char bmp's */ -}_vkvg_font_t; + _tex_ref_t curLine; /* tex coord where to add new char bmp's */ +} _vkvg_font_t; /* Font identification structure */ typedef struct { - char** names; /* Resolved Input names to this font by fontConfig or custom name set by @ref vkvg_load_from_path*/ - uint32_t namesCount; /* Count of resolved names by fontConfig */ - unsigned char* fontBuffer; /* stb_truetype in memory buffer */ - long fontBufSize;/* */ - char* fontFile; /* Font file full path*/ + char **names; /* Resolved Input names to this font by fontConfig or custom name set by @ref vkvg_load_from_path*/ + uint32_t namesCount; /* Count of resolved names by fontConfig */ + unsigned char *fontBuffer; /* stb_truetype in memory buffer */ + long fontBufSize; /* */ + char *fontFile; /* Font file full path*/ #ifndef VKVG_USE_FREETYPE - stbtt_fontinfo stbInfo; /* stb_truetype structure */ - int ascent; /* unscalled stb font metrics */ - int descent; - int lineGap; + stbtt_fontinfo stbInfo; /* stb_truetype structure */ + int ascent; /* unscalled stb font metrics */ + int descent; + int lineGap; #endif - uint32_t sizeCount; /* available font size loaded */ - _vkvg_font_t* sizes; /* loaded font size array */ -}_vkvg_font_identity_t; + uint32_t sizeCount; /* available font size loaded */ + _vkvg_font_t *sizes; /* loaded font size array */ +} _vkvg_font_identity_t; // Font cache global structure, entry point for all font related operations. typedef struct { #ifdef VKVG_USE_FREETYPE - FT_Library library; /* FreeType library*/ + FT_Library library; /* FreeType library*/ #else #endif #ifdef VKVG_USE_FONTCONFIG - FcConfig* config; /* Font config, used to find font files by font names*/ + FcConfig *config; /* Font config, used to find font files by font names*/ #endif - int stagingX; /* x pen in host buffer */ - uint8_t* hostBuff; /* host memory where bitmaps are first loaded */ - - VkCommandBuffer cmd; /* vulkan command buffer for font textures upload */ - vkh_buffer_t buff; /* stagin buffer */ - VkhImage texture; /* 2d array texture used by contexts to draw characteres */ - VkFormat texFormat; /* Format of the fonts texture array */ - uint8_t texPixelSize; /* Size in byte of a single pixel in a font texture */ - uint8_t texLength; /* layer count of 2d array texture, starts with FONT_CACHE_INIT_LAYERS count and increased when needed */ - int* pensY; /* array of current y pen positions for each texture in cache 2d array */ - VkFence uploadFence; /* Signaled when upload is finished */ - mtx_t mutex; /* font cache global mutex, used only if device is in thread aware mode (see: vkvg_device_set_thread_aware) */ - - _vkvg_font_identity_t* fonts; /* Loaded fonts structure array */ - int32_t fontsCount; /* Loaded fonts array count*/ -}_font_cache_t; - -#define LOCK_FONTCACHE(dev) \ - if (dev->threadAware)\ - mtx_lock (&dev->fontCache->mutex); -#define UNLOCK_FONTCACHE(dev) \ - if (dev->threadAware)\ - mtx_unlock (&dev->fontCache->mutex); + int stagingX; /* x pen in host buffer */ + uint8_t *hostBuff; /* host memory where bitmaps are first loaded */ + + VkCommandBuffer cmd; /* vulkan command buffer for font textures upload */ + vkh_buffer_t buff; /* stagin buffer */ + VkhImage texture; /* 2d array texture used by contexts to draw characteres */ + VkFormat texFormat; /* Format of the fonts texture array */ + uint8_t texPixelSize; /* Size in byte of a single pixel in a font texture */ + uint8_t texLength; /* layer count of 2d array texture, starts with FONT_CACHE_INIT_LAYERS count and increased when + needed */ + int *pensY; /* array of current y pen positions for each texture in cache 2d array */ + VkFence uploadFence; /* Signaled when upload is finished */ + mtx_t mutex; /* font cache global mutex, used only if device is in thread aware mode (see: + vkvg_device_set_thread_aware) */ + + _vkvg_font_identity_t *fonts; /* Loaded fonts structure array */ + int32_t fontsCount; /* Loaded fonts array count*/ +} _font_cache_t; + +#define LOCK_FONTCACHE(dev) \ + if (dev->threadAware) \ + mtx_lock(&dev->fontCache->mutex); +#define UNLOCK_FONTCACHE(dev) \ + if (dev->threadAware) \ + mtx_unlock(&dev->fontCache->mutex); // Precompute everything necessary to measure and draw one line of text, usefull to draw the same text multiple times. typedef struct _vkvg_text_run_t { - _vkvg_font_identity_t* fontId; /* vkvg font structure pointer */ - _vkvg_font_t* font; /* vkvg font structure pointer */ - VkvgDevice dev; /* vkvg device associated with this text run */ - vkvg_text_extents_t extents; /* store computed text extends */ - const char* text; /* utf8 char array of text*/ - unsigned int glyph_count;/* Total glyph count */ + _vkvg_font_identity_t *fontId; /* vkvg font structure pointer */ + _vkvg_font_t *font; /* vkvg font structure pointer */ + VkvgDevice dev; /* vkvg device associated with this text run */ + vkvg_text_extents_t extents; /* store computed text extends */ + const char *text; /* utf8 char array of text*/ + unsigned int glyph_count; /* Total glyph count */ #ifdef VKVG_USE_HARFBUZZ - hb_buffer_t* hbBuf; /* HarfBuzz buffer of text */ - hb_glyph_position_t* glyphs; /* HarfBuzz computed glyph positions array */ + hb_buffer_t *hbBuf; /* HarfBuzz buffer of text */ + hb_glyph_position_t *glyphs; /* HarfBuzz computed glyph positions array */ #else - vkvg_glyph_info_t* glyphs; /* computed glyph positions array */ + vkvg_glyph_info_t *glyphs; /* computed glyph positions array */ #endif } vkvg_text_run_t; -//Create font cache. -void _fonts_cache_create (VkvgDevice dev); -//Release all ressources of font cache. -void _font_cache_destroy (VkvgDevice dev); -_vkvg_font_identity_t *_font_cache_add_font_identity (VkvgContext ctx, const char* fontFile, const char *name); -bool _font_cache_load_font_file_in_memory (_vkvg_font_identity_t* fontId); -//Draw text -void _font_cache_show_text (VkvgContext ctx, const char* text); -//Get text dimmensions -void _font_cache_text_extents (VkvgContext ctx, const char* text, int length, vkvg_text_extents_t *extents); -//Get font global dimmensions -void _font_cache_font_extents (VkvgContext ctx, vkvg_font_extents_t* extents); -//Create text object that could be drawn multiple times minimizing harfbuzz and compute processing. -void _font_cache_create_text_run (VkvgContext ctx, const char* text, int length, VkvgText textRun); -//Release ressources held by a text run. -void _font_cache_destroy_text_run (VkvgText textRun); -//Draw text run -void _font_cache_show_text_run (VkvgContext ctx, VkvgText tr); -//update context font cache descriptor set -void _font_cache_update_context_descset (VkvgContext ctx); +// Create font cache. +void _fonts_cache_create(VkvgDevice dev); +// Release all ressources of font cache. +void _font_cache_destroy(VkvgDevice dev); +_vkvg_font_identity_t *_font_cache_add_font_identity(VkvgContext ctx, const char *fontFile, const char *name); +bool _font_cache_load_font_file_in_memory(_vkvg_font_identity_t *fontId); +// Draw text +void _font_cache_show_text(VkvgContext ctx, const char *text); +// Get text dimmensions +void _font_cache_text_extents(VkvgContext ctx, const char *text, int length, vkvg_text_extents_t *extents); +// Get font global dimmensions +void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t *extents); +// Create text object that could be drawn multiple times minimizing harfbuzz and compute processing. +void _font_cache_create_text_run(VkvgContext ctx, const char *text, int length, VkvgText textRun); +// Release ressources held by a text run. +void _font_cache_destroy_text_run(VkvgText textRun); +// Draw text run +void _font_cache_show_text_run(VkvgContext ctx, VkvgText tr); +// update context font cache descriptor set +void _font_cache_update_context_descset(VkvgContext ctx); #endif diff --git a/src/vkvg_internal.h b/src/vkvg_internal.h index 535ca81..3afbe43 100644 --- a/src/vkvg_internal.h +++ b/src/vkvg_internal.h @@ -22,14 +22,14 @@ #ifndef VKVG_INTERNAL_H #define VKVG_INTERNAL_H - //disable warning on iostream functions on windows +// disable warning on iostream functions on windows #define _CRT_SECURE_NO_WARNINGS #include #include #include #include -#include // needed before stdarg.h on Windows +#include // needed before stdarg.h on Windows #include #include @@ -37,61 +37,65 @@ #include #ifndef M_PIF - #define M_PIF 3.14159265358979323846f /* float pi */ - #define M_PIF_2 1.57079632679489661923f - #define M_2_PIF 0.63661977236758134308f // 2/pi +#define M_PIF 3.14159265358979323846f /* float pi */ +#define M_PIF_2 1.57079632679489661923f +#define M_2_PIF 0.63661977236758134308f // 2/pi #endif /*#ifndef M_2_PI - #define M_2_PI 0.63661977236758134308 // 2/pi + #define M_2_PI 0.63661977236758134308 // 2/pi #endif*/ #ifdef DEBUG -#define LOG(level,...) { \ - if ((vkvg_log_level) & (level)) \ - fprintf (stdout, __VA_ARGS__); \ -} +#define LOG(level, ...) \ + { \ + if ((vkvg_log_level) & (level)) \ + fprintf(stdout, __VA_ARGS__); \ + } #else #define LOG #endif -#define PATH_CLOSED_BIT 0x80000000 /* most significant bit of path elmts is closed/open path state */ -#define PATH_HAS_CURVES_BIT 0x40000000 /* 2rd most significant bit of path elmts is curved status - * for main path, this indicate that curve datas are present. - * For segments, this indicate that the segment is curved or not */ -#define PATH_IS_CONVEX_BIT 0x20000000 /* simple rectangle or circle. */ -#define PATH_ELT_MASK 0x1FFFFFFF /* Bit mask for fetching path element value */ +#define PATH_CLOSED_BIT 0x80000000 /* most significant bit of path elmts is closed/open path state */ +#define PATH_HAS_CURVES_BIT \ + 0x40000000 /* 2rd most significant bit of path elmts is curved status \ + * for main path, this indicate that curve datas are present. \ + * For segments, this indicate that the segment is curved or not */ +#define PATH_IS_CONVEX_BIT 0x20000000 /* simple rectangle or circle. */ +#define PATH_ELT_MASK 0x1FFFFFFF /* Bit mask for fetching path element value */ -#define ROUNDF(f, c) (((float)((int)((f) * (c))) / (c))) -#define ROUND_DOWN(v,p) (floorf(v * p) / p) -#define EQUF(a, b) (fabsf(a-(b))<=FLT_EPSILON) +#define ROUNDF(f, c) (((float)((int)((f) * (c))) / (c))) +#define ROUND_DOWN(v, p) (floorf(v * p) / p) +#define EQUF(a, b) (fabsf(a - (b)) <= FLT_EPSILON) #ifndef MAX - #define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #ifndef MIN - #define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif #include "deps/tinycthread.h" #include "cross_os.h" -//width of the stencil buffer will determine the number of context saving/restore layers -//the two first bits of the stencil are the FILL and the CLIP bits, all other bits are -//used to store clipping bit on context saving. 8 bit stencil will allow 6 save/restore layer +// width of the stencil buffer will determine the number of context saving/restore layers +// the two first bits of the stencil are the FILL and the CLIP bits, all other bits are +// used to store clipping bit on context saving. 8 bit stencil will allow 6 save/restore layer #define FB_COLOR_FORMAT VK_FORMAT_B8G8R8A8_UNORM -#define VKVG_SURFACE_IMGS_REQUIREMENTS (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|\ - VK_FORMAT_FEATURE_TRANSFER_DST_BIT|VK_FORMAT_FEATURE_TRANSFER_SRC_BIT|VK_FORMAT_FEATURE_BLIT_SRC_BIT) -#define VKVG_PNG_WRITE_IMG_REQUIREMENTS (VK_FORMAT_FEATURE_TRANSFER_SRC_BIT|VK_FORMAT_FEATURE_TRANSFER_DST_BIT|VK_FORMAT_FEATURE_BLIT_DST_BIT) -//30 seconds fence timeout +#define VKVG_SURFACE_IMGS_REQUIREMENTS \ + (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | \ + VK_FORMAT_FEATURE_TRANSFER_DST_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT) +#define VKVG_PNG_WRITE_IMG_REQUIREMENTS \ + (VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT) +// 30 seconds fence timeout #define VKVG_FENCE_TIMEOUT 30000000000 -//#define VKVG_FENCE_TIMEOUT 10000 +// #define VKVG_FENCE_TIMEOUT 10000 #include "vkvg.h" #include "vkh.h" #include "vectors.h" /*typedef struct { - vkvg_status_t status; + vkvg_status_t status; } _vkvg_no_mem_struct;*/ static vkvg_status_t _no_mem_status = VKVG_STATUS_NO_MEMORY; diff --git a/src/vkvg_matrix.c b/src/vkvg_matrix.c index 998ece0..c77f329 100644 --- a/src/vkvg_matrix.c +++ b/src/vkvg_matrix.c @@ -20,8 +20,8 @@ * THE SOFTWARE. */ -//most of the matrix logic is grabbed from cairo, so here is the -//licence: +// most of the matrix logic is grabbed from cairo, so here is the +// licence: /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California @@ -62,206 +62,168 @@ #define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */ -//matrix computations mainly taken from http://cairographics.org -static void _vkvg_matrix_scalar_multiply (vkvg_matrix_t *matrix, float scalar) -{ - matrix->xx *= scalar; - matrix->yx *= scalar; +// matrix computations mainly taken from http://cairographics.org +static void _vkvg_matrix_scalar_multiply(vkvg_matrix_t *matrix, float scalar) { + matrix->xx *= scalar; + matrix->yx *= scalar; - matrix->xy *= scalar; - matrix->yy *= scalar; + matrix->xy *= scalar; + matrix->yy *= scalar; - matrix->x0 *= scalar; - matrix->y0 *= scalar; + matrix->x0 *= scalar; + matrix->y0 *= scalar; } -void _vkvg_matrix_get_affine (const vkvg_matrix_t *matrix, - float *xx, float *yx, - float *xy, float *yy, - float *x0, float *y0) -{ - *xx = matrix->xx; - *yx = matrix->yx; - - *xy = matrix->xy; - *yy = matrix->yy; - - if (x0) - *x0 = matrix->x0; - if (y0) - *y0 = matrix->y0; +void _vkvg_matrix_get_affine(const vkvg_matrix_t *matrix, float *xx, float *yx, float *xy, float *yy, float *x0, + float *y0) { + *xx = matrix->xx; + *yx = matrix->yx; + + *xy = matrix->xy; + *yy = matrix->yy; + + if (x0) + *x0 = matrix->x0; + if (y0) + *y0 = matrix->y0; } -static void _vkvg_matrix_compute_adjoint (vkvg_matrix_t *matrix) -{ - /* adj (A) = transpose (C:cofactor (A,i,j)) */ - float a, b, c, d, tx, ty; - - _vkvg_matrix_get_affine (matrix, - &a, &b, - &c, &d, - &tx, &ty); - - vkvg_matrix_init (matrix, - d, -b, - -c, a, - c*ty - d*tx, b*tx - a*ty); +static void _vkvg_matrix_compute_adjoint(vkvg_matrix_t *matrix) { + /* adj (A) = transpose (C:cofactor (A,i,j)) */ + float a, b, c, d, tx, ty; + + _vkvg_matrix_get_affine(matrix, &a, &b, &c, &d, &tx, &ty); + + vkvg_matrix_init(matrix, d, -b, -c, a, c * ty - d * tx, b * tx - a * ty); } -float _vkvg_matrix_compute_determinant (const vkvg_matrix_t *matrix) -{ - float a, b, c, d; +float _vkvg_matrix_compute_determinant(const vkvg_matrix_t *matrix) { + float a, b, c, d; - a = matrix->xx; b = matrix->yx; - c = matrix->xy; d = matrix->yy; + a = matrix->xx; + b = matrix->yx; + c = matrix->xy; + d = matrix->yy; - return a*d - b*c; + return a * d - b * c; } -vkvg_status_t vkvg_matrix_invert (vkvg_matrix_t *matrix) -{ - float det; +vkvg_status_t vkvg_matrix_invert(vkvg_matrix_t *matrix) { + float det; - /* Simple scaling|translation matrices are quite common... */ - if (matrix->xy == 0. && matrix->yx == 0.) { - matrix->x0 = -matrix->x0; - matrix->y0 = -matrix->y0; + /* Simple scaling|translation matrices are quite common... */ + if (matrix->xy == 0. && matrix->yx == 0.) { + matrix->x0 = -matrix->x0; + matrix->y0 = -matrix->y0; - if (matrix->xx != 1.f) { - if (matrix->xx == 0.) - return VKVG_STATUS_INVALID_MATRIX; + if (matrix->xx != 1.f) { + if (matrix->xx == 0.) + return VKVG_STATUS_INVALID_MATRIX; - matrix->xx = 1.f / matrix->xx; - matrix->x0 *= matrix->xx; - } + matrix->xx = 1.f / matrix->xx; + matrix->x0 *= matrix->xx; + } - if (matrix->yy != 1.f) { - if (matrix->yy == 0.) - return VKVG_STATUS_INVALID_MATRIX; + if (matrix->yy != 1.f) { + if (matrix->yy == 0.) + return VKVG_STATUS_INVALID_MATRIX; - matrix->yy = 1.f / matrix->yy; - matrix->y0 *= matrix->yy; - } + matrix->yy = 1.f / matrix->yy; + matrix->y0 *= matrix->yy; + } - return VKVG_STATUS_SUCCESS; - } + return VKVG_STATUS_SUCCESS; + } - /* inv (A) = 1/det (A) * adj (A) */ - det = _vkvg_matrix_compute_determinant (matrix); + /* inv (A) = 1/det (A) * adj (A) */ + det = _vkvg_matrix_compute_determinant(matrix); - if (! ISFINITE (det)) - return VKVG_STATUS_INVALID_MATRIX; + if (!ISFINITE(det)) + return VKVG_STATUS_INVALID_MATRIX; - if (det == 0) - return VKVG_STATUS_INVALID_MATRIX; + if (det == 0) + return VKVG_STATUS_INVALID_MATRIX; - _vkvg_matrix_compute_adjoint (matrix); - _vkvg_matrix_scalar_multiply (matrix, 1 / det); + _vkvg_matrix_compute_adjoint(matrix); + _vkvg_matrix_scalar_multiply(matrix, 1 / det); - return VKVG_STATUS_SUCCESS; -} -void vkvg_matrix_init_identity (vkvg_matrix_t *matrix) -{ - vkvg_matrix_init (matrix, - 1, 0, - 0, 1, - 0, 0); + return VKVG_STATUS_SUCCESS; } +void vkvg_matrix_init_identity(vkvg_matrix_t *matrix) { vkvg_matrix_init(matrix, 1, 0, 0, 1, 0, 0); } -void vkvg_matrix_init (vkvg_matrix_t *matrix, - float xx, float yx, - float xy, float yy, - float x0, float y0) -{ - matrix->xx = xx; matrix->yx = yx; - matrix->xy = xy; matrix->yy = yy; - matrix->x0 = x0; matrix->y0 = y0; +void vkvg_matrix_init(vkvg_matrix_t *matrix, float xx, float yx, float xy, float yy, float x0, float y0) { + matrix->xx = xx; + matrix->yx = yx; + matrix->xy = xy; + matrix->yy = yy; + matrix->x0 = x0; + matrix->y0 = y0; } -void vkvg_matrix_init_translate (vkvg_matrix_t *matrix, float tx, float ty) -{ - vkvg_matrix_init (matrix, - 1, 0, - 0, 1, - tx, ty); -} -void vkvg_matrix_init_scale (vkvg_matrix_t *matrix, float sx, float sy) -{ - vkvg_matrix_init (matrix, - sx, 0, - 0, sy, - 0, 0); +void vkvg_matrix_init_translate(vkvg_matrix_t *matrix, float tx, float ty) { + vkvg_matrix_init(matrix, 1, 0, 0, 1, tx, ty); } -void vkvg_matrix_init_rotate (vkvg_matrix_t *matrix, float radians) -{ - float s; - float c; - - s = sinf (radians); - c = cosf (radians); - - vkvg_matrix_init (matrix, - c, s, - -s, c, - 0, 0); +void vkvg_matrix_init_scale(vkvg_matrix_t *matrix, float sx, float sy) { vkvg_matrix_init(matrix, sx, 0, 0, sy, 0, 0); } +void vkvg_matrix_init_rotate(vkvg_matrix_t *matrix, float radians) { + float s; + float c; + + s = sinf(radians); + c = cosf(radians); + + vkvg_matrix_init(matrix, c, s, -s, c, 0, 0); } -void vkvg_matrix_translate (vkvg_matrix_t *matrix, float tx, float ty) -{ - vkvg_matrix_t tmp; +void vkvg_matrix_translate(vkvg_matrix_t *matrix, float tx, float ty) { + vkvg_matrix_t tmp; - vkvg_matrix_init_translate (&tmp, tx, ty); + vkvg_matrix_init_translate(&tmp, tx, ty); - vkvg_matrix_multiply (matrix, &tmp, matrix); + vkvg_matrix_multiply(matrix, &tmp, matrix); } -void vkvg_matrix_scale (vkvg_matrix_t *matrix, float sx, float sy) -{ - vkvg_matrix_t tmp; +void vkvg_matrix_scale(vkvg_matrix_t *matrix, float sx, float sy) { + vkvg_matrix_t tmp; - vkvg_matrix_init_scale (&tmp, sx, sy); + vkvg_matrix_init_scale(&tmp, sx, sy); - vkvg_matrix_multiply (matrix, &tmp, matrix); + vkvg_matrix_multiply(matrix, &tmp, matrix); } -void vkvg_matrix_rotate (vkvg_matrix_t *matrix, float radians) -{ - vkvg_matrix_t tmp; +void vkvg_matrix_rotate(vkvg_matrix_t *matrix, float radians) { + vkvg_matrix_t tmp; - vkvg_matrix_init_rotate (&tmp, radians); + vkvg_matrix_init_rotate(&tmp, radians); - vkvg_matrix_multiply (matrix, &tmp, matrix); + vkvg_matrix_multiply(matrix, &tmp, matrix); } -void vkvg_matrix_multiply (vkvg_matrix_t *result, const vkvg_matrix_t *a, const vkvg_matrix_t *b) -{ - vkvg_matrix_t r; +void vkvg_matrix_multiply(vkvg_matrix_t *result, const vkvg_matrix_t *a, const vkvg_matrix_t *b) { + vkvg_matrix_t r; - r.xx = a->xx * b->xx + a->yx * b->xy; - r.yx = a->xx * b->yx + a->yx * b->yy; + r.xx = a->xx * b->xx + a->yx * b->xy; + r.yx = a->xx * b->yx + a->yx * b->yy; - r.xy = a->xy * b->xx + a->yy * b->xy; - r.yy = a->xy * b->yx + a->yy * b->yy; + r.xy = a->xy * b->xx + a->yy * b->xy; + r.yy = a->xy * b->yx + a->yy * b->yy; - r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0; - r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0; + r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0; + r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0; - *result = r; + *result = r; } -void vkvg_matrix_transform_distance (const vkvg_matrix_t *matrix, float *dx, float *dy) -{ - float new_x, new_y; +void vkvg_matrix_transform_distance(const vkvg_matrix_t *matrix, float *dx, float *dy) { + float new_x, new_y; - new_x = (matrix->xx * *dx + matrix->xy * *dy); - new_y = (matrix->yx * *dx + matrix->yy * *dy); + new_x = (matrix->xx * *dx + matrix->xy * *dy); + new_y = (matrix->yx * *dx + matrix->yy * *dy); - *dx = new_x; - *dy = new_y; + *dx = new_x; + *dy = new_y; } -void vkvg_matrix_transform_point (const vkvg_matrix_t *matrix, float *x, float *y) -{ - vkvg_matrix_transform_distance (matrix, x, y); +void vkvg_matrix_transform_point(const vkvg_matrix_t *matrix, float *x, float *y) { + vkvg_matrix_transform_distance(matrix, x, y); - *x += matrix->x0; - *y += matrix->y0; + *x += matrix->x0; + *y += matrix->y0; } -void vkvg_matrix_get_scale (const vkvg_matrix_t *matrix, float *sx, float *sy) { - *sx = sqrt (matrix->xx * matrix->xx + matrix->xy * matrix->xy); - /*if (matrix->xx < 0) - *sx = -*sx;*/ - *sy = sqrt (matrix->yx * matrix->yx + matrix->yy * matrix->yy); - /*if (matrix->yy < 0) - *sy = -*sy;*/ +void vkvg_matrix_get_scale(const vkvg_matrix_t *matrix, float *sx, float *sy) { + *sx = sqrt(matrix->xx * matrix->xx + matrix->xy * matrix->xy); + /*if (matrix->xx < 0) + *sx = -*sx;*/ + *sy = sqrt(matrix->yx * matrix->yx + matrix->yy * matrix->yy); + /*if (matrix->yy < 0) + *sy = -*sy;*/ } diff --git a/src/vkvg_matrix.h b/src/vkvg_matrix.h index 7607791..66db350 100644 --- a/src/vkvg_matrix.h +++ b/src/vkvg_matrix.h @@ -27,7 +27,4 @@ #include #include "vkvg.h" - - - #endif diff --git a/src/vkvg_pattern.c b/src/vkvg_pattern.c index acefab6..2aad091 100644 --- a/src/vkvg_pattern.c +++ b/src/vkvg_pattern.c @@ -25,225 +25,220 @@ #include "vkvg_device_internal.h" #include "vkvg_pattern.h" -VkvgPattern vkvg_pattern_create_for_surface (VkvgSurface surf){ - VkvgPattern pat = (vkvg_pattern_t*)calloc(1, sizeof(vkvg_pattern_t)); - if (!pat) - return (VkvgPattern)&_no_mem_status; - - pat->type = VKVG_PATTERN_TYPE_SURFACE; - pat->extend = VKVG_EXTEND_NONE; - pat->data = surf; - pat->references = 1; - - vkvg_surface_reference (surf); - if (surf->status) - pat->status = surf->status; - - return pat; -} -vkvg_status_t vkvg_pattern_get_linear_points (VkvgPattern pat, float* x0, float* y0, float* x1, float* y1) { - if (pat->status) - return pat->status; - if (pat->type != VKVG_PATTERN_TYPE_LINEAR) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; - - *x0 = grad->cp[0].x; - *y0 = grad->cp[0].y; - *x1 = grad->cp[0].z; - *y1 = grad->cp[0].w; - return VKVG_STATUS_SUCCESS; -} -vkvg_status_t vkvg_pattern_edit_linear (VkvgPattern pat, float x0, float y0, float x1, float y1){ - if (pat->status) - return pat->status; - if (pat->type != VKVG_PATTERN_TYPE_LINEAR) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; - - grad->cp[0] = (vec4){{x0}, {y0}, {x1}, {y1}}; - return VKVG_STATUS_SUCCESS; -} -VkvgPattern vkvg_pattern_create_linear (float x0, float y0, float x1, float y1){ - VkvgPattern pat = (vkvg_pattern_t*)calloc(1, sizeof(vkvg_pattern_t)); - if (!pat) - return (VkvgPattern)&_no_mem_status; - pat->type = VKVG_PATTERN_TYPE_LINEAR; - pat->extend = VKVG_EXTEND_NONE; - - pat->data = (void*)calloc(1,sizeof(vkvg_gradient_t)); - - if (pat->data) { - vkvg_pattern_edit_linear(pat, x0, y0, x1, y1); - pat->references = 1; - } else - pat->status = VKVG_STATUS_NO_MEMORY; - - return pat; -} -vkvg_status_t vkvg_pattern_edit_radial (VkvgPattern pat, - float cx0, float cy0, float radius0, - float cx1, float cy1, float radius1) { - if (pat->status) - return pat->status; - if (pat->type != VKVG_PATTERN_TYPE_RADIAL) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; - - vec2 c0 = {cx0, cy0}; - vec2 c1 = {cx1, cy1}; - - if (radius0 > radius1 - 1.0f) - radius0 = radius1 - 1.0f; - vec2 u = vec2_sub (c0, c1); - float l = vec2_length(u); - if (l + radius0 + 1.0f >= radius1) { - vec2 v = vec2_div_s(u, l); - c0 = vec2_add(c1, vec2_mult_s (v, radius1 - radius0 - 1.0f)); - } - - grad->cp[0] = (vec4){{c0.x}, {c0.y},{radius0},{0}}; - grad->cp[1] = (vec4){{c1.x}, {c1.y},{radius1},{0}}; - return VKVG_STATUS_SUCCESS; -} -VkvgPattern vkvg_pattern_create_radial (float cx0, float cy0, float radius0, - float cx1, float cy1, float radius1){ - VkvgPattern pat = (vkvg_pattern_t*)calloc(1, sizeof(vkvg_pattern_t)); - if (!pat) - return (VkvgPattern)&_no_mem_status; - pat->type = VKVG_PATTERN_TYPE_RADIAL; - pat->extend = VKVG_EXTEND_NONE; - - pat->data = (void*)calloc(1,sizeof(vkvg_gradient_t)); - - if (pat->data) { - vkvg_pattern_edit_radial (pat, cx0, cy0, radius0, cx1, cy1, radius1); - pat->references = 1; - } else - pat->status = VKVG_STATUS_NO_MEMORY; - - return pat; -} -VkvgPattern vkvg_pattern_reference (VkvgPattern pat) { - if (!pat->status) - pat->references++; - return pat; -} -uint32_t vkvg_pattern_get_reference_count (VkvgPattern pat) { - if (pat->status) - return 0; - return pat->references; -} -vkvg_status_t vkvg_pattern_add_color_stop (VkvgPattern pat, float offset, float r, float g, float b, float a) { - if (pat->status) - return pat->status; - if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; +VkvgPattern vkvg_pattern_create_for_surface(VkvgSurface surf) { + VkvgPattern pat = (vkvg_pattern_t *)calloc(1, sizeof(vkvg_pattern_t)); + if (!pat) + return (VkvgPattern)&_no_mem_status; + + pat->type = VKVG_PATTERN_TYPE_SURFACE; + pat->extend = VKVG_EXTEND_NONE; + pat->data = surf; + pat->references = 1; + + vkvg_surface_reference(surf); + if (surf->status) + pat->status = surf->status; + + return pat; +} +vkvg_status_t vkvg_pattern_get_linear_points(VkvgPattern pat, float *x0, float *y0, float *x1, float *y1) { + if (pat->status) + return pat->status; + if (pat->type != VKVG_PATTERN_TYPE_LINEAR) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; + + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; + + *x0 = grad->cp[0].x; + *y0 = grad->cp[0].y; + *x1 = grad->cp[0].z; + *y1 = grad->cp[0].w; + return VKVG_STATUS_SUCCESS; +} +vkvg_status_t vkvg_pattern_edit_linear(VkvgPattern pat, float x0, float y0, float x1, float y1) { + if (pat->status) + return pat->status; + if (pat->type != VKVG_PATTERN_TYPE_LINEAR) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; + + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; + + grad->cp[0] = (vec4){{x0}, {y0}, {x1}, {y1}}; + return VKVG_STATUS_SUCCESS; +} +VkvgPattern vkvg_pattern_create_linear(float x0, float y0, float x1, float y1) { + VkvgPattern pat = (vkvg_pattern_t *)calloc(1, sizeof(vkvg_pattern_t)); + if (!pat) + return (VkvgPattern)&_no_mem_status; + pat->type = VKVG_PATTERN_TYPE_LINEAR; + pat->extend = VKVG_EXTEND_NONE; + + pat->data = (void *)calloc(1, sizeof(vkvg_gradient_t)); + + if (pat->data) { + vkvg_pattern_edit_linear(pat, x0, y0, x1, y1); + pat->references = 1; + } else + pat->status = VKVG_STATUS_NO_MEMORY; + + return pat; +} +vkvg_status_t vkvg_pattern_edit_radial(VkvgPattern pat, float cx0, float cy0, float radius0, float cx1, float cy1, + float radius1) { + if (pat->status) + return pat->status; + if (pat->type != VKVG_PATTERN_TYPE_RADIAL) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; + + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; + + vec2 c0 = {cx0, cy0}; + vec2 c1 = {cx1, cy1}; + + if (radius0 > radius1 - 1.0f) + radius0 = radius1 - 1.0f; + vec2 u = vec2_sub(c0, c1); + float l = vec2_length(u); + if (l + radius0 + 1.0f >= radius1) { + vec2 v = vec2_div_s(u, l); + c0 = vec2_add(c1, vec2_mult_s(v, radius1 - radius0 - 1.0f)); + } + + grad->cp[0] = (vec4){{c0.x}, {c0.y}, {radius0}, {0}}; + grad->cp[1] = (vec4){{c1.x}, {c1.y}, {radius1}, {0}}; + return VKVG_STATUS_SUCCESS; +} +VkvgPattern vkvg_pattern_create_radial(float cx0, float cy0, float radius0, float cx1, float cy1, float radius1) { + VkvgPattern pat = (vkvg_pattern_t *)calloc(1, sizeof(vkvg_pattern_t)); + if (!pat) + return (VkvgPattern)&_no_mem_status; + pat->type = VKVG_PATTERN_TYPE_RADIAL; + pat->extend = VKVG_EXTEND_NONE; + + pat->data = (void *)calloc(1, sizeof(vkvg_gradient_t)); + + if (pat->data) { + vkvg_pattern_edit_radial(pat, cx0, cy0, radius0, cx1, cy1, radius1); + pat->references = 1; + } else + pat->status = VKVG_STATUS_NO_MEMORY; + + return pat; +} +VkvgPattern vkvg_pattern_reference(VkvgPattern pat) { + if (!pat->status) + pat->references++; + return pat; +} +uint32_t vkvg_pattern_get_reference_count(VkvgPattern pat) { + if (pat->status) + return 0; + return pat->references; +} +vkvg_status_t vkvg_pattern_add_color_stop(VkvgPattern pat, float offset, float r, float g, float b, float a) { + if (pat->status) + return pat->status; + if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; + + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; #ifdef VKVG_PREMULT_ALPHA - vkvg_color_t c = {a*r,a*g,a*b,a}; + vkvg_color_t c = {a * r, a * g, a * b, a}; #else - vkvg_color_t c = {r,g,b,a}; + vkvg_color_t c = {r, g, b, a}; #endif - grad->colors[grad->count] = c; + grad->colors[grad->count] = c; #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - grad->stops[grad->count] = offset; + grad->stops[grad->count] = offset; #else - grad->stops[grad->count].r = offset; + grad->stops[grad->count].r = offset; #endif - grad->count++; -} -void vkvg_pattern_set_extend (VkvgPattern pat, vkvg_extend_t extend){ - if (pat->status) - return; - pat->extend = extend; -} -void vkvg_pattern_set_filter (VkvgPattern pat, vkvg_filter_t filter){ - if (pat->status) - return; - pat->filter = filter; -} - -vkvg_extend_t vkvg_pattern_get_extend (VkvgPattern pat){ - if (pat->status) - return (vkvg_extend_t)0; - return pat->extend; -} -vkvg_filter_t vkvg_pattern_get_filter (VkvgPattern pat){ - if (pat->status) - return (vkvg_filter_t)0; - return pat->filter; -} -vkvg_pattern_type_t vkvg_pattern_get_type (VkvgPattern pat){ - if (pat->status) - return (vkvg_pattern_type_t)0; - return pat->type; -} -vkvg_status_t vkvg_pattern_get_color_stop_count (VkvgPattern pat, uint32_t* count) { - if (pat->status) - return pat->status; - if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; - *count = grad->count; - return VKVG_STATUS_SUCCESS; -} -vkvg_status_t vkvg_pattern_get_color_stop_rgba (VkvgPattern pat, uint32_t index, - float* offset, float* r, float* g, float* b, float* a) { - if (pat->status) - return pat->status; - if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; - if (index >= grad->count) - return VKVG_STATUS_INVALID_INDEX; + grad->count++; +} +void vkvg_pattern_set_extend(VkvgPattern pat, vkvg_extend_t extend) { + if (pat->status) + return; + pat->extend = extend; +} +void vkvg_pattern_set_filter(VkvgPattern pat, vkvg_filter_t filter) { + if (pat->status) + return; + pat->filter = filter; +} + +vkvg_extend_t vkvg_pattern_get_extend(VkvgPattern pat) { + if (pat->status) + return (vkvg_extend_t)0; + return pat->extend; +} +vkvg_filter_t vkvg_pattern_get_filter(VkvgPattern pat) { + if (pat->status) + return (vkvg_filter_t)0; + return pat->filter; +} +vkvg_pattern_type_t vkvg_pattern_get_type(VkvgPattern pat) { + if (pat->status) + return (vkvg_pattern_type_t)0; + return pat->type; +} +vkvg_status_t vkvg_pattern_get_color_stop_count(VkvgPattern pat, uint32_t *count) { + if (pat->status) + return pat->status; + if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; + *count = grad->count; + return VKVG_STATUS_SUCCESS; +} +vkvg_status_t vkvg_pattern_get_color_stop_rgba(VkvgPattern pat, uint32_t index, float *offset, float *r, float *g, + float *b, float *a) { + if (pat->status) + return pat->status; + if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; + if (index >= grad->count) + return VKVG_STATUS_INVALID_INDEX; #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - *offset = grad->stops[index]; + *offset = grad->stops[index]; #else - *offset = grad->stops[index].r; + *offset = grad->stops[index].r; #endif - vkvg_color_t c = grad->colors[index]; - *r = c.r; - *g = c.g; - *b = c.b; - *a = c.a; - return VKVG_STATUS_SUCCESS; -} -void vkvg_pattern_set_matrix (VkvgPattern pat, const vkvg_matrix_t* matrix) { - if (pat->status) - return; - pat->matrix = *matrix; - pat->hasMatrix = true; -} -void vkvg_pattern_get_matrix (VkvgPattern pat, vkvg_matrix_t* matrix) { - if (pat->status) - return; - if (pat->hasMatrix) - *matrix = pat->matrix; - else - *matrix = VKVG_IDENTITY_MATRIX; -} -vkvg_status_t vkvg_pattern_status (VkvgPattern pat) { - return pat->status; -} - -void vkvg_pattern_destroy(VkvgPattern pat) -{ - if (pat->status) - return; - pat->references--; - if (pat->references > 0) - return; - - if (pat->type == VKVG_PATTERN_TYPE_SURFACE) { - VkvgSurface surf = (VkvgSurface)pat->data; - vkvg_surface_destroy (surf); - }else - free (pat->data); - - free(pat); + vkvg_color_t c = grad->colors[index]; + *r = c.r; + *g = c.g; + *b = c.b; + *a = c.a; + return VKVG_STATUS_SUCCESS; +} +void vkvg_pattern_set_matrix(VkvgPattern pat, const vkvg_matrix_t *matrix) { + if (pat->status) + return; + pat->matrix = *matrix; + pat->hasMatrix = true; +} +void vkvg_pattern_get_matrix(VkvgPattern pat, vkvg_matrix_t *matrix) { + if (pat->status) + return; + if (pat->hasMatrix) + *matrix = pat->matrix; + else + *matrix = VKVG_IDENTITY_MATRIX; +} +vkvg_status_t vkvg_pattern_status(VkvgPattern pat) { return pat->status; } + +void vkvg_pattern_destroy(VkvgPattern pat) { + if (pat->status) + return; + pat->references--; + if (pat->references > 0) + return; + + if (pat->type == VKVG_PATTERN_TYPE_SURFACE) { + VkvgSurface surf = (VkvgSurface)pat->data; + vkvg_surface_destroy(surf); + } else + free(pat->data); + + free(pat); } diff --git a/src/vkvg_pattern.h b/src/vkvg_pattern.h index 2ad068d..0ccc7a5 100644 --- a/src/vkvg_pattern.h +++ b/src/vkvg_pattern.h @@ -25,25 +25,25 @@ #include "vkvg_internal.h" typedef struct _vkvg_pattern_t { - vkvg_status_t status; - uint32_t references; - vkvg_pattern_type_t type; - vkvg_extend_t extend; - vkvg_filter_t filter; - vkvg_matrix_t matrix; - bool hasMatrix; - void* data; -}vkvg_pattern_t; + vkvg_status_t status; + uint32_t references; + vkvg_pattern_type_t type; + vkvg_extend_t extend; + vkvg_filter_t filter; + vkvg_matrix_t matrix; + bool hasMatrix; + void *data; +} vkvg_pattern_t; typedef struct _vkvg_gradient_t { - vkvg_color_t colors[16]; + vkvg_color_t colors[16]; #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - float stops[16]; + float stops[16]; #else - vec4 stops[16]; + vec4 stops[16]; #endif - vec4 cp[2]; - uint32_t count; -}vkvg_gradient_t; + vec4 cp[2]; + uint32_t count; +} vkvg_gradient_t; #endif diff --git a/src/vkvg_surface.c b/src/vkvg_surface.c index 369adbd..fc28175 100644 --- a/src/vkvg_surface.c +++ b/src/vkvg_surface.c @@ -29,443 +29,430 @@ #include "stb_image_write.h" #include "vkh_image.h" -#define max(x,y) -void _transition_surf_images (VkvgSurface surf) { - LOCK_SURFACE(surf) - VkvgDevice dev = surf->dev; - - //_surface_wait_cmd (surf); - - vkh_cmd_begin (surf->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - VkhImage imgMs = surf->imgMS; - if (imgMs != NULL) - vkh_image_set_layout(surf->cmd, imgMs, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - - vkh_image_set_layout(surf->cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - vkh_image_set_layout (surf->cmd, surf->stencil, dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); - vkh_cmd_end (surf->cmd); - - _surface_submit_cmd (surf); - - UNLOCK_SURFACE(surf) +#define max(x, y) +void _transition_surf_images(VkvgSurface surf) { + LOCK_SURFACE(surf) + VkvgDevice dev = surf->dev; + + //_surface_wait_cmd (surf); + + vkh_cmd_begin(surf->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + VkhImage imgMs = surf->imgMS; + if (imgMs != NULL) + vkh_image_set_layout(surf->cmd, imgMs, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + + vkh_image_set_layout(surf->cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + vkh_image_set_layout(surf->cmd, surf->stencil, dev->stencilAspectFlag, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + vkh_cmd_end(surf->cmd); + + _surface_submit_cmd(surf); + + UNLOCK_SURFACE(surf) } -void vkvg_surface_clear (VkvgSurface surf) { - if (surf->status) - return; - _clear_surface(surf, VK_IMAGE_ASPECT_STENCIL_BIT|VK_IMAGE_ASPECT_COLOR_BIT); +void vkvg_surface_clear(VkvgSurface surf) { + if (surf->status) + return; + _clear_surface(surf, VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_COLOR_BIT); } -VkvgSurface vkvg_surface_create (VkvgDevice dev, uint32_t width, uint32_t height){ - VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); - if (surf->status) - return surf; +VkvgSurface vkvg_surface_create(VkvgDevice dev, uint32_t width, uint32_t height) { + VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); + if (surf->status) + return surf; - surf->width = MAX(1, width); - surf->height = MAX(1, height); - surf->newSurf = true;//used to clear all attacments on first render pass + surf->width = MAX(1, width); + surf->height = MAX(1, height); + surf->newSurf = true; // used to clear all attacments on first render pass - _create_surface_images (surf); + _create_surface_images(surf); - _transition_surf_images (surf); + _transition_surf_images(surf); - surf->status = VKVG_STATUS_SUCCESS; - vkvg_device_reference (surf->dev); - return surf; + surf->status = VKVG_STATUS_SUCCESS; + vkvg_device_reference(surf->dev); + return surf; } -VkvgSurface vkvg_surface_create_for_VkhImage (VkvgDevice dev, void* vkhImg) { - VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); - if (surf->status) - return surf; +VkvgSurface vkvg_surface_create_for_VkhImage(VkvgDevice dev, void *vkhImg) { + VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); + if (surf->status) + return surf; - if (!vkhImg) { - surf->status = VKVG_STATUS_INVALID_IMAGE; - return surf; - } + if (!vkhImg) { + surf->status = VKVG_STATUS_INVALID_IMAGE; + return surf; + } - VkhImage img = (VkhImage)vkhImg; - surf->width = img->infos.extent.width; - surf->height= img->infos.extent.height; + VkhImage img = (VkhImage)vkhImg; + surf->width = img->infos.extent.width; + surf->height = img->infos.extent.height; - surf->img = img; + surf->img = img; - vkh_image_create_sampler(img, VK_FILTER_NEAREST, VK_FILTER_NEAREST, - VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); + vkh_image_create_sampler(img, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); - _create_surface_secondary_images (surf); - _create_framebuffer (surf); + _create_surface_secondary_images(surf); + _create_framebuffer(surf); - _transition_surf_images (surf); - //_clear_surface (surf, VK_IMAGE_ASPECT_STENCIL_BIT); + _transition_surf_images(surf); + //_clear_surface (surf, VK_IMAGE_ASPECT_STENCIL_BIT); - surf->status = VKVG_STATUS_SUCCESS; - vkvg_device_reference (surf->dev); - return surf; + surf->status = VKVG_STATUS_SUCCESS; + vkvg_device_reference(surf->dev); + return surf; } -//TODO: it would be better to blit in original size and create ms final image with dest surf dims -VkvgSurface vkvg_surface_create_from_bitmap (VkvgDevice dev, unsigned char* img, uint32_t width, uint32_t height) { - VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); - if (surf->status) - return surf; - if (!img || width <= 0 || height <= 0) { - surf->status = VKVG_STATUS_INVALID_IMAGE; - return surf; - } - - surf->width = MAX(1, width); - surf->height = MAX(1, height); - - _create_surface_images (surf); - - uint32_t imgSize = width * height * 4; - VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}; - //original format image - VkhImage stagImg= vkh_image_create ((VkhDevice)surf->dev,VK_FORMAT_R8G8B8A8_UNORM,surf->width,surf->height,VK_IMAGE_TILING_LINEAR, - VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - //bgra bliting target - VkhImage tmpImg = vkh_image_create ((VkhDevice)surf->dev,surf->format,surf->width,surf->height,VK_IMAGE_TILING_LINEAR, - VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - vkh_image_create_descriptor (tmpImg, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, - VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); - //staging buffer - vkh_buffer_t buff = {0}; - vkh_buffer_init((VkhDevice)dev, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VKH_MEMORY_USAGE_CPU_TO_GPU, - imgSize, &buff, true); - - memcpy (vkh_buffer_get_mapped_pointer (&buff), img, imgSize); - - VkCommandBuffer cmd = surf->cmd; - - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - - VkBufferImageCopy bufferCopyRegion = { .imageSubresource = imgSubResLayers, - .imageExtent = {surf->width,surf->height,1}}; - - vkCmdCopyBufferToImage(cmd, buff.buffer, - vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); - - vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, tmpImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkImageBlit blit = { - .srcSubresource = imgSubResLayers, - .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - .dstSubresource = imgSubResLayers, - .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - }; - vkCmdBlitImage (cmd, - vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (tmpImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); - - vkh_image_set_layout (cmd, tmpImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - - vkh_cmd_end (cmd); - - _surface_submit_cmd (surf);//lock surface? - - vkh_buffer_reset (&buff); - vkh_image_destroy (stagImg); - - surf->newSurf = false; - - //create tmp context with rendering pipeline to create the multisample img - VkvgContext ctx = vkvg_create (surf); - -/* VkClearAttachment ca = {VK_IMAGE_ASPECT_COLOR_BIT,0, { 0.0f, 0.0f, 0.0f, 0.0f }}; - VkClearRect cr = {{{0,0},{surf->width,surf->height}},0,1}; - vkCmdClearAttachments(ctx->cmd, 1, &ca, 1, &cr);*/ - - vec4 srcRect = {.x=0,.y=0,.width=(float)surf->width,.height=(float)surf->height}; - ctx->pushConsts.source = srcRect; - ctx->pushConsts.fsq_patternType = (ctx->pushConsts.fsq_patternType & FULLSCREEN_BIT) + VKVG_PATTERN_TYPE_SURFACE; - - //_update_push_constants (ctx); - _update_descriptor_set (ctx, tmpImg, ctx->dsSrc); - _ensure_renderpass_is_started (ctx); - - vkvg_paint (ctx); - vkvg_destroy (ctx); - - vkh_image_destroy (tmpImg); - - surf->status = VKVG_STATUS_SUCCESS; - vkvg_device_reference (surf->dev); - return surf; +// TODO: it would be better to blit in original size and create ms final image with dest surf dims +VkvgSurface vkvg_surface_create_from_bitmap(VkvgDevice dev, unsigned char *img, uint32_t width, uint32_t height) { + VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); + if (surf->status) + return surf; + if (!img || width <= 0 || height <= 0) { + surf->status = VKVG_STATUS_INVALID_IMAGE; + return surf; + } + + surf->width = MAX(1, width); + surf->height = MAX(1, height); + + _create_surface_images(surf); + + uint32_t imgSize = width * height * 4; + VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + // original format image + VkhImage stagImg = vkh_image_create((VkhDevice)surf->dev, VK_FORMAT_R8G8B8A8_UNORM, surf->width, surf->height, + VK_IMAGE_TILING_LINEAR, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + // bgra bliting target + VkhImage tmpImg = + vkh_image_create((VkhDevice)surf->dev, surf->format, surf->width, surf->height, VK_IMAGE_TILING_LINEAR, + VKH_MEMORY_USAGE_GPU_ONLY, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + vkh_image_create_descriptor(tmpImg, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + // staging buffer + vkh_buffer_t buff = {0}; + vkh_buffer_init((VkhDevice)dev, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VKH_MEMORY_USAGE_CPU_TO_GPU, imgSize, &buff, + true); + + memcpy(vkh_buffer_get_mapped_pointer(&buff), img, imgSize); + + VkCommandBuffer cmd = surf->cmd; + + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkBufferImageCopy bufferCopyRegion = {.imageSubresource = imgSubResLayers, + .imageExtent = {surf->width, surf->height, 1}}; + + vkCmdCopyBufferToImage(cmd, buff.buffer, vkh_image_get_vkimage(stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, + &bufferCopyRegion); + + vkh_image_set_layout(cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, tmpImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkImageBlit blit = { + .srcSubresource = imgSubResLayers, + .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + .dstSubresource = imgSubResLayers, + .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + }; + vkCmdBlitImage(cmd, vkh_image_get_vkimage(stagImg), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(tmpImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); + + vkh_image_set_layout(cmd, tmpImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + vkh_cmd_end(cmd); + + _surface_submit_cmd(surf); // lock surface? + + vkh_buffer_reset(&buff); + vkh_image_destroy(stagImg); + + surf->newSurf = false; + + // create tmp context with rendering pipeline to create the multisample img + VkvgContext ctx = vkvg_create(surf); + + /* VkClearAttachment ca = {VK_IMAGE_ASPECT_COLOR_BIT,0, { 0.0f, 0.0f, 0.0f, 0.0f }}; + VkClearRect cr = {{{0,0},{surf->width,surf->height}},0,1}; + vkCmdClearAttachments(ctx->cmd, 1, &ca, 1, &cr);*/ + + vec4 srcRect = {.x = 0, .y = 0, .width = (float)surf->width, .height = (float)surf->height}; + ctx->pushConsts.source = srcRect; + ctx->pushConsts.fsq_patternType = (ctx->pushConsts.fsq_patternType & FULLSCREEN_BIT) + VKVG_PATTERN_TYPE_SURFACE; + + //_update_push_constants (ctx); + _update_descriptor_set(ctx, tmpImg, ctx->dsSrc); + _ensure_renderpass_is_started(ctx); + + vkvg_paint(ctx); + vkvg_destroy(ctx); + + vkh_image_destroy(tmpImg); + + surf->status = VKVG_STATUS_SUCCESS; + vkvg_device_reference(surf->dev); + return surf; } -VkvgSurface vkvg_surface_create_from_image (VkvgDevice dev, const char* filePath) { - int w = 0, - h = 0, - channels = 0; - unsigned char *img = stbi_load(filePath, &w, &h, &channels, 4);//force 4 components per pixel - if (!img){ - LOG(VKVG_LOG_ERR, "Could not load texture from %s, %s\n", filePath, stbi_failure_reason()); - return (VkvgSurface)&_no_mem_status; - } +VkvgSurface vkvg_surface_create_from_image(VkvgDevice dev, const char *filePath) { + int w = 0, h = 0, channels = 0; + unsigned char *img = stbi_load(filePath, &w, &h, &channels, 4); // force 4 components per pixel + if (!img) { + LOG(VKVG_LOG_ERR, "Could not load texture from %s, %s\n", filePath, stbi_failure_reason()); + return (VkvgSurface)&_no_mem_status; + } - VkvgSurface surf = vkvg_surface_create_from_bitmap(dev, img, (uint32_t)w, (uint32_t)h); + VkvgSurface surf = vkvg_surface_create_from_bitmap(dev, img, (uint32_t)w, (uint32_t)h); - stbi_image_free (img); + stbi_image_free(img); - return surf; + return surf; } -void vkvg_surface_destroy(VkvgSurface surf) -{ - if (surf->status) - return; +void vkvg_surface_destroy(VkvgSurface surf) { + if (surf->status) + return; - LOCK_SURFACE(surf) - surf->references--; - if (surf->references > 0) { - UNLOCK_SURFACE(surf) - return; - } - UNLOCK_SURFACE(surf) + LOCK_SURFACE(surf) + surf->references--; + if (surf->references > 0) { + UNLOCK_SURFACE(surf) + return; + } + UNLOCK_SURFACE(surf) - vkDestroyCommandPool(surf->dev->vkDev, surf->cmdPool, NULL); - vkDestroyFramebuffer(surf->dev->vkDev, surf->fb, NULL); + vkDestroyCommandPool(surf->dev->vkDev, surf->cmdPool, NULL); + vkDestroyFramebuffer(surf->dev->vkDev, surf->fb, NULL); - if (!surf->img->imported) - vkh_image_destroy(surf->img); + if (!surf->img->imported) + vkh_image_destroy(surf->img); - vkh_image_destroy(surf->imgMS); - vkh_image_destroy(surf->stencil); + vkh_image_destroy(surf->imgMS); + vkh_image_destroy(surf->stencil); - if (surf->dev->threadAware) - mtx_destroy (&surf->mutex); + if (surf->dev->threadAware) + mtx_destroy(&surf->mutex); #if VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - vkDestroySemaphore (surf->dev->vkDev, surf->timeline, NULL); + vkDestroySemaphore(surf->dev->vkDev, surf->timeline, NULL); #else - vkDestroyFence (surf->dev->vkDev, surf->flushFence, NULL); + vkDestroyFence(surf->dev->vkDev, surf->flushFence, NULL); #endif - vkvg_device_destroy (surf->dev); - free(surf); + vkvg_device_destroy(surf->dev); + free(surf); } -VkvgSurface vkvg_surface_reference (VkvgSurface surf) { - if (!surf->status) { - LOCK_SURFACE(surf) - surf->references++; - UNLOCK_SURFACE(surf) - } - return surf; +VkvgSurface vkvg_surface_reference(VkvgSurface surf) { + if (!surf->status) { + LOCK_SURFACE(surf) + surf->references++; + UNLOCK_SURFACE(surf) + } + return surf; } -uint32_t vkvg_surface_get_reference_count (VkvgSurface surf) { - if (surf->status) - return 0; - return surf->references; +uint32_t vkvg_surface_get_reference_count(VkvgSurface surf) { + if (surf->status) + return 0; + return surf->references; } -VkImage vkvg_surface_get_vk_image(VkvgSurface surf) -{ - if (surf->status) - return NULL; - if (surf->dev->deferredResolve) - _explicit_ms_resolve(surf); - return vkh_image_get_vkimage (surf->img); +VkImage vkvg_surface_get_vk_image(VkvgSurface surf) { + if (surf->status) + return NULL; + if (surf->dev->deferredResolve) + _explicit_ms_resolve(surf); + return vkh_image_get_vkimage(surf->img); } -void vkvg_surface_resolve (VkvgSurface surf){ - if (surf->status || !surf->dev->deferredResolve) - return; - _explicit_ms_resolve(surf); +void vkvg_surface_resolve(VkvgSurface surf) { + if (surf->status || !surf->dev->deferredResolve) + return; + _explicit_ms_resolve(surf); } -VkFormat vkvg_surface_get_vk_format(VkvgSurface surf) -{ - if (surf->status) - return VK_FORMAT_UNDEFINED; - return surf->format; +VkFormat vkvg_surface_get_vk_format(VkvgSurface surf) { + if (surf->status) + return VK_FORMAT_UNDEFINED; + return surf->format; } -uint32_t vkvg_surface_get_width (VkvgSurface surf) { - if (surf->status) - return 0; - return surf->width; +uint32_t vkvg_surface_get_width(VkvgSurface surf) { + if (surf->status) + return 0; + return surf->width; } -uint32_t vkvg_surface_get_height (VkvgSurface surf) { - if (surf->status) - return 0; - return surf->height; +uint32_t vkvg_surface_get_height(VkvgSurface surf) { + if (surf->status) + return 0; + return surf->height; } -vkvg_status_t vkvg_surface_write_to_png (VkvgSurface surf, const char* path){ - if (surf->status) { - LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, invalid status: %d\n", surf->status); - return VKVG_STATUS_INVALID_STATUS; - } - if (surf->dev->status) { - LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, invalid device status: %d\n", surf->dev->status); - return VKVG_STATUS_INVALID_STATUS; - } - if (surf->dev->pngStagFormat == VK_FORMAT_UNDEFINED) { - LOG(VKVG_LOG_ERR, "no suitable image format for png write\n"); - return VKVG_STATUS_INVALID_FORMAT; - } - if (!path) { - LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, null path\n"); - return VKVG_STATUS_WRITE_ERROR; - } - LOCK_SURFACE(surf) - VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}; - VkvgDevice dev = surf->dev; - - //RGBA to blit to, surf img is bgra - VkhImage stagImg; - - if (dev->pngStagTiling == VK_IMAGE_TILING_LINEAR) - stagImg = vkh_image_create ((VkhDevice)surf->dev, dev->pngStagFormat, surf->width, surf->height, dev->pngStagTiling, - VKH_MEMORY_USAGE_GPU_TO_CPU, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - else - stagImg = vkh_image_create ((VkhDevice)surf->dev, dev->pngStagFormat, surf->width,surf->height, dev->pngStagTiling, - VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - - VkCommandBuffer cmd = surf->cmd; - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkImageBlit blit = { - .srcSubresource = imgSubResLayers, - .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - .dstSubresource = imgSubResLayers, - .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - }; - vkCmdBlitImage (cmd, - vkh_image_get_vkimage (surf->img), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_NEAREST); - - vkh_cmd_end (cmd); - - _surface_submit_cmd (surf); - - VkhImage stagImgLinear = stagImg; - - if (dev->pngStagTiling == VK_IMAGE_TILING_OPTIMAL) { - stagImgLinear = vkh_image_create ((VkhDevice)surf->dev, dev->pngStagFormat, surf->width, surf->height, VK_IMAGE_TILING_LINEAR, - VKH_MEMORY_USAGE_GPU_TO_CPU, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - VkImageCopy cpy = { - .srcSubresource = imgSubResLayers, - .srcOffset = {0}, - .dstSubresource = imgSubResLayers, - .dstOffset = {0}, - .extent = {(int32_t)surf->width, (int32_t)surf->height, 1} - }; - - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (cmd, stagImgLinear, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkCmdCopyImage(cmd, - vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (stagImgLinear), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cpy); - - vkh_cmd_end (cmd); - - _surface_submit_cmd (surf); - - vkh_image_destroy (stagImg); - } - - void* img = vkh_image_map (stagImgLinear); - - uint64_t stride = vkh_image_get_stride(stagImgLinear); - - stbi_write_png (path, (int32_t)surf->width, (int32_t)surf->height, 4, img, (int32_t)stride); - - vkh_image_unmap (stagImgLinear); - vkh_image_destroy (stagImgLinear); - - UNLOCK_SURFACE(surf) - return VKVG_STATUS_SUCCESS; +vkvg_status_t vkvg_surface_write_to_png(VkvgSurface surf, const char *path) { + if (surf->status) { + LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, invalid status: %d\n", surf->status); + return VKVG_STATUS_INVALID_STATUS; + } + if (surf->dev->status) { + LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, invalid device status: %d\n", surf->dev->status); + return VKVG_STATUS_INVALID_STATUS; + } + if (surf->dev->pngStagFormat == VK_FORMAT_UNDEFINED) { + LOG(VKVG_LOG_ERR, "no suitable image format for png write\n"); + return VKVG_STATUS_INVALID_FORMAT; + } + if (!path) { + LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, null path\n"); + return VKVG_STATUS_WRITE_ERROR; + } + LOCK_SURFACE(surf) + VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + VkvgDevice dev = surf->dev; + + // RGBA to blit to, surf img is bgra + VkhImage stagImg; + + if (dev->pngStagTiling == VK_IMAGE_TILING_LINEAR) + stagImg = vkh_image_create((VkhDevice)surf->dev, dev->pngStagFormat, surf->width, surf->height, + dev->pngStagTiling, VKH_MEMORY_USAGE_GPU_TO_CPU, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + else + stagImg = vkh_image_create((VkhDevice)surf->dev, dev->pngStagFormat, surf->width, surf->height, + dev->pngStagTiling, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + + VkCommandBuffer cmd = surf->cmd; + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkImageBlit blit = { + .srcSubresource = imgSubResLayers, + .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + .dstSubresource = imgSubResLayers, + .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + }; + vkCmdBlitImage(cmd, vkh_image_get_vkimage(surf->img), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_NEAREST); + + vkh_cmd_end(cmd); + + _surface_submit_cmd(surf); + + VkhImage stagImgLinear = stagImg; + + if (dev->pngStagTiling == VK_IMAGE_TILING_OPTIMAL) { + stagImgLinear = vkh_image_create((VkhDevice)surf->dev, dev->pngStagFormat, surf->width, surf->height, + VK_IMAGE_TILING_LINEAR, VKH_MEMORY_USAGE_GPU_TO_CPU, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + VkImageCopy cpy = {.srcSubresource = imgSubResLayers, + .srcOffset = {0}, + .dstSubresource = imgSubResLayers, + .dstOffset = {0}, + .extent = {(int32_t)surf->width, (int32_t)surf->height, 1}}; + + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(cmd, stagImgLinear, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkCmdCopyImage(cmd, vkh_image_get_vkimage(stagImg), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(stagImgLinear), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cpy); + + vkh_cmd_end(cmd); + + _surface_submit_cmd(surf); + + vkh_image_destroy(stagImg); + } + + void *img = vkh_image_map(stagImgLinear); + + uint64_t stride = vkh_image_get_stride(stagImgLinear); + + stbi_write_png(path, (int32_t)surf->width, (int32_t)surf->height, 4, img, (int32_t)stride); + + vkh_image_unmap(stagImgLinear); + vkh_image_destroy(stagImgLinear); + + UNLOCK_SURFACE(surf) + return VKVG_STATUS_SUCCESS; } -vkvg_status_t vkvg_surface_write_to_memory (VkvgSurface surf, unsigned char* const bitmap){ - if (surf->status) { - LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_memory failed, invalid status: %d\n", surf->status); - return VKVG_STATUS_INVALID_STATUS; - } - if (!bitmap) { - LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_memory failed, null path\n"); - return VKVG_STATUS_INVALID_IMAGE; - } - - LOCK_SURFACE(surf) - - VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}; - VkvgDevice dev = surf->dev; - - //RGBA to blit to, surf img is bgra - VkhImage stagImg= vkh_image_create ((VkhDevice)surf->dev,VK_FORMAT_B8G8R8A8_UNORM ,surf->width,surf->height,VK_IMAGE_TILING_LINEAR, - VKH_MEMORY_USAGE_GPU_TO_CPU, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - - VkCommandBuffer cmd = surf->cmd; - - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkImageBlit blit = { - .srcSubresource = imgSubResLayers, - .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - .dstSubresource = imgSubResLayers, - .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - }; - vkCmdBlitImage (cmd, - vkh_image_get_vkimage (surf->img), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_NEAREST); - - vkh_cmd_end (cmd); - - _surface_submit_cmd (surf); - - uint64_t stride = vkh_image_get_stride(stagImg); - uint32_t dest_stride = surf->width * 4; - - char* img = vkh_image_map (stagImg); - char* row = (char*)bitmap; - for (uint32_t y = 0; y < surf->height; y++) { - memcpy(row, img, dest_stride); - row += dest_stride; - img += stride; - } - - vkh_image_unmap (stagImg); - vkh_image_destroy (stagImg); - - UNLOCK_SURFACE(surf) - - return VKVG_STATUS_SUCCESS; +vkvg_status_t vkvg_surface_write_to_memory(VkvgSurface surf, unsigned char *const bitmap) { + if (surf->status) { + LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_memory failed, invalid status: %d\n", surf->status); + return VKVG_STATUS_INVALID_STATUS; + } + if (!bitmap) { + LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_memory failed, null path\n"); + return VKVG_STATUS_INVALID_IMAGE; + } + + LOCK_SURFACE(surf) + + VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + VkvgDevice dev = surf->dev; + + // RGBA to blit to, surf img is bgra + VkhImage stagImg = vkh_image_create((VkhDevice)surf->dev, VK_FORMAT_B8G8R8A8_UNORM, surf->width, surf->height, + VK_IMAGE_TILING_LINEAR, VKH_MEMORY_USAGE_GPU_TO_CPU, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + + VkCommandBuffer cmd = surf->cmd; + + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkImageBlit blit = { + .srcSubresource = imgSubResLayers, + .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + .dstSubresource = imgSubResLayers, + .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + }; + vkCmdBlitImage(cmd, vkh_image_get_vkimage(surf->img), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_NEAREST); + + vkh_cmd_end(cmd); + + _surface_submit_cmd(surf); + + uint64_t stride = vkh_image_get_stride(stagImg); + uint32_t dest_stride = surf->width * 4; + + char *img = vkh_image_map(stagImg); + char *row = (char *)bitmap; + for (uint32_t y = 0; y < surf->height; y++) { + memcpy(row, img, dest_stride); + row += dest_stride; + img += stride; + } + + vkh_image_unmap(stagImg); + vkh_image_destroy(stagImg); + + UNLOCK_SURFACE(surf) + + return VKVG_STATUS_SUCCESS; } diff --git a/src/vkvg_surface_internal.c b/src/vkvg_surface_internal.c index ec0cc07..f1bf9dd 100644 --- a/src/vkvg_surface_internal.c +++ b/src/vkvg_surface_internal.c @@ -25,215 +25,227 @@ #include "vkh_image.h" #include "vkh_queue.h" -void _explicit_ms_resolve (VkvgSurface surf){ - LOCK_SURFACE (surf) - - VkCommandBuffer cmd = surf->cmd; - - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (cmd, surf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkImageResolve re = { - .extent = {surf->width, surf->height,1}, - .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}, - .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1} - }; - - vkCmdResolveImage(cmd, - vkh_image_get_vkimage (surf->imgMS), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (surf->img) ,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1,&re); - vkh_image_set_layout (cmd, surf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - vkh_cmd_end (cmd); - - _surface_submit_cmd (surf); - - UNLOCK_SURFACE (surf) +void _explicit_ms_resolve(VkvgSurface surf) { + LOCK_SURFACE(surf) + + VkCommandBuffer cmd = surf->cmd; + + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(cmd, surf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkImageResolve re = {.extent = {surf->width, surf->height, 1}, + .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}}; + + vkCmdResolveImage(cmd, vkh_image_get_vkimage(surf->imgMS), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(surf->img), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &re); + vkh_image_set_layout(cmd, surf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + vkh_cmd_end(cmd); + + _surface_submit_cmd(surf); + + UNLOCK_SURFACE(surf) } -void _clear_surface (VkvgSurface surf, VkImageAspectFlags aspect) -{ - LOCK_SURFACE (surf) +void _clear_surface(VkvgSurface surf, VkImageAspectFlags aspect) { + LOCK_SURFACE(surf) - VkCommandBuffer cmd = surf->cmd; + VkCommandBuffer cmd = surf->cmd; - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) { - VkClearColorValue cclr = {{0,0,0,0}}; - VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1}; + if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) { + VkClearColorValue cclr = {{0, 0, 0, 0}}; + VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; - VkhImage img = surf->imgMS; - if (surf->dev->samples == VK_SAMPLE_COUNT_1_BIT) - img = surf->img; + VkhImage img = surf->imgMS; + if (surf->dev->samples == VK_SAMPLE_COUNT_1_BIT) + img = surf->img; - vkh_image_set_layout (cmd, img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - vkCmdClearColorImage(cmd, vkh_image_get_vkimage (img), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cclr, 1, &range); + vkCmdClearColorImage(cmd, vkh_image_get_vkimage(img), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cclr, 1, &range); - vkh_image_set_layout (cmd, img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - } - if (aspect & VK_IMAGE_ASPECT_STENCIL_BIT) { - VkClearDepthStencilValue clr = {0,0}; - VkImageSubresourceRange range = {VK_IMAGE_ASPECT_STENCIL_BIT,0,1,0,1}; + vkh_image_set_layout(cmd, img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + } + if (aspect & VK_IMAGE_ASPECT_STENCIL_BIT) { + VkClearDepthStencilValue clr = {0, 0}; + VkImageSubresourceRange range = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1}; - vkh_image_set_layout (cmd, surf->stencil, VK_IMAGE_ASPECT_STENCIL_BIT, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, surf->stencil, VK_IMAGE_ASPECT_STENCIL_BIT, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkCmdClearDepthStencilImage (cmd, vkh_image_get_vkimage (surf->stencil), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,&clr,1,&range); + vkCmdClearDepthStencilImage(cmd, vkh_image_get_vkimage(surf->stencil), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &clr, 1, &range); - vkh_image_set_layout (cmd, surf->stencil, VK_IMAGE_ASPECT_STENCIL_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); - } - vkh_cmd_end (cmd); + vkh_image_set_layout(cmd, surf->stencil, VK_IMAGE_ASPECT_STENCIL_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + } + vkh_cmd_end(cmd); - _surface_submit_cmd (surf); + _surface_submit_cmd(surf); - UNLOCK_SURFACE (surf) + UNLOCK_SURFACE(surf) } -void _create_surface_main_image (VkvgSurface surf){ - surf->img = vkh_image_create((VkhDevice)surf->dev,surf->format,surf->width,surf->height,surf->dev->supportedTiling,VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - vkh_image_create_descriptor(surf->img, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_image_set_name(surf->img, "SURF main color"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(surf->img), "SURF main color VIEW"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(surf->img), "SURF main color SAMPLER"); +void _create_surface_main_image(VkvgSurface surf) { + surf->img = vkh_image_create((VkhDevice)surf->dev, surf->format, surf->width, surf->height, + surf->dev->supportedTiling, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + vkh_image_create_descriptor(surf->img, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_image_set_name(surf->img, "SURF main color"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(surf->img), + "SURF main color VIEW"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(surf->img), + "SURF main color SAMPLER"); #endif } -//create multisample color img if sample count > 1 and the stencil buffer multisampled or not -void _create_surface_secondary_images (VkvgSurface surf) { - if (surf->dev->samples > VK_SAMPLE_COUNT_1_BIT){ - surf->imgMS = vkh_image_ms_create((VkhDevice)surf->dev,surf->format,surf->dev->samples,surf->width,surf->height,VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - vkh_image_create_descriptor(surf->imgMS, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, - VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_image_set_name(surf->imgMS, "SURF MS color IMG"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(surf->imgMS), "SURF MS color VIEW"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(surf->imgMS), "SURF MS color SAMPLER"); +// create multisample color img if sample count > 1 and the stencil buffer multisampled or not +void _create_surface_secondary_images(VkvgSurface surf) { + if (surf->dev->samples > VK_SAMPLE_COUNT_1_BIT) { + surf->imgMS = vkh_image_ms_create((VkhDevice)surf->dev, surf->format, surf->dev->samples, surf->width, + surf->height, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + vkh_image_create_descriptor(surf->imgMS, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_image_set_name(surf->imgMS, "SURF MS color IMG"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, + (uint64_t)vkh_image_get_view(surf->imgMS), "SURF MS color VIEW"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, + (uint64_t)vkh_image_get_sampler(surf->imgMS), "SURF MS color SAMPLER"); #endif - } - surf->stencil = vkh_image_ms_create((VkhDevice)surf->dev,surf->dev->stencilFormat,surf->dev->samples,surf->width,surf->height,VKH_MEMORY_USAGE_GPU_ONLY, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - vkh_image_create_descriptor(surf->stencil, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_STENCIL_BIT, VK_FILTER_NEAREST, - VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_image_set_name(surf->stencil, "SURF stencil"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(surf->stencil), "SURF stencil VIEW"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(surf->stencil), "SURF stencil SAMPLER"); + } + surf->stencil = vkh_image_ms_create((VkhDevice)surf->dev, surf->dev->stencilFormat, surf->dev->samples, surf->width, + surf->height, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + vkh_image_create_descriptor(surf->stencil, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_STENCIL_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_image_set_name(surf->stencil, "SURF stencil"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, + (uint64_t)vkh_image_get_view(surf->stencil), "SURF stencil VIEW"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, + (uint64_t)vkh_image_get_sampler(surf->stencil), "SURF stencil SAMPLER"); #endif } -void _create_framebuffer (VkvgSurface surf) { - VkImageView attachments[] = { - vkh_image_get_view (surf->img), - vkh_image_get_view (surf->stencil), - vkh_image_get_view (surf->imgMS), - }; - VkFramebufferCreateInfo frameBufferCreateInfo = { .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .renderPass = surf->dev->renderPass, - .attachmentCount = 3, - .pAttachments = attachments, - .width = surf->width, - .height = surf->height, - .layers = 1 }; - if (surf->dev->samples == VK_SAMPLE_COUNT_1_BIT) - frameBufferCreateInfo.attachmentCount = 2; - else if (surf->dev->deferredResolve) { - attachments[0] = attachments[2]; - frameBufferCreateInfo.attachmentCount = 2; - } - VK_CHECK_RESULT(vkCreateFramebuffer(surf->dev->vkDev, &frameBufferCreateInfo, NULL, &surf->fb)); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_FRAMEBUFFER, (uint64_t)surf->fb, "SURF FB"); +void _create_framebuffer(VkvgSurface surf) { + VkImageView attachments[] = { + vkh_image_get_view(surf->img), + vkh_image_get_view(surf->stencil), + vkh_image_get_view(surf->imgMS), + }; + VkFramebufferCreateInfo frameBufferCreateInfo = {.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .renderPass = surf->dev->renderPass, + .attachmentCount = 3, + .pAttachments = attachments, + .width = surf->width, + .height = surf->height, + .layers = 1}; + if (surf->dev->samples == VK_SAMPLE_COUNT_1_BIT) + frameBufferCreateInfo.attachmentCount = 2; + else if (surf->dev->deferredResolve) { + attachments[0] = attachments[2]; + frameBufferCreateInfo.attachmentCount = 2; + } + VK_CHECK_RESULT(vkCreateFramebuffer(surf->dev->vkDev, &frameBufferCreateInfo, NULL, &surf->fb)); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_FRAMEBUFFER, (uint64_t)surf->fb, "SURF FB"); #endif } -void _create_surface_images (VkvgSurface surf) { +void _create_surface_images(VkvgSurface surf) { - _create_surface_main_image (surf); - _create_surface_secondary_images(surf); - _create_framebuffer (surf); + _create_surface_main_image(surf); + _create_surface_secondary_images(surf); + _create_framebuffer(surf); #if defined(DEBUG) && defined(ENABLE_VALIDATION) - vkh_image_set_name(surf->img, "surfImg"); - vkh_image_set_name(surf->imgMS, "surfImgMS"); - vkh_image_set_name(surf->stencil, "surfStencil"); + vkh_image_set_name(surf->img, "surfImg"); + vkh_image_set_name(surf->imgMS, "surfImgMS"); + vkh_image_set_name(surf->stencil, "surfStencil"); #endif } -VkvgSurface _create_surface (VkvgDevice dev, VkFormat format) { - VkvgSurface surf = (vkvg_surface*)calloc(1,sizeof(vkvg_surface)); - if (!surf) - return (VkvgSurface)&_no_mem_status; - - surf->references = 1; - if (dev->status != VKVG_STATUS_SUCCESS) { - surf->status = VKVG_STATUS_DEVICE_ERROR; - return surf; - } - surf->dev = dev; - surf->format = format; - if (dev->threadAware) - mtx_init (&surf->mutex, mtx_plain); - surf->cmdPool = vkh_cmd_pool_create ((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); - vkh_cmd_buffs_create((VkhDevice)dev, surf->cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1, &surf->cmd); +VkvgSurface _create_surface(VkvgDevice dev, VkFormat format) { + VkvgSurface surf = (vkvg_surface *)calloc(1, sizeof(vkvg_surface)); + if (!surf) + return (VkvgSurface)&_no_mem_status; + + surf->references = 1; + if (dev->status != VKVG_STATUS_SUCCESS) { + surf->status = VKVG_STATUS_DEVICE_ERROR; + return surf; + } + surf->dev = dev; + surf->format = format; + if (dev->threadAware) + mtx_init(&surf->mutex, mtx_plain); + surf->cmdPool = + vkh_cmd_pool_create((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + vkh_cmd_buffs_create((VkhDevice)dev, surf->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1, &surf->cmd); #if VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - surf->timeline = vkh_timeline_create ((VkhDevice)dev, 0); + surf->timeline = vkh_timeline_create((VkhDevice)dev, 0); #else - surf->flushFence = vkh_fence_create ((VkhDevice)dev); + surf->flushFence = vkh_fence_create((VkhDevice)dev); #endif #if defined(DEBUG) && defined(VKVG_DBG_UTILS) - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)surf->cmd, "vkvgSurfCmd"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)surf->cmd, "vkvgSurfCmd"); #endif - return surf; + return surf; } -//if fence sync, surf mutex must be locked. +// if fence sync, surf mutex must be locked. /*bool _surface_wait_cmd (VkvgSurface surf) { - LOG(VKVG_LOG_INFO, "SURF: _surface__wait_flush_fence\n"); + LOG(VKVG_LOG_INFO, "SURF: _surface__wait_flush_fence\n"); #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - if (vkh_timeline_wait ((VkhDevice)surf->dev, surf->timeline, surf->timelineStep) == VK_SUCCESS) - return true; + if (vkh_timeline_wait ((VkhDevice)surf->dev, surf->timeline, surf->timelineStep) == VK_SUCCESS) + return true; #else - if (WaitForFences (surf->dev->vkDev, 1, &surf->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) { - ResetFences (surf->dev->vkDev, 1, &surf->flushFence); - return true; - } + if (WaitForFences (surf->dev->vkDev, 1, &surf->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) { + ResetFences (surf->dev->vkDev, 1, &surf->flushFence); + return true; + } #endif - LOG(VKVG_LOG_DEBUG, "CTX: _wait_flush_fence timeout\n"); - surf->status = VKVG_STATUS_TIMEOUT; - return false; + LOG(VKVG_LOG_DEBUG, "CTX: _wait_flush_fence timeout\n"); + surf->status = VKVG_STATUS_TIMEOUT; + return false; }*/ -//surface mutex must be locked to call this method, locking to guard also the surf->cmd local buffer usage. -void _surface_submit_cmd (VkvgSurface surf) { - VkvgDevice dev = surf->dev; +// surface mutex must be locked to call this method, locking to guard also the surf->cmd local buffer usage. +void _surface_submit_cmd(VkvgSurface surf) { + VkvgDevice dev = surf->dev; #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - LOCK_DEVICE - vkh_cmd_submit_timelined (dev->gQueue, &surf->cmd, surf->timeline, surf->timelineStep, surf->timelineStep+1); - surf->timelineStep++; - UNLOCK_DEVICE - vkh_timeline_wait ((VkhDevice)dev, surf->timeline, surf->timelineStep); + LOCK_DEVICE + vkh_cmd_submit_timelined(dev->gQueue, &surf->cmd, surf->timeline, surf->timelineStep, surf->timelineStep + 1); + surf->timelineStep++; + UNLOCK_DEVICE + vkh_timeline_wait((VkhDevice)dev, surf->timeline, surf->timelineStep); #else - LOCK_DEVICE - vkh_cmd_submit (surf->dev->gQueue, &surf->cmd, surf->flushFence); - UNLOCK_DEVICE - WaitForFences (surf->dev->vkDev, 1, &surf->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT); - ResetFences (surf->dev->vkDev, 1, &surf->flushFence); + LOCK_DEVICE + vkh_cmd_submit(surf->dev->gQueue, &surf->cmd, surf->flushFence); + UNLOCK_DEVICE + WaitForFences(surf->dev->vkDev, 1, &surf->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT); + ResetFences(surf->dev->vkDev, 1, &surf->flushFence); #endif } diff --git a/src/vkvg_surface_internal.h b/src/vkvg_surface_internal.h index 5cc47c6..085ce77 100644 --- a/src/vkvg_surface_internal.h +++ b/src/vkvg_surface_internal.h @@ -27,44 +27,44 @@ #include "vkh.h" typedef struct _vkvg_surface_t { - vkvg_status_t status; /**< Current status of surface, affected by last operation */ - uint32_t references; - VkvgDevice dev; - uint32_t width; - uint32_t height; - VkFormat format; - VkFramebuffer fb; - VkhImage img; - VkhImage imgMS; - VkhImage stencil; - VkCommandPool cmdPool; //local pools ensure thread safety - VkCommandBuffer cmd; //surface local command buffer. - bool newSurf; - mtx_t mutex; + vkvg_status_t status; /**< Current status of surface, affected by last operation */ + uint32_t references; + VkvgDevice dev; + uint32_t width; + uint32_t height; + VkFormat format; + VkFramebuffer fb; + VkhImage img; + VkhImage imgMS; + VkhImage stencil; + VkCommandPool cmdPool; // local pools ensure thread safety + VkCommandBuffer cmd; // surface local command buffer. + bool newSurf; + mtx_t mutex; #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - VkSemaphore timeline; /**< Timeline semaphore */ - uint64_t timelineStep; + VkSemaphore timeline; /**< Timeline semaphore */ + uint64_t timelineStep; #else - VkFence flushFence; //unsignaled idle. + VkFence flushFence; // unsignaled idle. #endif -}vkvg_surface; +} vkvg_surface; -#define LOCK_SURFACE(surf) \ - if (surf->dev->threadAware)\ - mtx_lock (&surf->mutex); -#define UNLOCK_SURFACE(surf) \ - if (surf->dev->threadAware)\ - mtx_unlock (&surf->mutex); +#define LOCK_SURFACE(surf) \ + if (surf->dev->threadAware) \ + mtx_lock(&surf->mutex); +#define UNLOCK_SURFACE(surf) \ + if (surf->dev->threadAware) \ + mtx_unlock(&surf->mutex); -void _explicit_ms_resolve (VkvgSurface surf); -void _clear_surface (VkvgSurface surf, VkImageAspectFlags aspect); -void _create_surface_main_image (VkvgSurface surf); -void _create_surface_secondary_images (VkvgSurface surf); -void _create_framebuffer (VkvgSurface surf); -void _create_surface_images (VkvgSurface surf); -VkvgSurface _create_surface (VkvgDevice dev, VkFormat format); +void _explicit_ms_resolve(VkvgSurface surf); +void _clear_surface(VkvgSurface surf, VkImageAspectFlags aspect); +void _create_surface_main_image(VkvgSurface surf); +void _create_surface_secondary_images(VkvgSurface surf); +void _create_framebuffer(VkvgSurface surf); +void _create_surface_images(VkvgSurface surf); +VkvgSurface _create_surface(VkvgDevice dev, VkFormat format); -void _surface_submit_cmd (VkvgSurface surf); -//bool _surface_wait_cmd (VkvgSurface surf); +void _surface_submit_cmd(VkvgSurface surf); +// bool _surface_wait_cmd (VkvgSurface surf); #endif diff --git a/template.c b/template.c index 333fcdf..6ac3390 100644 --- a/template.c +++ b/template.c @@ -4,13 +4,13 @@ #include "test.h" -void test_name(){ - VkvgContext ctx = vkvg_create(surf); +void test_name() { + VkvgContext ctx = vkvg_create(surf); - vkvg_destroy(ctx); + vkvg_destroy(ctx); } int main(int argc, char *argv[]) { - PERFORM_TEST (test_name, argc, argv); - return 0; + PERFORM_TEST(test_name, argc, argv); + return 0; } diff --git a/tests/arcs.c b/tests/arcs.c index cfeb131..e711b41 100644 --- a/tests/arcs.c +++ b/tests/arcs.c @@ -1,92 +1,92 @@ #include "test.h" -void draw_growing_circles (VkvgContext ctx, float y, int count) { - float x = 2; - for (int i=1; i=0) { - vkvg_stroke_preserve(ctx); - vkvg_set_dash(ctx, NULL, 0, 0); - vkvg_set_line_width(ctx,2); - vkvg_set_source_rgba(ctx,0,0,0,1); - vkvg_stroke(ctx); - vkvg_set_source_rgba(ctx,0.5f,0.5f,1.0f,0.7f); - vkvg_arc (ctx, pts[hoverPt].x, pts[hoverPt].y, pointSize, 0, M_PIF*2); - vkvg_fill_preserve(ctx); - vkvg_stroke(ctx); - } else - vkvg_stroke(ctx); - - //draw_v(ctx, 200, 20, VKVG_LINE_JOIN_BEVEL); - //draw_v(ctx, 300, 80, VKVG_LINE_JOIN_ROUND); - vkvg_destroy(ctx); + vkvg_set_line_width(ctx, 1); + vkvg_set_source_rgba(ctx, 0.5, 0.5, 0.5, 0.6); + for (int i = 0; i < ptsCount; i++) { + + if (i == hoverPt) { + vkvg_arc(ctx, pts[i].x, pts[i].y, hoverPointSize, 0, M_PIF * 2); + vkvg_set_source_rgba(ctx, 0.5, 0.5, 1.0, 0.6); + vkvg_fill_preserve(ctx); + vkvg_set_source_rgba(ctx, 0.5, 0.5, 0.5, 0.6); + } else { + vkvg_arc(ctx, pts[i].x, pts[i].y, pointSize, 0, M_PIF * 2); + vkvg_fill_preserve(ctx); + } + vkvg_stroke(ctx); + } + + if (hoverPt >= 0) { + vkvg_stroke_preserve(ctx); + vkvg_set_dash(ctx, NULL, 0, 0); + vkvg_set_line_width(ctx, 2); + vkvg_set_source_rgba(ctx, 0, 0, 0, 1); + vkvg_stroke(ctx); + vkvg_set_source_rgba(ctx, 0.5f, 0.5f, 1.0f, 0.7f); + vkvg_arc(ctx, pts[hoverPt].x, pts[hoverPt].y, pointSize, 0, M_PIF * 2); + vkvg_fill_preserve(ctx); + vkvg_stroke(ctx); + } else + vkvg_stroke(ctx); + + // draw_v(ctx, 200, 20, VKVG_LINE_JOIN_BEVEL); + // draw_v(ctx, 300, 80, VKVG_LINE_JOIN_ROUND); + vkvg_destroy(ctx); } -static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { - if (action == GLFW_RELEASE) - return; - switch (key) { - case GLFW_KEY_ESCAPE : - glfwSetWindowShouldClose(window, GLFW_TRUE); - break; - case GLFW_KEY_W : - isClosed ^= true; - break; - case GLFW_KEY_F : - isFilled ^= true; - break; - case GLFW_KEY_J : - lineJoin++; - if (lineJoin > 2) - lineJoin = 0; - break; - case GLFW_KEY_C : - lineCap++; - if (lineCap > 2) - lineCap = 0; - break; - case GLFW_KEY_KP_ADD : - lineWidth++; - break; - case GLFW_KEY_KP_SUBTRACT : - if (lineWidth > 1) - lineWidth--; - break; +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { + if (action == GLFW_RELEASE) + return; + switch (key) { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GLFW_TRUE); + break; + case GLFW_KEY_W: + isClosed ^= true; + break; + case GLFW_KEY_F: + isFilled ^= true; + break; + case GLFW_KEY_J: + lineJoin++; + if (lineJoin > 2) + lineJoin = 0; + break; + case GLFW_KEY_C: + lineCap++; + if (lineCap > 2) + lineCap = 0; + break; + case GLFW_KEY_KP_ADD: + lineWidth++; + break; + case GLFW_KEY_KP_SUBTRACT: + if (lineWidth > 1) + lineWidth--; + break; #ifdef VKVG_WIRED_DEBUG - case GLFW_KEY_F1: - _wired_debug ^= (1U << 0); - break; - case GLFW_KEY_F2: - _wired_debug ^= (1U << 1); - break; - case GLFW_KEY_F3: - _wired_debug ^= (1U << 2); - break; + case GLFW_KEY_F1: + _wired_debug ^= (1U << 0); + break; + case GLFW_KEY_F2: + _wired_debug ^= (1U << 1); + break; + case GLFW_KEY_F3: + _wired_debug ^= (1U << 2); + break; #endif - } + } } -static void mouse_move_callback(GLFWwindow* window, double x, double y){ - if (mouseDown) { - if (hoverPt < 0) - return; - pts[hoverPt].x = x; - pts[hoverPt].y = y; - } else { - for (int i=0; i pts[i].x - hoverPointSize && - x < pts[i].x + hoverPointSize && - y > pts[i].y - hoverPointSize && - y < pts[i].y + hoverPointSize) { - hoverPt = i; - return; - } - } - hoverPt = -1; - } +static void mouse_move_callback(GLFWwindow *window, double x, double y) { + if (mouseDown) { + if (hoverPt < 0) + return; + pts[hoverPt].x = x; + pts[hoverPt].y = y; + } else { + for (int i = 0; i < ptsCount; i++) { + if (x > pts[i].x - hoverPointSize && x < pts[i].x + hoverPointSize && y > pts[i].y - hoverPointSize && + y < pts[i].y + hoverPointSize) { + hoverPt = i; + return; + } + } + hoverPt = -1; + } } -static void scroll_callback(GLFWwindow* window, double x, double y){ - if (y<0.f) - zoom *= 0.5f; - else - zoom *= 2.0f; +static void scroll_callback(GLFWwindow *window, double x, double y) { + if (y < 0.f) + zoom *= 0.5f; + else + zoom *= 2.0f; } -static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif){ - if (but != GLFW_MOUSE_BUTTON_1) - return; - if (state == GLFW_TRUE) - mouseDown = true; - else - mouseDown = false; +static void mouse_button_callback(GLFWwindow *window, int but, int state, int modif) { + if (but != GLFW_MOUSE_BUTTON_1) + return; + if (state == GLFW_TRUE) + mouseDown = true; + else + mouseDown = false; } +int main(int argc, char *argv[]) { + _parse_args(argc, argv); + VkEngine e; + e = vkengine_create(VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); -int main(int argc, char* argv[]) { + VkhPresenter r = e->renderer; + vkengine_set_key_callback(e, key_callback); + vkengine_set_mouse_but_callback(e, mouse_button_callback); + vkengine_set_cursor_pos_callback(e, mouse_move_callback); + vkengine_set_scroll_callback(e, scroll_callback); - _parse_args (argc, argv); - VkEngine e; - e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); + vkvg_device_create_info_t info = {samples, false, vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0}; + device = vkvg_device_create(&info); - VkhPresenter r = e->renderer; - vkengine_set_key_callback (e, key_callback); - vkengine_set_mouse_but_callback(e, mouse_button_callback); - vkengine_set_cursor_pos_callback(e, mouse_move_callback); - vkengine_set_scroll_callback(e, scroll_callback); + surf = vkvg_surface_create(device, test_width, test_height); - vkvg_device_create_info_t info = { - samples, - false, - vkh_app_get_inst(e->app), - r->dev->phy, - r->dev->dev, - r->qFam, - 0 - }; - device = vkvg_device_create(&info); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); - surf = vkvg_surface_create(device, test_width, test_height); + while (!vkengine_should_close(e)) { + glfwPollEvents(); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); + draw(); - while (!vkengine_should_close (e)) { - glfwPollEvents(); + if (!vkh_presenter_draw(r)) { + vkh_presenter_get_size(r, &test_width, &test_height); + vkvg_surface_destroy(surf); + surf = vkvg_surface_create(device, test_width, test_height); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); + vkDeviceWaitIdle(r->dev->dev); + continue; + } + } + vkDeviceWaitIdle(e->dev->dev); - draw (); + vkvg_surface_destroy(surf); - if (!vkh_presenter_draw (r)){ - vkh_presenter_get_size (r, &test_width, &test_height); - vkvg_surface_destroy (surf); - surf = vkvg_surface_create(device, test_width, test_height); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); - vkDeviceWaitIdle(r->dev->dev); - continue; - } - } - vkDeviceWaitIdle(e->dev->dev); + vkvg_device_destroy(device); - vkvg_surface_destroy (surf); + vkengine_destroy(e); - vkvg_device_destroy (device); - - vkengine_destroy (e); - - return 0; + return 0; } diff --git a/tests/circles.c b/tests/circles.c index 3a34d81..e8f88ba 100644 --- a/tests/circles.c +++ b/tests/circles.c @@ -1,63 +1,63 @@ #include "test.h" -void draw_growing_circles (VkvgContext ctx, float y, int count) { - float x = 2; - for (int i=1; iwidth, image->height); - // Use... - for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { - for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { - for (int i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); - } - } - } - // Delete - nsvgDelete(image); + // Load + NSVGImage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + printf("size: %f x %f\n", image->width, image->height); + // Use... + for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { + for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { + for (int i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); + } + } + } + // Delete + nsvgDelete(image); */ enum NSVGpaintType { - NSVG_PAINT_NONE = 0, - NSVG_PAINT_COLOR = 1, - NSVG_PAINT_LINEAR_GRADIENT = 2, - NSVG_PAINT_RADIAL_GRADIENT = 3 + NSVG_PAINT_NONE = 0, + NSVG_PAINT_COLOR = 1, + NSVG_PAINT_LINEAR_GRADIENT = 2, + NSVG_PAINT_RADIAL_GRADIENT = 3 }; -enum NSVGspreadType { - NSVG_SPREAD_PAD = 0, - NSVG_SPREAD_REFLECT = 1, - NSVG_SPREAD_REPEAT = 2 -}; +enum NSVGspreadType { NSVG_SPREAD_PAD = 0, NSVG_SPREAD_REFLECT = 1, NSVG_SPREAD_REPEAT = 2 }; -enum NSVGlineJoin { - NSVG_JOIN_MITER = 0, - NSVG_JOIN_ROUND = 1, - NSVG_JOIN_BEVEL = 2 -}; +enum NSVGlineJoin { NSVG_JOIN_MITER = 0, NSVG_JOIN_ROUND = 1, NSVG_JOIN_BEVEL = 2 }; -enum NSVGlineCap { - NSVG_CAP_BUTT = 0, - NSVG_CAP_ROUND = 1, - NSVG_CAP_SQUARE = 2 -}; +enum NSVGlineCap { NSVG_CAP_BUTT = 0, NSVG_CAP_ROUND = 1, NSVG_CAP_SQUARE = 2 }; -enum NSVGfillRule { - NSVG_FILLRULE_NONZERO = 0, - NSVG_FILLRULE_EVENODD = 1 -}; +enum NSVGfillRule { NSVG_FILLRULE_NONZERO = 0, NSVG_FILLRULE_EVENODD = 1 }; -enum NSVGflags { - NSVG_FLAGS_VISIBLE = 0x01 -}; +enum NSVGflags { NSVG_FLAGS_VISIBLE = 0x01 }; typedef struct NSVGgradientStop { - unsigned int color; - float offset; + unsigned int color; + float offset; } NSVGgradientStop; typedef struct NSVGgradient { - float xform[6]; - char spread; - float fx, fy; - int nstops; - NSVGgradientStop stops[1]; + float xform[6]; + char spread; + float fx, fy; + int nstops; + NSVGgradientStop stops[1]; } NSVGgradient; typedef struct NSVGpaint { - char type; - union { - unsigned int color; - NSVGgradient* gradient; - }; + char type; + union { + unsigned int color; + NSVGgradient *gradient; + }; } NSVGpaint; -typedef struct NSVGpath -{ - float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... - int npts; // Total number of bezier points. - char closed; // Flag indicating if shapes should be treated as closed. - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - struct NSVGpath* next; // Pointer to next path, or NULL if last element. +typedef struct NSVGpath { + float *pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... + int npts; // Total number of bezier points. + char closed; // Flag indicating if shapes should be treated as closed. + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + struct NSVGpath *next; // Pointer to next path, or NULL if last element. } NSVGpath; -typedef struct NSVGshape -{ - char id[64]; // Optional 'id' attr of the shape or its group - NSVGpaint fill; // Fill paint - NSVGpaint stroke; // Stroke paint - float opacity; // Opacity of the shape. - float strokeWidth; // Stroke width (scaled). - float strokeDashOffset; // Stroke dash offset (scaled). - float strokeDashArray[8]; // Stroke dash array (scaled). - char strokeDashCount; // Number of dash values in dash array. - char strokeLineJoin; // Stroke join type. - char strokeLineCap; // Stroke cap type. - float miterLimit; // Miter limit - char fillRule; // Fill rule, see NSVGfillRule. - unsigned char flags; // Logical or of NSVG_FLAGS_* flags - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - NSVGpath* paths; // Linked list of paths in the image. - struct NSVGshape* next; // Pointer to next shape, or NULL if last element. +typedef struct NSVGshape { + char id[64]; // Optional 'id' attr of the shape or its group + NSVGpaint fill; // Fill paint + NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. + float strokeWidth; // Stroke width (scaled). + float strokeDashOffset; // Stroke dash offset (scaled). + float strokeDashArray[8]; // Stroke dash array (scaled). + char strokeDashCount; // Number of dash values in dash array. + char strokeLineJoin; // Stroke join type. + char strokeLineCap; // Stroke cap type. + float miterLimit; // Miter limit + char fillRule; // Fill rule, see NSVGfillRule. + unsigned char flags; // Logical or of NSVG_FLAGS_* flags + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + NSVGpath *paths; // Linked list of paths in the image. + struct NSVGshape *next; // Pointer to next shape, or NULL if last element. } NSVGshape; -typedef struct NSVGimage -{ - float width; // Width of the image. - float height; // Height of the image. - NSVGshape* shapes; // Linked list of shapes in the image. +typedef struct NSVGimage { + float width; // Width of the image. + float height; // Height of the image. + NSVGshape *shapes; // Linked list of shapes in the image. } NSVGimage; // Parses SVG file from a file, returns SVG image as paths. -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); +NSVGimage *nsvgParseFromFile(const char *filename, const char *units, float dpi); // Parses SVG file from a null terminated string, returns SVG image as paths. // Important note: changes the string. -NSVGimage* nsvgParse(char* input, const char* units, float dpi); +NSVGimage *nsvgParse(char *input, const char *units, float dpi); // Deletes list of paths. -void nsvgDelete(NSVGimage* image); +void nsvgDelete(NSVGimage *image); #ifdef __cplusplus } @@ -182,2744 +161,2747 @@ void nsvgDelete(NSVGimage* image); #include #include -#define NSVG_PI (3.14159265358979323846264338327f) -#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. +#define NSVG_PI (3.14159265358979323846264338327f) +#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. -#define NSVG_ALIGN_MIN 0 -#define NSVG_ALIGN_MID 1 -#define NSVG_ALIGN_MAX 2 -#define NSVG_ALIGN_NONE 0 -#define NSVG_ALIGN_MEET 1 +#define NSVG_ALIGN_MIN 0 +#define NSVG_ALIGN_MID 1 +#define NSVG_ALIGN_MAX 2 +#define NSVG_ALIGN_NONE 0 +#define NSVG_ALIGN_MEET 1 #define NSVG_ALIGN_SLICE 2 -#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) +#define NSVG_NOTUSED(v) \ + do { \ + (void)(1 ? (void)0 : ((void)(v))); \ + } while (0) #define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) #ifdef _MSC_VER - #pragma warning (disable: 4996) // Switch off security warnings - #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings - #ifdef __cplusplus - #define NSVG_INLINE inline - #else - #define NSVG_INLINE - #endif +#pragma warning(disable : 4996) // Switch off security warnings +#pragma warning(disable : 4100) // Switch off unreferenced formal parameter warnings +#ifdef __cplusplus +#define NSVG_INLINE inline #else - #define NSVG_INLINE inline +#define NSVG_INLINE +#endif +#else +#define NSVG_INLINE inline #endif +static int nsvg__isspace(char c) { return strchr(" \t\n\v\f\r", c) != 0; } -static int nsvg__isspace(char c) -{ - return strchr(" \t\n\v\f\r", c) != 0; -} +static int nsvg__isdigit(char c) { return c >= '0' && c <= '9'; } -static int nsvg__isdigit(char c) -{ - return c >= '0' && c <= '9'; -} - -static int nsvg__isnum(char c) -{ - return strchr("0123456789+-.eE", c) != 0; -} +static int nsvg__isnum(char c) { return strchr("0123456789+-.eE", c) != 0; } static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } - // Simple XML parser -#define NSVG_XML_TAG 1 -#define NSVG_XML_CONTENT 2 +#define NSVG_XML_TAG 1 +#define NSVG_XML_CONTENT 2 #define NSVG_XML_MAX_ATTRIBS 256 -static void nsvg__parseContent(char* s, - void (*contentCb)(void* ud, const char* s), - void* ud) -{ - // Trim start white spaces - while (*s && nsvg__isspace(*s)) s++; - if (!*s) return; - - if (contentCb) - (*contentCb)(ud, s); -} - -static void nsvg__parseElement(char* s, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void* ud) -{ - const char* attr[NSVG_XML_MAX_ATTRIBS]; - int nattr = 0; - char* name; - int start = 0; - int end = 0; - char quote; - - // Skip white space after the '<' - while (*s && nsvg__isspace(*s)) s++; - - // Check if the tag is end tag - if (*s == '/') { - s++; - end = 1; - } else { - start = 1; - } - - // Skip comments, data and preprocessor stuff. - if (!*s || *s == '?' || *s == '!') - return; - - // Get tag name - name = s; - while (*s && !nsvg__isspace(*s)) s++; - if (*s) { *s++ = '\0'; } - - // Get attribs - while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { - char* name = NULL; - char* value = NULL; - - // Skip white space before the attrib name - while (*s && nsvg__isspace(*s)) s++; - if (!*s) break; - if (*s == '/') { - end = 1; - break; - } - name = s; - // Find end of the attrib name. - while (*s && !nsvg__isspace(*s) && *s != '=') s++; - if (*s) { *s++ = '\0'; } - // Skip until the beginning of the value. - while (*s && *s != '\"' && *s != '\'') s++; - if (!*s) break; - quote = *s; - s++; - // Store value and find the end of it. - value = s; - while (*s && *s != quote) s++; - if (*s) { *s++ = '\0'; } - - // Store only well formed attributes - if (name && value) { - attr[nattr++] = name; - attr[nattr++] = value; - } - } - - // List terminator - attr[nattr++] = 0; - attr[nattr++] = 0; - - // Call callbacks. - if (start && startelCb) - (*startelCb)(ud, name, attr); - if (end && endelCb) - (*endelCb)(ud, name); -} - -int nsvg__parseXML(char* input, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void (*contentCb)(void* ud, const char* s), - void* ud) -{ - char* s = input; - char* mark = s; - int state = NSVG_XML_CONTENT; - while (*s) { - if (*s == '<' && state == NSVG_XML_CONTENT) { - // Start of a tag - *s++ = '\0'; - nsvg__parseContent(mark, contentCb, ud); - mark = s; - state = NSVG_XML_TAG; - } else if (*s == '>' && state == NSVG_XML_TAG) { - // Start of a content or new tag. - *s++ = '\0'; - nsvg__parseElement(mark, startelCb, endelCb, ud); - mark = s; - state = NSVG_XML_CONTENT; - } else { - s++; - } - } - - return 1; +static void nsvg__parseContent(char *s, void (*contentCb)(void *ud, const char *s), void *ud) { + // Trim start white spaces + while (*s && nsvg__isspace(*s)) + s++; + if (!*s) + return; + + if (contentCb) + (*contentCb)(ud, s); +} + +static void nsvg__parseElement(char *s, void (*startelCb)(void *ud, const char *el, const char **attr), + void (*endelCb)(void *ud, const char *el), void *ud) { + const char *attr[NSVG_XML_MAX_ATTRIBS]; + int nattr = 0; + char *name; + int start = 0; + int end = 0; + char quote; + + // Skip white space after the '<' + while (*s && nsvg__isspace(*s)) + s++; + + // Check if the tag is end tag + if (*s == '/') { + s++; + end = 1; + } else { + start = 1; + } + + // Skip comments, data and preprocessor stuff. + if (!*s || *s == '?' || *s == '!') + return; + + // Get tag name + name = s; + while (*s && !nsvg__isspace(*s)) + s++; + if (*s) { + *s++ = '\0'; + } + + // Get attribs + while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS - 3) { + char *name = NULL; + char *value = NULL; + + // Skip white space before the attrib name + while (*s && nsvg__isspace(*s)) + s++; + if (!*s) + break; + if (*s == '/') { + end = 1; + break; + } + name = s; + // Find end of the attrib name. + while (*s && !nsvg__isspace(*s) && *s != '=') + s++; + if (*s) { + *s++ = '\0'; + } + // Skip until the beginning of the value. + while (*s && *s != '\"' && *s != '\'') + s++; + if (!*s) + break; + quote = *s; + s++; + // Store value and find the end of it. + value = s; + while (*s && *s != quote) + s++; + if (*s) { + *s++ = '\0'; + } + + // Store only well formed attributes + if (name && value) { + attr[nattr++] = name; + attr[nattr++] = value; + } + } + + // List terminator + attr[nattr++] = 0; + attr[nattr++] = 0; + + // Call callbacks. + if (start && startelCb) + (*startelCb)(ud, name, attr); + if (end && endelCb) + (*endelCb)(ud, name); +} + +int nsvg__parseXML(char *input, void (*startelCb)(void *ud, const char *el, const char **attr), + void (*endelCb)(void *ud, const char *el), void (*contentCb)(void *ud, const char *s), void *ud) { + char *s = input; + char *mark = s; + int state = NSVG_XML_CONTENT; + while (*s) { + if (*s == '<' && state == NSVG_XML_CONTENT) { + // Start of a tag + *s++ = '\0'; + nsvg__parseContent(mark, contentCb, ud); + mark = s; + state = NSVG_XML_TAG; + } else if (*s == '>' && state == NSVG_XML_TAG) { + // Start of a content or new tag. + *s++ = '\0'; + nsvg__parseElement(mark, startelCb, endelCb, ud); + mark = s; + state = NSVG_XML_CONTENT; + } else { + s++; + } + } + + return 1; } - /* Simple SVG parser. */ #define NSVG_MAX_ATTR 128 -enum NSVGgradientUnits { - NSVG_USER_SPACE = 0, - NSVG_OBJECT_SPACE = 1 -}; +enum NSVGgradientUnits { NSVG_USER_SPACE = 0, NSVG_OBJECT_SPACE = 1 }; #define NSVG_MAX_DASHES 8 enum NSVGunits { - NSVG_UNITS_USER, - NSVG_UNITS_PX, - NSVG_UNITS_PT, - NSVG_UNITS_PC, - NSVG_UNITS_MM, - NSVG_UNITS_CM, - NSVG_UNITS_IN, - NSVG_UNITS_PERCENT, - NSVG_UNITS_EM, - NSVG_UNITS_EX + NSVG_UNITS_USER, + NSVG_UNITS_PX, + NSVG_UNITS_PT, + NSVG_UNITS_PC, + NSVG_UNITS_MM, + NSVG_UNITS_CM, + NSVG_UNITS_IN, + NSVG_UNITS_PERCENT, + NSVG_UNITS_EM, + NSVG_UNITS_EX }; typedef struct NSVGcoordinate { - float value; - int units; + float value; + int units; } NSVGcoordinate; typedef struct NSVGlinearData { - NSVGcoordinate x1, y1, x2, y2; + NSVGcoordinate x1, y1, x2, y2; } NSVGlinearData; typedef struct NSVGradialData { - NSVGcoordinate cx, cy, r, fx, fy; + NSVGcoordinate cx, cy, r, fx, fy; } NSVGradialData; -typedef struct NSVGgradientData -{ - char id[64]; - char ref[64]; - char type; - union { - NSVGlinearData linear; - NSVGradialData radial; - }; - char spread; - char units; - float xform[6]; - int nstops; - NSVGgradientStop* stops; - struct NSVGgradientData* next; +typedef struct NSVGgradientData { + char id[64]; + char ref[64]; + char type; + union { + NSVGlinearData linear; + NSVGradialData radial; + }; + char spread; + char units; + float xform[6]; + int nstops; + NSVGgradientStop *stops; + struct NSVGgradientData *next; } NSVGgradientData; -typedef struct NSVGattrib -{ - char id[64]; - float xform[6]; - unsigned int fillColor; - unsigned int strokeColor; - float opacity; - float fillOpacity; - float strokeOpacity; - char fillGradient[64]; - char strokeGradient[64]; - float strokeWidth; - float strokeDashOffset; - float strokeDashArray[NSVG_MAX_DASHES]; - int strokeDashCount; - char strokeLineJoin; - char strokeLineCap; - float miterLimit; - char fillRule; - float fontSize; - unsigned int stopColor; - float stopOpacity; - float stopOffset; - char hasFill; - char hasStroke; - char visible; +typedef struct NSVGattrib { + char id[64]; + float xform[6]; + unsigned int fillColor; + unsigned int strokeColor; + float opacity; + float fillOpacity; + float strokeOpacity; + char fillGradient[64]; + char strokeGradient[64]; + float strokeWidth; + float strokeDashOffset; + float strokeDashArray[NSVG_MAX_DASHES]; + int strokeDashCount; + char strokeLineJoin; + char strokeLineCap; + float miterLimit; + char fillRule; + float fontSize; + unsigned int stopColor; + float stopOpacity; + float stopOffset; + char hasFill; + char hasStroke; + char visible; } NSVGattrib; -typedef struct NSVGparser -{ - NSVGattrib attr[NSVG_MAX_ATTR]; - int attrHead; - float* pts; - int npts; - int cpts; - NSVGpath* plist; - NSVGimage* image; - NSVGgradientData* gradients; - NSVGshape* shapesTail; - float viewMinx, viewMiny, viewWidth, viewHeight; - int alignX, alignY, alignType; - float dpi; - char pathFlag; - char defsFlag; +typedef struct NSVGparser { + NSVGattrib attr[NSVG_MAX_ATTR]; + int attrHead; + float *pts; + int npts; + int cpts; + NSVGpath *plist; + NSVGimage *image; + NSVGgradientData *gradients; + NSVGshape *shapesTail; + float viewMinx, viewMiny, viewWidth, viewHeight; + int alignX, alignY, alignType; + float dpi; + char pathFlag; + char defsFlag; } NSVGparser; -static void nsvg__xformIdentity(float* t) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetTranslation(float* t, float tx, float ty) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = tx; t[5] = ty; -} - -static void nsvg__xformSetScale(float* t, float sx, float sy) -{ - t[0] = sx; t[1] = 0.0f; - t[2] = 0.0f; t[3] = sy; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetSkewX(float* t, float a) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = tanf(a); t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetSkewY(float* t, float a) -{ - t[0] = 1.0f; t[1] = tanf(a); - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetRotation(float* t, float a) -{ - float cs = cosf(a), sn = sinf(a); - t[0] = cs; t[1] = sn; - t[2] = -sn; t[3] = cs; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformMultiply(float* t, float* s) -{ - float t0 = t[0] * s[0] + t[1] * s[2]; - float t2 = t[2] * s[0] + t[3] * s[2]; - float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; - t[1] = t[0] * s[1] + t[1] * s[3]; - t[3] = t[2] * s[1] + t[3] * s[3]; - t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; - t[0] = t0; - t[2] = t2; - t[4] = t4; -} - -static void nsvg__xformInverse(float* inv, float* t) -{ - double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; - if (det > -1e-6 && det < 1e-6) { - nsvg__xformIdentity(t); - return; - } - invdet = 1.0 / det; - inv[0] = (float)(t[3] * invdet); - inv[2] = (float)(-t[2] * invdet); - inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); - inv[1] = (float)(-t[1] * invdet); - inv[3] = (float)(t[0] * invdet); - inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); -} - -static void nsvg__xformPremultiply(float* t, float* s) -{ - float s2[6]; - memcpy(s2, s, sizeof(float)*6); - nsvg__xformMultiply(s2, t); - memcpy(t, s2, sizeof(float)*6); -} - -static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) -{ - *dx = x*t[0] + y*t[2] + t[4]; - *dy = x*t[1] + y*t[3] + t[5]; -} - -static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) -{ - *dx = x*t[0] + y*t[2]; - *dy = x*t[1] + y*t[3]; +static void nsvg__xformIdentity(float *t) { + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetTranslation(float *t, float tx, float ty) { + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = tx; + t[5] = ty; +} + +static void nsvg__xformSetScale(float *t, float sx, float sy) { + t[0] = sx; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = sy; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetSkewX(float *t, float a) { + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = tanf(a); + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetSkewY(float *t, float a) { + t[0] = 1.0f; + t[1] = tanf(a); + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetRotation(float *t, float a) { + float cs = cosf(a), sn = sinf(a); + t[0] = cs; + t[1] = sn; + t[2] = -sn; + t[3] = cs; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformMultiply(float *t, float *s) { + float t0 = t[0] * s[0] + t[1] * s[2]; + float t2 = t[2] * s[0] + t[3] * s[2]; + float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; + t[1] = t[0] * s[1] + t[1] * s[3]; + t[3] = t[2] * s[1] + t[3] * s[3]; + t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; + t[0] = t0; + t[2] = t2; + t[4] = t4; +} + +static void nsvg__xformInverse(float *inv, float *t) { + double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; + if (det > -1e-6 && det < 1e-6) { + nsvg__xformIdentity(t); + return; + } + invdet = 1.0 / det; + inv[0] = (float)(t[3] * invdet); + inv[2] = (float)(-t[2] * invdet); + inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); + inv[1] = (float)(-t[1] * invdet); + inv[3] = (float)(t[0] * invdet); + inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); +} + +static void nsvg__xformPremultiply(float *t, float *s) { + float s2[6]; + memcpy(s2, s, sizeof(float) * 6); + nsvg__xformMultiply(s2, t); + memcpy(t, s2, sizeof(float) * 6); +} + +static void nsvg__xformPoint(float *dx, float *dy, float x, float y, float *t) { + *dx = x * t[0] + y * t[2] + t[4]; + *dy = x * t[1] + y * t[3] + t[5]; +} + +static void nsvg__xformVec(float *dx, float *dy, float x, float y, float *t) { + *dx = x * t[0] + y * t[2]; + *dy = x * t[1] + y * t[3]; } #define NSVG_EPSILON (1e-12) -static int nsvg__ptInBounds(float* pt, float* bounds) -{ - return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; -} - - -static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) -{ - double it = 1.0-t; - return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; -} - -static void nsvg__curveBounds(float* bounds, float* curve) -{ - int i, j, count; - double roots[2], a, b, c, b2ac, t, v; - float* v0 = &curve[0]; - float* v1 = &curve[2]; - float* v2 = &curve[4]; - float* v3 = &curve[6]; - - // Start the bounding box by end points - bounds[0] = nsvg__minf(v0[0], v3[0]); - bounds[1] = nsvg__minf(v0[1], v3[1]); - bounds[2] = nsvg__maxf(v0[0], v3[0]); - bounds[3] = nsvg__maxf(v0[1], v3[1]); - - // Bezier curve fits inside the convex hull of it's control points. - // If control points are inside the bounds, we're done. - if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) - return; - - // Add bezier curve inflection points in X and Y. - for (i = 0; i < 2; i++) { - a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; - b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; - c = 3.0 * v1[i] - 3.0 * v0[i]; - count = 0; - if (fabs(a) < NSVG_EPSILON) { - if (fabs(b) > NSVG_EPSILON) { - t = -c / b; - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - } - } else { - b2ac = b*b - 4.0*c*a; - if (b2ac > NSVG_EPSILON) { - t = (-b + sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - t = (-b - sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - } - } - for (j = 0; j < count; j++) { - v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); - bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); - bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); - } - } -} - -static NSVGparser* nsvg__createParser() -{ - NSVGparser* p; - p = (NSVGparser*)malloc(sizeof(NSVGparser)); - if (p == NULL) goto error; - memset(p, 0, sizeof(NSVGparser)); - - p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); - if (p->image == NULL) goto error; - memset(p->image, 0, sizeof(NSVGimage)); - - // Init style - nsvg__xformIdentity(p->attr[0].xform); - memset(p->attr[0].id, 0, sizeof p->attr[0].id); - p->attr[0].fillColor = NSVG_RGB(0,0,0); - p->attr[0].strokeColor = NSVG_RGB(0,0,0); - p->attr[0].opacity = 1; - p->attr[0].fillOpacity = 1; - p->attr[0].strokeOpacity = 1; - p->attr[0].stopOpacity = 1; - p->attr[0].strokeWidth = 1; - p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; - p->attr[0].strokeLineCap = NSVG_CAP_BUTT; - p->attr[0].miterLimit = 4; - p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; - p->attr[0].hasFill = 1; - p->attr[0].visible = 1; - - return p; +static int nsvg__ptInBounds(float *pt, float *bounds) { + return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; +} + +static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) { + double it = 1.0 - t; + return it * it * it * p0 + 3.0 * it * it * t * p1 + 3.0 * it * t * t * p2 + t * t * t * p3; +} + +static void nsvg__curveBounds(float *bounds, float *curve) { + int i, j, count; + double roots[2], a, b, c, b2ac, t, v; + float *v0 = &curve[0]; + float *v1 = &curve[2]; + float *v2 = &curve[4]; + float *v3 = &curve[6]; + + // Start the bounding box by end points + bounds[0] = nsvg__minf(v0[0], v3[0]); + bounds[1] = nsvg__minf(v0[1], v3[1]); + bounds[2] = nsvg__maxf(v0[0], v3[0]); + bounds[3] = nsvg__maxf(v0[1], v3[1]); + + // Bezier curve fits inside the convex hull of it's control points. + // If control points are inside the bounds, we're done. + if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) + return; + + // Add bezier curve inflection points in X and Y. + for (i = 0; i < 2; i++) { + a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; + b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; + c = 3.0 * v1[i] - 3.0 * v0[i]; + count = 0; + if (fabs(a) < NSVG_EPSILON) { + if (fabs(b) > NSVG_EPSILON) { + t = -c / b; + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + } + } else { + b2ac = b * b - 4.0 * c * a; + if (b2ac > NSVG_EPSILON) { + t = (-b + sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + t = (-b - sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + } + } + for (j = 0; j < count; j++) { + v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); + bounds[0 + i] = nsvg__minf(bounds[0 + i], (float)v); + bounds[2 + i] = nsvg__maxf(bounds[2 + i], (float)v); + } + } +} + +static NSVGparser *nsvg__createParser() { + NSVGparser *p; + p = (NSVGparser *)malloc(sizeof(NSVGparser)); + if (p == NULL) + goto error; + memset(p, 0, sizeof(NSVGparser)); + + p->image = (NSVGimage *)malloc(sizeof(NSVGimage)); + if (p->image == NULL) + goto error; + memset(p->image, 0, sizeof(NSVGimage)); + + // Init style + nsvg__xformIdentity(p->attr[0].xform); + memset(p->attr[0].id, 0, sizeof p->attr[0].id); + p->attr[0].fillColor = NSVG_RGB(0, 0, 0); + p->attr[0].strokeColor = NSVG_RGB(0, 0, 0); + p->attr[0].opacity = 1; + p->attr[0].fillOpacity = 1; + p->attr[0].strokeOpacity = 1; + p->attr[0].stopOpacity = 1; + p->attr[0].strokeWidth = 1; + p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; + p->attr[0].strokeLineCap = NSVG_CAP_BUTT; + p->attr[0].miterLimit = 4; + p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; + p->attr[0].hasFill = 1; + p->attr[0].visible = 1; + + return p; error: - if (p) { - if (p->image) free(p->image); - free(p); - } - return NULL; -} - -static void nsvg__deletePaths(NSVGpath* path) -{ - while (path) { - NSVGpath *next = path->next; - if (path->pts != NULL) - free(path->pts); - free(path); - path = next; - } -} - -static void nsvg__deletePaint(NSVGpaint* paint) -{ - if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) - free(paint->gradient); + if (p) { + if (p->image) + free(p->image); + free(p); + } + return NULL; } - -static void nsvg__deleteGradientData(NSVGgradientData* grad) -{ - NSVGgradientData* next; - while (grad != NULL) { - next = grad->next; - free(grad->stops); - free(grad); - grad = next; - } + +static void nsvg__deletePaths(NSVGpath *path) { + while (path) { + NSVGpath *next = path->next; + if (path->pts != NULL) + free(path->pts); + free(path); + path = next; + } } -static void nsvg__deleteParser(NSVGparser* p) -{ - if (p != NULL) { - nsvg__deletePaths(p->plist); - nsvg__deleteGradientData(p->gradients); - nsvgDelete(p->image); - free(p->pts); - free(p); - } +static void nsvg__deletePaint(NSVGpaint *paint) { + if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) + free(paint->gradient); } -static void nsvg__resetPath(NSVGparser* p) -{ - p->npts = 0; -} - -static void nsvg__addPoint(NSVGparser* p, float x, float y) -{ - if (p->npts+1 > p->cpts) { - p->cpts = p->cpts ? p->cpts*2 : 8; - p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); - if (!p->pts) return; - } - p->pts[p->npts*2+0] = x; - p->pts[p->npts*2+1] = y; - p->npts++; -} - -static void nsvg__moveTo(NSVGparser* p, float x, float y) -{ - if (p->npts > 0) { - p->pts[(p->npts-1)*2+0] = x; - p->pts[(p->npts-1)*2+1] = y; - } else { - nsvg__addPoint(p, x, y); - } -} - -static void nsvg__lineTo(NSVGparser* p, float x, float y) -{ - float px,py, dx,dy; - if (p->npts > 0) { - px = p->pts[(p->npts-1)*2+0]; - py = p->pts[(p->npts-1)*2+1]; - dx = x - px; - dy = y - py; - nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); - nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); - nsvg__addPoint(p, x, y); - } -} - -static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) -{ - nsvg__addPoint(p, cpx1, cpy1); - nsvg__addPoint(p, cpx2, cpy2); - nsvg__addPoint(p, x, y); -} - -static NSVGattrib* nsvg__getAttr(NSVGparser* p) -{ - return &p->attr[p->attrHead]; -} - -static void nsvg__pushAttr(NSVGparser* p) -{ - if (p->attrHead < NSVG_MAX_ATTR-1) { - p->attrHead++; - memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); - } -} - -static void nsvg__popAttr(NSVGparser* p) -{ - if (p->attrHead > 0) - p->attrHead--; -} - -static float nsvg__actualOrigX(NSVGparser* p) -{ - return p->viewMinx; -} - -static float nsvg__actualOrigY(NSVGparser* p) -{ - return p->viewMiny; -} - -static float nsvg__actualWidth(NSVGparser* p) -{ - return p->viewWidth; -} - -static float nsvg__actualHeight(NSVGparser* p) -{ - return p->viewHeight; -} - -static float nsvg__actualLength(NSVGparser* p) -{ - float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); - return sqrtf(w*w + h*h) / sqrtf(2.0f); -} - -static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) -{ - NSVGattrib* attr = nsvg__getAttr(p); - switch (c.units) { - case NSVG_UNITS_USER: return c.value; - case NSVG_UNITS_PX: return c.value; - case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; - case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; - case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; - case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; - case NSVG_UNITS_IN: return c.value * p->dpi; - case NSVG_UNITS_EM: return c.value * attr->fontSize; - case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. - case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; - default: return c.value; - } - return c.value; -} - -static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) -{ - NSVGgradientData* grad = p->gradients; - while (grad) { - if (strcmp(grad->id, id) == 0) - return grad; - grad = grad->next; - } - return NULL; -} - -static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType) -{ - NSVGattrib* attr = nsvg__getAttr(p); - NSVGgradientData* data = NULL; - NSVGgradientData* ref = NULL; - NSVGgradientStop* stops = NULL; - NSVGgradient* grad; - float ox, oy, sw, sh, sl; - int nstops = 0; - - data = nsvg__findGradientData(p, id); - if (data == NULL) return NULL; - - // TODO: use ref to fill in all unset values too. - ref = data; - while (ref != NULL) { - if (stops == NULL && ref->stops != NULL) { - stops = ref->stops; - nstops = ref->nstops; - break; - } - ref = nsvg__findGradientData(p, ref->ref); - } - if (stops == NULL) return NULL; - - grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); - if (grad == NULL) return NULL; - - // The shape width and height. - if (data->units == NSVG_OBJECT_SPACE) { - ox = localBounds[0]; - oy = localBounds[1]; - sw = localBounds[2] - localBounds[0]; - sh = localBounds[3] - localBounds[1]; - } else { - ox = nsvg__actualOrigX(p); - oy = nsvg__actualOrigY(p); - sw = nsvg__actualWidth(p); - sh = nsvg__actualHeight(p); - } - sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); - - if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { - float x1, y1, x2, y2, dx, dy; - x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); - y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); - x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); - y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); - // Calculate transform aligned to the line - dx = x2 - x1; - dy = y2 - y1; - grad->xform[0] = dy; grad->xform[1] = -dx; - grad->xform[2] = dx; grad->xform[3] = dy; - grad->xform[4] = x1; grad->xform[5] = y1; - } else { - float cx, cy, fx, fy, r; - cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); - cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); - fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); - fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); - r = nsvg__convertToPixels(p, data->radial.r, 0, sl); - // Calculate transform aligned to the circle - grad->xform[0] = r; grad->xform[1] = 0; - grad->xform[2] = 0; grad->xform[3] = r; - grad->xform[4] = cx; grad->xform[5] = cy; - grad->fx = fx / r; - grad->fy = fy / r; - } - - nsvg__xformMultiply(grad->xform, data->xform); - nsvg__xformMultiply(grad->xform, attr->xform); - - grad->spread = data->spread; - memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); - grad->nstops = nstops; - - *paintType = data->type; - - return grad; -} - -static float nsvg__getAverageScale(float* t) -{ - float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); - float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); - return (sx + sy) * 0.5f; -} - -static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) -{ - NSVGpath* path; - float curve[4*2], curveBounds[4]; - int i, first = 1; - for (path = shape->paths; path != NULL; path = path->next) { - nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); - for (i = 0; i < path->npts-1; i += 3) { - nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); - nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); - nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); - nsvg__curveBounds(curveBounds, curve); - if (first) { - bounds[0] = curveBounds[0]; - bounds[1] = curveBounds[1]; - bounds[2] = curveBounds[2]; - bounds[3] = curveBounds[3]; - first = 0; - } else { - bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); - bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); - bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); - bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); - } - curve[0] = curve[6]; - curve[1] = curve[7]; - } - } -} - -static void nsvg__addShape(NSVGparser* p) -{ - NSVGattrib* attr = nsvg__getAttr(p); - float scale = 1.0f; - NSVGshape* shape; - NSVGpath* path; - int i; - - if (p->plist == NULL) - return; - - shape = (NSVGshape*)malloc(sizeof(NSVGshape)); - if (shape == NULL) goto error; - memset(shape, 0, sizeof(NSVGshape)); - - memcpy(shape->id, attr->id, sizeof shape->id); - scale = nsvg__getAverageScale(attr->xform); - shape->strokeWidth = attr->strokeWidth * scale; - shape->strokeDashOffset = attr->strokeDashOffset * scale; - shape->strokeDashCount = (char)attr->strokeDashCount; - for (i = 0; i < attr->strokeDashCount; i++) - shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; - shape->strokeLineJoin = attr->strokeLineJoin; - shape->strokeLineCap = attr->strokeLineCap; - shape->miterLimit = attr->miterLimit; - shape->fillRule = attr->fillRule; - shape->opacity = attr->opacity; - - shape->paths = p->plist; - p->plist = NULL; - - // Calculate shape bounds - shape->bounds[0] = shape->paths->bounds[0]; - shape->bounds[1] = shape->paths->bounds[1]; - shape->bounds[2] = shape->paths->bounds[2]; - shape->bounds[3] = shape->paths->bounds[3]; - for (path = shape->paths->next; path != NULL; path = path->next) { - shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); - shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); - shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); - shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); - } - - // Set fill - if (attr->hasFill == 0) { - shape->fill.type = NSVG_PAINT_NONE; - } else if (attr->hasFill == 1) { - shape->fill.type = NSVG_PAINT_COLOR; - shape->fill.color = attr->fillColor; - shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; - } else if (attr->hasFill == 2) { - float inv[6], localBounds[4]; - nsvg__xformInverse(inv, attr->xform); - nsvg__getLocalBounds(localBounds, shape, inv); - shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); - if (shape->fill.gradient == NULL) { - shape->fill.type = NSVG_PAINT_NONE; - } - } - - // Set stroke - if (attr->hasStroke == 0) { - shape->stroke.type = NSVG_PAINT_NONE; - } else if (attr->hasStroke == 1) { - shape->stroke.type = NSVG_PAINT_COLOR; - shape->stroke.color = attr->strokeColor; - shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; - } else if (attr->hasStroke == 2) { - float inv[6], localBounds[4]; - nsvg__xformInverse(inv, attr->xform); - nsvg__getLocalBounds(localBounds, shape, inv); - shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); - if (shape->stroke.gradient == NULL) - shape->stroke.type = NSVG_PAINT_NONE; - } - - // Set flags - shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); - - // Add to tail - if (p->image->shapes == NULL) - p->image->shapes = shape; - else - p->shapesTail->next = shape; - p->shapesTail = shape; - - return; +static void nsvg__deleteGradientData(NSVGgradientData *grad) { + NSVGgradientData *next; + while (grad != NULL) { + next = grad->next; + free(grad->stops); + free(grad); + grad = next; + } +} + +static void nsvg__deleteParser(NSVGparser *p) { + if (p != NULL) { + nsvg__deletePaths(p->plist); + nsvg__deleteGradientData(p->gradients); + nsvgDelete(p->image); + free(p->pts); + free(p); + } +} + +static void nsvg__resetPath(NSVGparser *p) { p->npts = 0; } + +static void nsvg__addPoint(NSVGparser *p, float x, float y) { + if (p->npts + 1 > p->cpts) { + p->cpts = p->cpts ? p->cpts * 2 : 8; + p->pts = (float *)realloc(p->pts, p->cpts * 2 * sizeof(float)); + if (!p->pts) + return; + } + p->pts[p->npts * 2 + 0] = x; + p->pts[p->npts * 2 + 1] = y; + p->npts++; +} + +static void nsvg__moveTo(NSVGparser *p, float x, float y) { + if (p->npts > 0) { + p->pts[(p->npts - 1) * 2 + 0] = x; + p->pts[(p->npts - 1) * 2 + 1] = y; + } else { + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__lineTo(NSVGparser *p, float x, float y) { + float px, py, dx, dy; + if (p->npts > 0) { + px = p->pts[(p->npts - 1) * 2 + 0]; + py = p->pts[(p->npts - 1) * 2 + 1]; + dx = x - px; + dy = y - py; + nsvg__addPoint(p, px + dx / 3.0f, py + dy / 3.0f); + nsvg__addPoint(p, x - dx / 3.0f, y - dy / 3.0f); + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__cubicBezTo(NSVGparser *p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) { + nsvg__addPoint(p, cpx1, cpy1); + nsvg__addPoint(p, cpx2, cpy2); + nsvg__addPoint(p, x, y); +} + +static NSVGattrib *nsvg__getAttr(NSVGparser *p) { return &p->attr[p->attrHead]; } + +static void nsvg__pushAttr(NSVGparser *p) { + if (p->attrHead < NSVG_MAX_ATTR - 1) { + p->attrHead++; + memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead - 1], sizeof(NSVGattrib)); + } +} + +static void nsvg__popAttr(NSVGparser *p) { + if (p->attrHead > 0) + p->attrHead--; +} + +static float nsvg__actualOrigX(NSVGparser *p) { return p->viewMinx; } + +static float nsvg__actualOrigY(NSVGparser *p) { return p->viewMiny; } + +static float nsvg__actualWidth(NSVGparser *p) { return p->viewWidth; } + +static float nsvg__actualHeight(NSVGparser *p) { return p->viewHeight; } + +static float nsvg__actualLength(NSVGparser *p) { + float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); + return sqrtf(w * w + h * h) / sqrtf(2.0f); +} + +static float nsvg__convertToPixels(NSVGparser *p, NSVGcoordinate c, float orig, float length) { + NSVGattrib *attr = nsvg__getAttr(p); + switch (c.units) { + case NSVG_UNITS_USER: + return c.value; + case NSVG_UNITS_PX: + return c.value; + case NSVG_UNITS_PT: + return c.value / 72.0f * p->dpi; + case NSVG_UNITS_PC: + return c.value / 6.0f * p->dpi; + case NSVG_UNITS_MM: + return c.value / 25.4f * p->dpi; + case NSVG_UNITS_CM: + return c.value / 2.54f * p->dpi; + case NSVG_UNITS_IN: + return c.value * p->dpi; + case NSVG_UNITS_EM: + return c.value * attr->fontSize; + case NSVG_UNITS_EX: + return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. + case NSVG_UNITS_PERCENT: + return orig + c.value / 100.0f * length; + default: + return c.value; + } + return c.value; +} + +static NSVGgradientData *nsvg__findGradientData(NSVGparser *p, const char *id) { + NSVGgradientData *grad = p->gradients; + while (grad) { + if (strcmp(grad->id, id) == 0) + return grad; + grad = grad->next; + } + return NULL; +} + +static NSVGgradient *nsvg__createGradient(NSVGparser *p, const char *id, const float *localBounds, char *paintType) { + NSVGattrib *attr = nsvg__getAttr(p); + NSVGgradientData *data = NULL; + NSVGgradientData *ref = NULL; + NSVGgradientStop *stops = NULL; + NSVGgradient *grad; + float ox, oy, sw, sh, sl; + int nstops = 0; + + data = nsvg__findGradientData(p, id); + if (data == NULL) + return NULL; + + // TODO: use ref to fill in all unset values too. + ref = data; + while (ref != NULL) { + if (stops == NULL && ref->stops != NULL) { + stops = ref->stops; + nstops = ref->nstops; + break; + } + ref = nsvg__findGradientData(p, ref->ref); + } + if (stops == NULL) + return NULL; + + grad = (NSVGgradient *)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop) * (nstops - 1)); + if (grad == NULL) + return NULL; + + // The shape width and height. + if (data->units == NSVG_OBJECT_SPACE) { + ox = localBounds[0]; + oy = localBounds[1]; + sw = localBounds[2] - localBounds[0]; + sh = localBounds[3] - localBounds[1]; + } else { + ox = nsvg__actualOrigX(p); + oy = nsvg__actualOrigY(p); + sw = nsvg__actualWidth(p); + sh = nsvg__actualHeight(p); + } + sl = sqrtf(sw * sw + sh * sh) / sqrtf(2.0f); + + if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { + float x1, y1, x2, y2, dx, dy; + x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); + y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); + x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); + y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); + // Calculate transform aligned to the line + dx = x2 - x1; + dy = y2 - y1; + grad->xform[0] = dy; + grad->xform[1] = -dx; + grad->xform[2] = dx; + grad->xform[3] = dy; + grad->xform[4] = x1; + grad->xform[5] = y1; + } else { + float cx, cy, fx, fy, r; + cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); + cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); + fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); + fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); + r = nsvg__convertToPixels(p, data->radial.r, 0, sl); + // Calculate transform aligned to the circle + grad->xform[0] = r; + grad->xform[1] = 0; + grad->xform[2] = 0; + grad->xform[3] = r; + grad->xform[4] = cx; + grad->xform[5] = cy; + grad->fx = fx / r; + grad->fy = fy / r; + } + + nsvg__xformMultiply(grad->xform, data->xform); + nsvg__xformMultiply(grad->xform, attr->xform); + + grad->spread = data->spread; + memcpy(grad->stops, stops, nstops * sizeof(NSVGgradientStop)); + grad->nstops = nstops; + + *paintType = data->type; + + return grad; +} + +static float nsvg__getAverageScale(float *t) { + float sx = sqrtf(t[0] * t[0] + t[2] * t[2]); + float sy = sqrtf(t[1] * t[1] + t[3] * t[3]); + return (sx + sy) * 0.5f; +} + +static void nsvg__getLocalBounds(float *bounds, NSVGshape *shape, float *xform) { + NSVGpath *path; + float curve[4 * 2], curveBounds[4]; + int i, first = 1; + for (path = shape->paths; path != NULL; path = path->next) { + nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); + for (i = 0; i < path->npts - 1; i += 3) { + nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i + 1) * 2], path->pts[(i + 1) * 2 + 1], xform); + nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i + 2) * 2], path->pts[(i + 2) * 2 + 1], xform); + nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i + 3) * 2], path->pts[(i + 3) * 2 + 1], xform); + nsvg__curveBounds(curveBounds, curve); + if (first) { + bounds[0] = curveBounds[0]; + bounds[1] = curveBounds[1]; + bounds[2] = curveBounds[2]; + bounds[3] = curveBounds[3]; + first = 0; + } else { + bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); + bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); + bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); + bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); + } + curve[0] = curve[6]; + curve[1] = curve[7]; + } + } +} + +static void nsvg__addShape(NSVGparser *p) { + NSVGattrib *attr = nsvg__getAttr(p); + float scale = 1.0f; + NSVGshape *shape; + NSVGpath *path; + int i; + + if (p->plist == NULL) + return; + + shape = (NSVGshape *)malloc(sizeof(NSVGshape)); + if (shape == NULL) + goto error; + memset(shape, 0, sizeof(NSVGshape)); + + memcpy(shape->id, attr->id, sizeof shape->id); + scale = nsvg__getAverageScale(attr->xform); + shape->strokeWidth = attr->strokeWidth * scale; + shape->strokeDashOffset = attr->strokeDashOffset * scale; + shape->strokeDashCount = (char)attr->strokeDashCount; + for (i = 0; i < attr->strokeDashCount; i++) + shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; + shape->strokeLineJoin = attr->strokeLineJoin; + shape->strokeLineCap = attr->strokeLineCap; + shape->miterLimit = attr->miterLimit; + shape->fillRule = attr->fillRule; + shape->opacity = attr->opacity; + + shape->paths = p->plist; + p->plist = NULL; + + // Calculate shape bounds + shape->bounds[0] = shape->paths->bounds[0]; + shape->bounds[1] = shape->paths->bounds[1]; + shape->bounds[2] = shape->paths->bounds[2]; + shape->bounds[3] = shape->paths->bounds[3]; + for (path = shape->paths->next; path != NULL; path = path->next) { + shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); + shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); + shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); + shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); + } + + // Set fill + if (attr->hasFill == 0) { + shape->fill.type = NSVG_PAINT_NONE; + } else if (attr->hasFill == 1) { + shape->fill.type = NSVG_PAINT_COLOR; + shape->fill.color = attr->fillColor; + shape->fill.color |= (unsigned int)(attr->fillOpacity * 255) << 24; + } else if (attr->hasFill == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); + if (shape->fill.gradient == NULL) { + shape->fill.type = NSVG_PAINT_NONE; + } + } + + // Set stroke + if (attr->hasStroke == 0) { + shape->stroke.type = NSVG_PAINT_NONE; + } else if (attr->hasStroke == 1) { + shape->stroke.type = NSVG_PAINT_COLOR; + shape->stroke.color = attr->strokeColor; + shape->stroke.color |= (unsigned int)(attr->strokeOpacity * 255) << 24; + } else if (attr->hasStroke == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); + if (shape->stroke.gradient == NULL) + shape->stroke.type = NSVG_PAINT_NONE; + } + + // Set flags + shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); + + // Add to tail + if (p->image->shapes == NULL) + p->image->shapes = shape; + else + p->shapesTail->next = shape; + p->shapesTail = shape; + + return; error: - if (shape) free(shape); -} - -static void nsvg__addPath(NSVGparser* p, char closed) -{ - NSVGattrib* attr = nsvg__getAttr(p); - NSVGpath* path = NULL; - float bounds[4]; - float* curve; - int i; - - if (p->npts < 4) - return; - - if (closed) - nsvg__lineTo(p, p->pts[0], p->pts[1]); - - path = (NSVGpath*)malloc(sizeof(NSVGpath)); - if (path == NULL) goto error; - memset(path, 0, sizeof(NSVGpath)); - - path->pts = (float*)malloc(p->npts*2*sizeof(float)); - if (path->pts == NULL) goto error; - path->closed = closed; - path->npts = p->npts; - - // Transform path. - for (i = 0; i < p->npts; ++i) - nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); - - // Find bounds - for (i = 0; i < path->npts-1; i += 3) { - curve = &path->pts[i*2]; - nsvg__curveBounds(bounds, curve); - if (i == 0) { - path->bounds[0] = bounds[0]; - path->bounds[1] = bounds[1]; - path->bounds[2] = bounds[2]; - path->bounds[3] = bounds[3]; - } else { - path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); - path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); - path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); - path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); - } - } - - path->next = p->plist; - p->plist = path; - - return; + if (shape) + free(shape); +} + +static void nsvg__addPath(NSVGparser *p, char closed) { + NSVGattrib *attr = nsvg__getAttr(p); + NSVGpath *path = NULL; + float bounds[4]; + float *curve; + int i; + + if (p->npts < 4) + return; + + if (closed) + nsvg__lineTo(p, p->pts[0], p->pts[1]); + + path = (NSVGpath *)malloc(sizeof(NSVGpath)); + if (path == NULL) + goto error; + memset(path, 0, sizeof(NSVGpath)); + + path->pts = (float *)malloc(p->npts * 2 * sizeof(float)); + if (path->pts == NULL) + goto error; + path->closed = closed; + path->npts = p->npts; + + // Transform path. + for (i = 0; i < p->npts; ++i) + nsvg__xformPoint(&path->pts[i * 2], &path->pts[i * 2 + 1], p->pts[i * 2], p->pts[i * 2 + 1], attr->xform); + + // Find bounds + for (i = 0; i < path->npts - 1; i += 3) { + curve = &path->pts[i * 2]; + nsvg__curveBounds(bounds, curve); + if (i == 0) { + path->bounds[0] = bounds[0]; + path->bounds[1] = bounds[1]; + path->bounds[2] = bounds[2]; + path->bounds[3] = bounds[3]; + } else { + path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); + path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); + path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); + path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); + } + } + + path->next = p->plist; + p->plist = path; + + return; error: - if (path != NULL) { - if (path->pts != NULL) free(path->pts); - free(path); - } + if (path != NULL) { + if (path->pts != NULL) + free(path->pts); + free(path); + } } // We roll our own string to float because the std library one uses locale and messes things up. -static double nsvg__atof(const char* s) -{ - char* cur = (char*)s; - char* end = NULL; - double res = 0.0, sign = 1.0; - long long intPart = 0, fracPart = 0; - char hasIntPart = 0, hasFracPart = 0; - - // Parse optional sign - if (*cur == '+') { - cur++; - } else if (*cur == '-') { - sign = -1; - cur++; - } - - // Parse integer part - if (nsvg__isdigit(*cur)) { - // Parse digit sequence - intPart = (double)strtoll(cur, &end, 10); - if (cur != end) { - res = (double)intPart; - hasIntPart = 1; - cur = end; - } - } - - // Parse fractional part. - if (*cur == '.') { - cur++; // Skip '.' - if (nsvg__isdigit(*cur)) { - // Parse digit sequence - fracPart = strtoll(cur, &end, 10); - if (cur != end) { - res += (double)fracPart / pow(10.0, (double)(end - cur)); - hasFracPart = 1; - cur = end; - } - } - } - - // A valid number should have integer or fractional part. - if (!hasIntPart && !hasFracPart) - return 0.0; - - // Parse optional exponent - if (*cur == 'e' || *cur == 'E') { - int expPart = 0; - cur++; // skip 'E' - expPart = strtol(cur, &end, 10); // Parse digit sequence with sign - if (cur != end) { - res *= pow(10.0, (double)expPart); - } - } - - return res * sign; -} - - -static const char* nsvg__parseNumber(const char* s, char* it, const int size) -{ - const int last = size-1; - int i = 0; - - // sign - if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; - s++; - } - // integer part - while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - if (*s == '.') { - // decimal point - if (i < last) it[i++] = *s; - s++; - // fraction part - while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - } - // exponent - if (*s == 'e' || *s == 'E') { - if (i < last) it[i++] = *s; - s++; - if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; - s++; - } - while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - } - it[i] = '\0'; - - return s; -} - -static const char* nsvg__getNextPathItem(const char* s, char* it) -{ - it[0] = '\0'; - // Skip white spaces and commas - while (*s && (nsvg__isspace(*s) || *s == ',')) s++; - if (!*s) return s; - if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { - s = nsvg__parseNumber(s, it, 64); - } else { - // Parse command - it[0] = *s++; - it[1] = '\0'; - return s; - } - - return s; -} - -static unsigned int nsvg__parseColorHex(const char* str) -{ - unsigned int c = 0, r = 0, g = 0, b = 0; - int n = 0; - str++; // skip # - // Calculate number of characters. - while(str[n] && !nsvg__isspace(str[n])) - n++; - if (n == 6) { - sscanf(str, "%x", &c); - } else if (n == 3) { - sscanf(str, "%x", &c); - c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8); - c |= c<<4; - } - r = (c >> 16) & 0xff; - g = (c >> 8) & 0xff; - b = c & 0xff; - return NSVG_RGB(r,g,b); -} - -static unsigned int nsvg__parseColorRGB(const char* str) -{ - int r = -1, g = -1, b = -1; - char s1[32]="", s2[32]=""; - sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); - if (strchr(s1, '%')) { - return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100); - } else { - return NSVG_RGB(r,g,b); - } +static double nsvg__atof(const char *s) { + char *cur = (char *)s; + char *end = NULL; + double res = 0.0, sign = 1.0; + long long intPart = 0, fracPart = 0; + char hasIntPart = 0, hasFracPart = 0; + + // Parse optional sign + if (*cur == '+') { + cur++; + } else if (*cur == '-') { + sign = -1; + cur++; + } + + // Parse integer part + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + intPart = (double)strtoll(cur, &end, 10); + if (cur != end) { + res = (double)intPart; + hasIntPart = 1; + cur = end; + } + } + + // Parse fractional part. + if (*cur == '.') { + cur++; // Skip '.' + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + fracPart = strtoll(cur, &end, 10); + if (cur != end) { + res += (double)fracPart / pow(10.0, (double)(end - cur)); + hasFracPart = 1; + cur = end; + } + } + } + + // A valid number should have integer or fractional part. + if (!hasIntPart && !hasFracPart) + return 0.0; + + // Parse optional exponent + if (*cur == 'e' || *cur == 'E') { + int expPart = 0; + cur++; // skip 'E' + expPart = strtol(cur, &end, 10); // Parse digit sequence with sign + if (cur != end) { + res *= pow(10.0, (double)expPart); + } + } + + return res * sign; +} + +static const char *nsvg__parseNumber(const char *s, char *it, const int size) { + const int last = size - 1; + int i = 0; + + // sign + if (*s == '-' || *s == '+') { + if (i < last) + it[i++] = *s; + s++; + } + // integer part + while (*s && nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + if (*s == '.') { + // decimal point + if (i < last) + it[i++] = *s; + s++; + // fraction part + while (*s && nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + } + // exponent + if (*s == 'e' || *s == 'E') { + if (i < last) + it[i++] = *s; + s++; + if (*s == '-' || *s == '+') { + if (i < last) + it[i++] = *s; + s++; + } + while (*s && nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + } + it[i] = '\0'; + + return s; +} + +static const char *nsvg__getNextPathItem(const char *s, char *it) { + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) + s++; + if (!*s) + return s; + if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { + s = nsvg__parseNumber(s, it, 64); + } else { + // Parse command + it[0] = *s++; + it[1] = '\0'; + return s; + } + + return s; +} + +static unsigned int nsvg__parseColorHex(const char *str) { + unsigned int c = 0, r = 0, g = 0, b = 0; + int n = 0; + str++; // skip # + // Calculate number of characters. + while (str[n] && !nsvg__isspace(str[n])) + n++; + if (n == 6) { + sscanf(str, "%x", &c); + } else if (n == 3) { + sscanf(str, "%x", &c); + c = (c & 0xf) | ((c & 0xf0) << 4) | ((c & 0xf00) << 8); + c |= c << 4; + } + r = (c >> 16) & 0xff; + g = (c >> 8) & 0xff; + b = c & 0xff; + return NSVG_RGB(r, g, b); +} + +static unsigned int nsvg__parseColorRGB(const char *str) { + int r = -1, g = -1, b = -1; + char s1[32] = "", s2[32] = ""; + sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); + if (strchr(s1, '%')) { + return NSVG_RGB((r * 255) / 100, (g * 255) / 100, (b * 255) / 100); + } else { + return NSVG_RGB(r, g, b); + } } typedef struct NSVGNamedColor { - const char* name; - unsigned int color; + const char *name; + unsigned int color; } NSVGNamedColor; NSVGNamedColor nsvg__colors[] = { - { "red", NSVG_RGB(255, 0, 0) }, - { "green", NSVG_RGB( 0, 128, 0) }, - { "blue", NSVG_RGB( 0, 0, 255) }, - { "yellow", NSVG_RGB(255, 255, 0) }, - { "cyan", NSVG_RGB( 0, 255, 255) }, - { "magenta", NSVG_RGB(255, 0, 255) }, - { "black", NSVG_RGB( 0, 0, 0) }, - { "grey", NSVG_RGB(128, 128, 128) }, - { "gray", NSVG_RGB(128, 128, 128) }, - { "white", NSVG_RGB(255, 255, 255) }, + {"red", NSVG_RGB(255, 0, 0)}, + {"green", NSVG_RGB(0, 128, 0)}, + {"blue", NSVG_RGB(0, 0, 255)}, + {"yellow", NSVG_RGB(255, 255, 0)}, + {"cyan", NSVG_RGB(0, 255, 255)}, + {"magenta", NSVG_RGB(255, 0, 255)}, + {"black", NSVG_RGB(0, 0, 0)}, + {"grey", NSVG_RGB(128, 128, 128)}, + {"gray", NSVG_RGB(128, 128, 128)}, + {"white", NSVG_RGB(255, 255, 255)}, #ifdef NANOSVG_ALL_COLOR_KEYWORDS - { "aliceblue", NSVG_RGB(240, 248, 255) }, - { "antiquewhite", NSVG_RGB(250, 235, 215) }, - { "aqua", NSVG_RGB( 0, 255, 255) }, - { "aquamarine", NSVG_RGB(127, 255, 212) }, - { "azure", NSVG_RGB(240, 255, 255) }, - { "beige", NSVG_RGB(245, 245, 220) }, - { "bisque", NSVG_RGB(255, 228, 196) }, - { "blanchedalmond", NSVG_RGB(255, 235, 205) }, - { "blueviolet", NSVG_RGB(138, 43, 226) }, - { "brown", NSVG_RGB(165, 42, 42) }, - { "burlywood", NSVG_RGB(222, 184, 135) }, - { "cadetblue", NSVG_RGB( 95, 158, 160) }, - { "chartreuse", NSVG_RGB(127, 255, 0) }, - { "chocolate", NSVG_RGB(210, 105, 30) }, - { "coral", NSVG_RGB(255, 127, 80) }, - { "cornflowerblue", NSVG_RGB(100, 149, 237) }, - { "cornsilk", NSVG_RGB(255, 248, 220) }, - { "crimson", NSVG_RGB(220, 20, 60) }, - { "darkblue", NSVG_RGB( 0, 0, 139) }, - { "darkcyan", NSVG_RGB( 0, 139, 139) }, - { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, - { "darkgray", NSVG_RGB(169, 169, 169) }, - { "darkgreen", NSVG_RGB( 0, 100, 0) }, - { "darkgrey", NSVG_RGB(169, 169, 169) }, - { "darkkhaki", NSVG_RGB(189, 183, 107) }, - { "darkmagenta", NSVG_RGB(139, 0, 139) }, - { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, - { "darkorange", NSVG_RGB(255, 140, 0) }, - { "darkorchid", NSVG_RGB(153, 50, 204) }, - { "darkred", NSVG_RGB(139, 0, 0) }, - { "darksalmon", NSVG_RGB(233, 150, 122) }, - { "darkseagreen", NSVG_RGB(143, 188, 143) }, - { "darkslateblue", NSVG_RGB( 72, 61, 139) }, - { "darkslategray", NSVG_RGB( 47, 79, 79) }, - { "darkslategrey", NSVG_RGB( 47, 79, 79) }, - { "darkturquoise", NSVG_RGB( 0, 206, 209) }, - { "darkviolet", NSVG_RGB(148, 0, 211) }, - { "deeppink", NSVG_RGB(255, 20, 147) }, - { "deepskyblue", NSVG_RGB( 0, 191, 255) }, - { "dimgray", NSVG_RGB(105, 105, 105) }, - { "dimgrey", NSVG_RGB(105, 105, 105) }, - { "dodgerblue", NSVG_RGB( 30, 144, 255) }, - { "firebrick", NSVG_RGB(178, 34, 34) }, - { "floralwhite", NSVG_RGB(255, 250, 240) }, - { "forestgreen", NSVG_RGB( 34, 139, 34) }, - { "fuchsia", NSVG_RGB(255, 0, 255) }, - { "gainsboro", NSVG_RGB(220, 220, 220) }, - { "ghostwhite", NSVG_RGB(248, 248, 255) }, - { "gold", NSVG_RGB(255, 215, 0) }, - { "goldenrod", NSVG_RGB(218, 165, 32) }, - { "greenyellow", NSVG_RGB(173, 255, 47) }, - { "honeydew", NSVG_RGB(240, 255, 240) }, - { "hotpink", NSVG_RGB(255, 105, 180) }, - { "indianred", NSVG_RGB(205, 92, 92) }, - { "indigo", NSVG_RGB( 75, 0, 130) }, - { "ivory", NSVG_RGB(255, 255, 240) }, - { "khaki", NSVG_RGB(240, 230, 140) }, - { "lavender", NSVG_RGB(230, 230, 250) }, - { "lavenderblush", NSVG_RGB(255, 240, 245) }, - { "lawngreen", NSVG_RGB(124, 252, 0) }, - { "lemonchiffon", NSVG_RGB(255, 250, 205) }, - { "lightblue", NSVG_RGB(173, 216, 230) }, - { "lightcoral", NSVG_RGB(240, 128, 128) }, - { "lightcyan", NSVG_RGB(224, 255, 255) }, - { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, - { "lightgray", NSVG_RGB(211, 211, 211) }, - { "lightgreen", NSVG_RGB(144, 238, 144) }, - { "lightgrey", NSVG_RGB(211, 211, 211) }, - { "lightpink", NSVG_RGB(255, 182, 193) }, - { "lightsalmon", NSVG_RGB(255, 160, 122) }, - { "lightseagreen", NSVG_RGB( 32, 178, 170) }, - { "lightskyblue", NSVG_RGB(135, 206, 250) }, - { "lightslategray", NSVG_RGB(119, 136, 153) }, - { "lightslategrey", NSVG_RGB(119, 136, 153) }, - { "lightsteelblue", NSVG_RGB(176, 196, 222) }, - { "lightyellow", NSVG_RGB(255, 255, 224) }, - { "lime", NSVG_RGB( 0, 255, 0) }, - { "limegreen", NSVG_RGB( 50, 205, 50) }, - { "linen", NSVG_RGB(250, 240, 230) }, - { "maroon", NSVG_RGB(128, 0, 0) }, - { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, - { "mediumblue", NSVG_RGB( 0, 0, 205) }, - { "mediumorchid", NSVG_RGB(186, 85, 211) }, - { "mediumpurple", NSVG_RGB(147, 112, 219) }, - { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, - { "mediumslateblue", NSVG_RGB(123, 104, 238) }, - { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, - { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, - { "mediumvioletred", NSVG_RGB(199, 21, 133) }, - { "midnightblue", NSVG_RGB( 25, 25, 112) }, - { "mintcream", NSVG_RGB(245, 255, 250) }, - { "mistyrose", NSVG_RGB(255, 228, 225) }, - { "moccasin", NSVG_RGB(255, 228, 181) }, - { "navajowhite", NSVG_RGB(255, 222, 173) }, - { "navy", NSVG_RGB( 0, 0, 128) }, - { "oldlace", NSVG_RGB(253, 245, 230) }, - { "olive", NSVG_RGB(128, 128, 0) }, - { "olivedrab", NSVG_RGB(107, 142, 35) }, - { "orange", NSVG_RGB(255, 165, 0) }, - { "orangered", NSVG_RGB(255, 69, 0) }, - { "orchid", NSVG_RGB(218, 112, 214) }, - { "palegoldenrod", NSVG_RGB(238, 232, 170) }, - { "palegreen", NSVG_RGB(152, 251, 152) }, - { "paleturquoise", NSVG_RGB(175, 238, 238) }, - { "palevioletred", NSVG_RGB(219, 112, 147) }, - { "papayawhip", NSVG_RGB(255, 239, 213) }, - { "peachpuff", NSVG_RGB(255, 218, 185) }, - { "peru", NSVG_RGB(205, 133, 63) }, - { "pink", NSVG_RGB(255, 192, 203) }, - { "plum", NSVG_RGB(221, 160, 221) }, - { "powderblue", NSVG_RGB(176, 224, 230) }, - { "purple", NSVG_RGB(128, 0, 128) }, - { "rosybrown", NSVG_RGB(188, 143, 143) }, - { "royalblue", NSVG_RGB( 65, 105, 225) }, - { "saddlebrown", NSVG_RGB(139, 69, 19) }, - { "salmon", NSVG_RGB(250, 128, 114) }, - { "sandybrown", NSVG_RGB(244, 164, 96) }, - { "seagreen", NSVG_RGB( 46, 139, 87) }, - { "seashell", NSVG_RGB(255, 245, 238) }, - { "sienna", NSVG_RGB(160, 82, 45) }, - { "silver", NSVG_RGB(192, 192, 192) }, - { "skyblue", NSVG_RGB(135, 206, 235) }, - { "slateblue", NSVG_RGB(106, 90, 205) }, - { "slategray", NSVG_RGB(112, 128, 144) }, - { "slategrey", NSVG_RGB(112, 128, 144) }, - { "snow", NSVG_RGB(255, 250, 250) }, - { "springgreen", NSVG_RGB( 0, 255, 127) }, - { "steelblue", NSVG_RGB( 70, 130, 180) }, - { "tan", NSVG_RGB(210, 180, 140) }, - { "teal", NSVG_RGB( 0, 128, 128) }, - { "thistle", NSVG_RGB(216, 191, 216) }, - { "tomato", NSVG_RGB(255, 99, 71) }, - { "turquoise", NSVG_RGB( 64, 224, 208) }, - { "violet", NSVG_RGB(238, 130, 238) }, - { "wheat", NSVG_RGB(245, 222, 179) }, - { "whitesmoke", NSVG_RGB(245, 245, 245) }, - { "yellowgreen", NSVG_RGB(154, 205, 50) }, + {"aliceblue", NSVG_RGB(240, 248, 255)}, + {"antiquewhite", NSVG_RGB(250, 235, 215)}, + {"aqua", NSVG_RGB(0, 255, 255)}, + {"aquamarine", NSVG_RGB(127, 255, 212)}, + {"azure", NSVG_RGB(240, 255, 255)}, + {"beige", NSVG_RGB(245, 245, 220)}, + {"bisque", NSVG_RGB(255, 228, 196)}, + {"blanchedalmond", NSVG_RGB(255, 235, 205)}, + {"blueviolet", NSVG_RGB(138, 43, 226)}, + {"brown", NSVG_RGB(165, 42, 42)}, + {"burlywood", NSVG_RGB(222, 184, 135)}, + {"cadetblue", NSVG_RGB(95, 158, 160)}, + {"chartreuse", NSVG_RGB(127, 255, 0)}, + {"chocolate", NSVG_RGB(210, 105, 30)}, + {"coral", NSVG_RGB(255, 127, 80)}, + {"cornflowerblue", NSVG_RGB(100, 149, 237)}, + {"cornsilk", NSVG_RGB(255, 248, 220)}, + {"crimson", NSVG_RGB(220, 20, 60)}, + {"darkblue", NSVG_RGB(0, 0, 139)}, + {"darkcyan", NSVG_RGB(0, 139, 139)}, + {"darkgoldenrod", NSVG_RGB(184, 134, 11)}, + {"darkgray", NSVG_RGB(169, 169, 169)}, + {"darkgreen", NSVG_RGB(0, 100, 0)}, + {"darkgrey", NSVG_RGB(169, 169, 169)}, + {"darkkhaki", NSVG_RGB(189, 183, 107)}, + {"darkmagenta", NSVG_RGB(139, 0, 139)}, + {"darkolivegreen", NSVG_RGB(85, 107, 47)}, + {"darkorange", NSVG_RGB(255, 140, 0)}, + {"darkorchid", NSVG_RGB(153, 50, 204)}, + {"darkred", NSVG_RGB(139, 0, 0)}, + {"darksalmon", NSVG_RGB(233, 150, 122)}, + {"darkseagreen", NSVG_RGB(143, 188, 143)}, + {"darkslateblue", NSVG_RGB(72, 61, 139)}, + {"darkslategray", NSVG_RGB(47, 79, 79)}, + {"darkslategrey", NSVG_RGB(47, 79, 79)}, + {"darkturquoise", NSVG_RGB(0, 206, 209)}, + {"darkviolet", NSVG_RGB(148, 0, 211)}, + {"deeppink", NSVG_RGB(255, 20, 147)}, + {"deepskyblue", NSVG_RGB(0, 191, 255)}, + {"dimgray", NSVG_RGB(105, 105, 105)}, + {"dimgrey", NSVG_RGB(105, 105, 105)}, + {"dodgerblue", NSVG_RGB(30, 144, 255)}, + {"firebrick", NSVG_RGB(178, 34, 34)}, + {"floralwhite", NSVG_RGB(255, 250, 240)}, + {"forestgreen", NSVG_RGB(34, 139, 34)}, + {"fuchsia", NSVG_RGB(255, 0, 255)}, + {"gainsboro", NSVG_RGB(220, 220, 220)}, + {"ghostwhite", NSVG_RGB(248, 248, 255)}, + {"gold", NSVG_RGB(255, 215, 0)}, + {"goldenrod", NSVG_RGB(218, 165, 32)}, + {"greenyellow", NSVG_RGB(173, 255, 47)}, + {"honeydew", NSVG_RGB(240, 255, 240)}, + {"hotpink", NSVG_RGB(255, 105, 180)}, + {"indianred", NSVG_RGB(205, 92, 92)}, + {"indigo", NSVG_RGB(75, 0, 130)}, + {"ivory", NSVG_RGB(255, 255, 240)}, + {"khaki", NSVG_RGB(240, 230, 140)}, + {"lavender", NSVG_RGB(230, 230, 250)}, + {"lavenderblush", NSVG_RGB(255, 240, 245)}, + {"lawngreen", NSVG_RGB(124, 252, 0)}, + {"lemonchiffon", NSVG_RGB(255, 250, 205)}, + {"lightblue", NSVG_RGB(173, 216, 230)}, + {"lightcoral", NSVG_RGB(240, 128, 128)}, + {"lightcyan", NSVG_RGB(224, 255, 255)}, + {"lightgoldenrodyellow", NSVG_RGB(250, 250, 210)}, + {"lightgray", NSVG_RGB(211, 211, 211)}, + {"lightgreen", NSVG_RGB(144, 238, 144)}, + {"lightgrey", NSVG_RGB(211, 211, 211)}, + {"lightpink", NSVG_RGB(255, 182, 193)}, + {"lightsalmon", NSVG_RGB(255, 160, 122)}, + {"lightseagreen", NSVG_RGB(32, 178, 170)}, + {"lightskyblue", NSVG_RGB(135, 206, 250)}, + {"lightslategray", NSVG_RGB(119, 136, 153)}, + {"lightslategrey", NSVG_RGB(119, 136, 153)}, + {"lightsteelblue", NSVG_RGB(176, 196, 222)}, + {"lightyellow", NSVG_RGB(255, 255, 224)}, + {"lime", NSVG_RGB(0, 255, 0)}, + {"limegreen", NSVG_RGB(50, 205, 50)}, + {"linen", NSVG_RGB(250, 240, 230)}, + {"maroon", NSVG_RGB(128, 0, 0)}, + {"mediumaquamarine", NSVG_RGB(102, 205, 170)}, + {"mediumblue", NSVG_RGB(0, 0, 205)}, + {"mediumorchid", NSVG_RGB(186, 85, 211)}, + {"mediumpurple", NSVG_RGB(147, 112, 219)}, + {"mediumseagreen", NSVG_RGB(60, 179, 113)}, + {"mediumslateblue", NSVG_RGB(123, 104, 238)}, + {"mediumspringgreen", NSVG_RGB(0, 250, 154)}, + {"mediumturquoise", NSVG_RGB(72, 209, 204)}, + {"mediumvioletred", NSVG_RGB(199, 21, 133)}, + {"midnightblue", NSVG_RGB(25, 25, 112)}, + {"mintcream", NSVG_RGB(245, 255, 250)}, + {"mistyrose", NSVG_RGB(255, 228, 225)}, + {"moccasin", NSVG_RGB(255, 228, 181)}, + {"navajowhite", NSVG_RGB(255, 222, 173)}, + {"navy", NSVG_RGB(0, 0, 128)}, + {"oldlace", NSVG_RGB(253, 245, 230)}, + {"olive", NSVG_RGB(128, 128, 0)}, + {"olivedrab", NSVG_RGB(107, 142, 35)}, + {"orange", NSVG_RGB(255, 165, 0)}, + {"orangered", NSVG_RGB(255, 69, 0)}, + {"orchid", NSVG_RGB(218, 112, 214)}, + {"palegoldenrod", NSVG_RGB(238, 232, 170)}, + {"palegreen", NSVG_RGB(152, 251, 152)}, + {"paleturquoise", NSVG_RGB(175, 238, 238)}, + {"palevioletred", NSVG_RGB(219, 112, 147)}, + {"papayawhip", NSVG_RGB(255, 239, 213)}, + {"peachpuff", NSVG_RGB(255, 218, 185)}, + {"peru", NSVG_RGB(205, 133, 63)}, + {"pink", NSVG_RGB(255, 192, 203)}, + {"plum", NSVG_RGB(221, 160, 221)}, + {"powderblue", NSVG_RGB(176, 224, 230)}, + {"purple", NSVG_RGB(128, 0, 128)}, + {"rosybrown", NSVG_RGB(188, 143, 143)}, + {"royalblue", NSVG_RGB(65, 105, 225)}, + {"saddlebrown", NSVG_RGB(139, 69, 19)}, + {"salmon", NSVG_RGB(250, 128, 114)}, + {"sandybrown", NSVG_RGB(244, 164, 96)}, + {"seagreen", NSVG_RGB(46, 139, 87)}, + {"seashell", NSVG_RGB(255, 245, 238)}, + {"sienna", NSVG_RGB(160, 82, 45)}, + {"silver", NSVG_RGB(192, 192, 192)}, + {"skyblue", NSVG_RGB(135, 206, 235)}, + {"slateblue", NSVG_RGB(106, 90, 205)}, + {"slategray", NSVG_RGB(112, 128, 144)}, + {"slategrey", NSVG_RGB(112, 128, 144)}, + {"snow", NSVG_RGB(255, 250, 250)}, + {"springgreen", NSVG_RGB(0, 255, 127)}, + {"steelblue", NSVG_RGB(70, 130, 180)}, + {"tan", NSVG_RGB(210, 180, 140)}, + {"teal", NSVG_RGB(0, 128, 128)}, + {"thistle", NSVG_RGB(216, 191, 216)}, + {"tomato", NSVG_RGB(255, 99, 71)}, + {"turquoise", NSVG_RGB(64, 224, 208)}, + {"violet", NSVG_RGB(238, 130, 238)}, + {"wheat", NSVG_RGB(245, 222, 179)}, + {"whitesmoke", NSVG_RGB(245, 245, 245)}, + {"yellowgreen", NSVG_RGB(154, 205, 50)}, #endif }; -static unsigned int nsvg__parseColorName(const char* str) -{ - int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); - - for (i = 0; i < ncolors; i++) { - if (strcmp(nsvg__colors[i].name, str) == 0) { - return nsvg__colors[i].color; - } - } - - return NSVG_RGB(128, 128, 128); -} - -static unsigned int nsvg__parseColor(const char* str) -{ - size_t len = 0; - while(*str == ' ') ++str; - len = strlen(str); - if (len >= 1 && *str == '#') - return nsvg__parseColorHex(str); - else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') - return nsvg__parseColorRGB(str); - return nsvg__parseColorName(str); -} - -static float nsvg__parseOpacity(const char* str) -{ - float val = 0; - sscanf(str, "%f", &val); - if (val < 0.0f) val = 0.0f; - if (val > 1.0f) val = 1.0f; - return val; -} - -static float nsvg__parseMiterLimit(const char* str) -{ - float val = 0; - sscanf(str, "%f", &val); - if (val < 0.0f) val = 0.0f; - return val; -} - -static int nsvg__parseUnits(const char* units) -{ - if (units[0] == 'p' && units[1] == 'x') - return NSVG_UNITS_PX; - else if (units[0] == 'p' && units[1] == 't') - return NSVG_UNITS_PT; - else if (units[0] == 'p' && units[1] == 'c') - return NSVG_UNITS_PC; - else if (units[0] == 'm' && units[1] == 'm') - return NSVG_UNITS_MM; - else if (units[0] == 'c' && units[1] == 'm') - return NSVG_UNITS_CM; - else if (units[0] == 'i' && units[1] == 'n') - return NSVG_UNITS_IN; - else if (units[0] == '%') - return NSVG_UNITS_PERCENT; - else if (units[0] == 'e' && units[1] == 'm') - return NSVG_UNITS_EM; - else if (units[0] == 'e' && units[1] == 'x') - return NSVG_UNITS_EX; - return NSVG_UNITS_USER; -} - -static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) -{ - NSVGcoordinate coord = {0, NSVG_UNITS_USER}; - char units[32]=""; - sscanf(str, "%f%31s", &coord.value, units); - coord.units = nsvg__parseUnits(units); - return coord; -} - -static NSVGcoordinate nsvg__coord(float v, int units) -{ - NSVGcoordinate coord = {v, units}; - return coord; -} - -static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) -{ - NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); - return nsvg__convertToPixels(p, coord, orig, length); -} - -static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) -{ - const char* end; - const char* ptr; - char it[64]; - - *na = 0; - ptr = str; - while (*ptr && *ptr != '(') ++ptr; - if (*ptr == 0) - return 1; - end = ptr; - while (*end && *end != ')') ++end; - if (*end == 0) - return 1; - - while (ptr < end) { - if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { - if (*na >= maxNa) return 0; - ptr = nsvg__parseNumber(ptr, it, 64); - args[(*na)++] = (float)nsvg__atof(it); - } else { - ++ptr; - } - } - return (int)(end - str); -} - - -static int nsvg__parseMatrix(float* xform, const char* str) -{ - float t[6]; - int na = 0; - int len = nsvg__parseTransformArgs(str, t, 6, &na); - if (na != 6) return len; - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseTranslate(float* xform, const char* str) -{ - float args[2]; - float t[6]; - int na = 0; - int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = 0.0; - - nsvg__xformSetTranslation(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseScale(float* xform, const char* str) -{ - float args[2]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = args[0]; - nsvg__xformSetScale(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseSkewX(float* xform, const char* str) -{ - float args[1]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseSkewY(float* xform, const char* str) -{ - float args[1]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseRotate(float* xform, const char* str) -{ - float args[3]; - int na = 0; - float m[6]; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 3, &na); - if (na == 1) - args[1] = args[2] = 0.0f; - nsvg__xformIdentity(m); - - if (na > 1) { - nsvg__xformSetTranslation(t, -args[1], -args[2]); - nsvg__xformMultiply(m, t); - } - - nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); - nsvg__xformMultiply(m, t); - - if (na > 1) { - nsvg__xformSetTranslation(t, args[1], args[2]); - nsvg__xformMultiply(m, t); - } - - memcpy(xform, m, sizeof(float)*6); - - return len; -} - -static void nsvg__parseTransform(float* xform, const char* str) -{ - float t[6]; - nsvg__xformIdentity(xform); - while (*str) - { - if (strncmp(str, "matrix", 6) == 0) - str += nsvg__parseMatrix(t, str); - else if (strncmp(str, "translate", 9) == 0) - str += nsvg__parseTranslate(t, str); - else if (strncmp(str, "scale", 5) == 0) - str += nsvg__parseScale(t, str); - else if (strncmp(str, "rotate", 6) == 0) - str += nsvg__parseRotate(t, str); - else if (strncmp(str, "skewX", 5) == 0) - str += nsvg__parseSkewX(t, str); - else if (strncmp(str, "skewY", 5) == 0) - str += nsvg__parseSkewY(t, str); - else{ - ++str; - continue; - } - - nsvg__xformPremultiply(xform, t); - } -} - -static void nsvg__parseUrl(char* id, const char* str) -{ - int i = 0; - str += 4; // "url("; - if (*str == '#') - str++; - while (i < 63 && *str != ')') { - id[i] = *str++; - i++; - } - id[i] = '\0'; -} - -static char nsvg__parseLineCap(const char* str) -{ - if (strcmp(str, "butt") == 0) - return NSVG_CAP_BUTT; - else if (strcmp(str, "round") == 0) - return NSVG_CAP_ROUND; - else if (strcmp(str, "square") == 0) - return NSVG_CAP_SQUARE; - // TODO: handle inherit. - return NSVG_CAP_BUTT; -} - -static char nsvg__parseLineJoin(const char* str) -{ - if (strcmp(str, "miter") == 0) - return NSVG_JOIN_MITER; - else if (strcmp(str, "round") == 0) - return NSVG_JOIN_ROUND; - else if (strcmp(str, "bevel") == 0) - return NSVG_JOIN_BEVEL; - // TODO: handle inherit. - return NSVG_JOIN_MITER; -} - -static char nsvg__parseFillRule(const char* str) -{ - if (strcmp(str, "nonzero") == 0) - return NSVG_FILLRULE_NONZERO; - else if (strcmp(str, "evenodd") == 0) - return NSVG_FILLRULE_EVENODD; - // TODO: handle inherit. - return NSVG_FILLRULE_NONZERO; -} - -static const char* nsvg__getNextDashItem(const char* s, char* it) -{ - int n = 0; - it[0] = '\0'; - // Skip white spaces and commas - while (*s && (nsvg__isspace(*s) || *s == ',')) s++; - // Advance until whitespace, comma or end. - while (*s && (!nsvg__isspace(*s) && *s != ',')) { - if (n < 63) - it[n++] = *s; - s++; - } - it[n++] = '\0'; - return s; -} - -static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) -{ - char item[64]; - int count = 0, i; - float sum = 0.0f; - - // Handle "none" - if (str[0] == 'n') - return 0; - - // Parse dashes - while (*str) { - str = nsvg__getNextDashItem(str, item); - if (!*item) break; - if (count < NSVG_MAX_DASHES) - strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); - } - - for (i = 0; i < count; i++) - sum += strokeDashArray[i]; - if (sum <= 1e-6f) - count = 0; - - return count; -} - -static void nsvg__parseStyle(NSVGparser* p, const char* str); - -static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) -{ - float xform[6]; - NSVGattrib* attr = nsvg__getAttr(p); - if (!attr) return 0; - - if (strcmp(name, "style") == 0) { - nsvg__parseStyle(p, value); - } else if (strcmp(name, "display") == 0) { - if (strcmp(value, "none") == 0) - attr->visible = 0; - // Don't reset ->visible on display:inline, one display:none hides the whole subtree - - } else if (strcmp(name, "fill") == 0) { - if (strcmp(value, "none") == 0) { - attr->hasFill = 0; - } else if (strncmp(value, "url(", 4) == 0) { - attr->hasFill = 2; - nsvg__parseUrl(attr->fillGradient, value); - } else { - attr->hasFill = 1; - attr->fillColor = nsvg__parseColor(value); - } - } else if (strcmp(name, "opacity") == 0) { - attr->opacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "fill-opacity") == 0) { - attr->fillOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "stroke") == 0) { - if (strcmp(value, "none") == 0) { - attr->hasStroke = 0; - } else if (strncmp(value, "url(", 4) == 0) { - attr->hasStroke = 2; - nsvg__parseUrl(attr->strokeGradient, value); - } else { - attr->hasStroke = 1; - attr->strokeColor = nsvg__parseColor(value); - } - } else if (strcmp(name, "stroke-width") == 0) { - attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "stroke-dasharray") == 0) { - attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); - } else if (strcmp(name, "stroke-dashoffset") == 0) { - attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "stroke-opacity") == 0) { - attr->strokeOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "stroke-linecap") == 0) { - attr->strokeLineCap = nsvg__parseLineCap(value); - } else if (strcmp(name, "stroke-linejoin") == 0) { - attr->strokeLineJoin = nsvg__parseLineJoin(value); - } else if (strcmp(name, "stroke-miterlimit") == 0) { - attr->miterLimit = nsvg__parseMiterLimit(value); - } else if (strcmp(name, "fill-rule") == 0) { - attr->fillRule = nsvg__parseFillRule(value); - } else if (strcmp(name, "font-size") == 0) { - attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "transform") == 0) { - nsvg__parseTransform(xform, value); - nsvg__xformPremultiply(attr->xform, xform); - } else if (strcmp(name, "stop-color") == 0) { - attr->stopColor = nsvg__parseColor(value); - } else if (strcmp(name, "stop-opacity") == 0) { - attr->stopOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "offset") == 0) { - attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); - } else if (strcmp(name, "id") == 0) { - strncpy(attr->id, value, 63); - attr->id[63] = '\0'; - } else { - return 0; - } - return 1; -} - -static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) -{ - const char* str; - const char* val; - char name[512]; - char value[512]; - int n; - - str = start; - while (str < end && *str != ':') ++str; - - val = str; - - // Right Trim - while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; - ++str; - - n = (int)(str - start); - if (n > 511) n = 511; - if (n) memcpy(name, start, n); - name[n] = 0; - - while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; - - n = (int)(end - val); - if (n > 511) n = 511; - if (n) memcpy(value, val, n); - value[n] = 0; - - return nsvg__parseAttr(p, name, value); -} - -static void nsvg__parseStyle(NSVGparser* p, const char* str) -{ - const char* start; - const char* end; - - while (*str) { - // Left Trim - while(*str && nsvg__isspace(*str)) ++str; - start = str; - while(*str && *str != ';') ++str; - end = str; - - // Right Trim - while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; - ++end; - - nsvg__parseNameValue(p, start, end); - if (*str) ++str; - } -} - -static void nsvg__parseAttribs(NSVGparser* p, const char** attr) -{ - int i; - for (i = 0; attr[i]; i += 2) - { - if (strcmp(attr[i], "style") == 0) - nsvg__parseStyle(p, attr[i + 1]); - else - nsvg__parseAttr(p, attr[i], attr[i + 1]); - } -} - -static int nsvg__getArgsPerElement(char cmd) -{ - switch (cmd) { - case 'v': - case 'V': - case 'h': - case 'H': - return 1; - case 'm': - case 'M': - case 'l': - case 'L': - case 't': - case 'T': - return 2; - case 'q': - case 'Q': - case 's': - case 'S': - return 4; - case 'c': - case 'C': - return 6; - case 'a': - case 'A': - return 7; - } - return 0; -} - -static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) { - *cpx += args[0]; - *cpy += args[1]; - } else { - *cpx = args[0]; - *cpy = args[1]; - } - nsvg__moveTo(p, *cpx, *cpy); -} - -static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) { - *cpx += args[0]; - *cpy += args[1]; - } else { - *cpx = args[0]; - *cpy = args[1]; - } - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) - *cpx += args[0]; - else - *cpx = args[0]; - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) - *cpy += args[0]; - else - *cpy = args[0]; - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x2, y2, cx1, cy1, cx2, cy2; - - if (rel) { - cx1 = *cpx + args[0]; - cy1 = *cpy + args[1]; - cx2 = *cpx + args[2]; - cy2 = *cpy + args[3]; - x2 = *cpx + args[4]; - y2 = *cpy + args[5]; - } else { - cx1 = args[0]; - cy1 = args[1]; - cx2 = args[2]; - cy2 = args[3]; - x2 = args[4]; - y2 = args[5]; - } - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx2; - *cpy2 = cy2; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - cx2 = *cpx + args[0]; - cy2 = *cpy + args[1]; - x2 = *cpx + args[2]; - y2 = *cpy + args[3]; - } else { - cx2 = args[0]; - cy2 = args[1]; - x2 = args[2]; - y2 = args[3]; - } - - cx1 = 2*x1 - *cpx2; - cy1 = 2*y1 - *cpy2; - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx2; - *cpy2 = cy2; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx, cy; - float cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - cx = *cpx + args[0]; - cy = *cpy + args[1]; - x2 = *cpx + args[2]; - y2 = *cpy + args[3]; - } else { - cx = args[0]; - cy = args[1]; - x2 = args[2]; - y2 = args[3]; - } - - // Convert to cubic bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx; - *cpy2 = cy; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx, cy; - float cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - x2 = *cpx + args[0]; - y2 = *cpy + args[1]; - } else { - x2 = args[0]; - y2 = args[1]; - } - - cx = 2*x1 - *cpx2; - cy = 2*y1 - *cpy2; - - // Convert to cubix bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx; - *cpy2 = cy; - *cpx = x2; - *cpy = y2; -} - -static float nsvg__sqr(float x) { return x*x; } -static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } - -static float nsvg__vecrat(float ux, float uy, float vx, float vy) -{ - return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); -} - -static float nsvg__vecang(float ux, float uy, float vx, float vy) -{ - float r = nsvg__vecrat(ux,uy, vx,vy); - if (r < -1.0f) r = -1.0f; - if (r > 1.0f) r = 1.0f; - return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); -} - -static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - // Ported from canvg (https://code.google.com/p/canvg/) - float rx, ry, rotx; - float x1, y1, x2, y2, cx, cy, dx, dy, d; - float x1p, y1p, cxp, cyp, s, sa, sb; - float ux, uy, vx, vy, a1, da; - float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; - float sinrx, cosrx; - int fa, fs; - int i, ndivs; - float hda, kappa; - - rx = fabsf(args[0]); // y radius - ry = fabsf(args[1]); // x radius - rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle - fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc - fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction - x1 = *cpx; // start point - y1 = *cpy; - if (rel) { // end point - x2 = *cpx + args[5]; - y2 = *cpy + args[6]; - } else { - x2 = args[5]; - y2 = args[6]; - } - - dx = x1 - x2; - dy = y1 - y2; - d = sqrtf(dx*dx + dy*dy); - if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { - // The arc degenerates to a line - nsvg__lineTo(p, x2, y2); - *cpx = x2; - *cpy = y2; - return; - } - - sinrx = sinf(rotx); - cosrx = cosf(rotx); - - // Convert to center point parameterization. - // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - // 1) Compute x1', y1' - x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; - y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; - d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); - if (d > 1) { - d = sqrtf(d); - rx *= d; - ry *= d; - } - // 2) Compute cx', cy' - s = 0.0f; - sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); - sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); - if (sa < 0.0f) sa = 0.0f; - if (sb > 0.0f) - s = sqrtf(sa / sb); - if (fa == fs) - s = -s; - cxp = s * rx * y1p / ry; - cyp = s * -ry * x1p / rx; - - // 3) Compute cx,cy from cx',cy' - cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; - cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; - - // 4) Calculate theta1, and delta theta. - ux = (x1p - cxp) / rx; - uy = (y1p - cyp) / ry; - vx = (-x1p - cxp) / rx; - vy = (-y1p - cyp) / ry; - a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle - da = nsvg__vecang(ux,uy, vx,vy); // Delta angle - -// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; -// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; - - if (fs == 0 && da > 0) - da -= 2 * NSVG_PI; - else if (fs == 1 && da < 0) - da += 2 * NSVG_PI; - - // Approximate the arc using cubic spline segments. - t[0] = cosrx; t[1] = sinrx; - t[2] = -sinrx; t[3] = cosrx; - t[4] = cx; t[5] = cy; - - // Split arc into max 90 degree segments. - // The loop assumes an iteration per end point (including start and end), this +1. - ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); - hda = (da / (float)ndivs) / 2.0f; - kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); - if (da < 0.0f) - kappa = -kappa; - - for (i = 0; i <= ndivs; i++) { - a = a1 + da * ((float)i/(float)ndivs); - dx = cosf(a); - dy = sinf(a); - nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position - nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent - if (i > 0) - nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); - px = x; - py = y; - ptanx = tanx; - ptany = tany; - } - - *cpx = x2; - *cpy = y2; -} - -static void nsvg__parsePath(NSVGparser* p, const char** attr) -{ - const char* s = NULL; - char cmd = '\0'; - float args[10]; - int nargs; - int rargs = 0; - float cpx, cpy, cpx2, cpy2; - const char* tmp[4]; - char closedFlag; - int i; - char item[64]; - - for (i = 0; attr[i]; i += 2) { - if (strcmp(attr[i], "d") == 0) { - s = attr[i + 1]; - } else { - tmp[0] = attr[i]; - tmp[1] = attr[i + 1]; - tmp[2] = 0; - tmp[3] = 0; - nsvg__parseAttribs(p, tmp); - } - } - - if (s) { - nsvg__resetPath(p); - cpx = 0; cpy = 0; - cpx2 = 0; cpy2 = 0; - closedFlag = 0; - nargs = 0; - - while (*s) { - s = nsvg__getNextPathItem(s, item); - if (!*item) break; - if (nsvg__isnum(item[0])) { - if (nargs < 10) - args[nargs++] = (float)nsvg__atof(item); - if (nargs >= rargs) { - switch (cmd) { - case 'm': - case 'M': - nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); - // Moveto can be followed by multiple coordinate pairs, - // which should be treated as linetos. - cmd = (cmd == 'm') ? 'l' : 'L'; - rargs = nsvg__getArgsPerElement(cmd); - cpx2 = cpx; cpy2 = cpy; - break; - case 'l': - case 'L': - nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'H': - case 'h': - nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'V': - case 'v': - nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'C': - case 'c': - nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); - break; - case 'S': - case 's': - nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); - break; - case 'Q': - case 'q': - nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); - break; - case 'T': - case 't': - nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); - break; - case 'A': - case 'a': - nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - default: - if (nargs >= 2) { - cpx = args[nargs-2]; - cpy = args[nargs-1]; - cpx2 = cpx; cpy2 = cpy; - } - break; - } - nargs = 0; - } - } else { - cmd = item[0]; - rargs = nsvg__getArgsPerElement(cmd); - if (cmd == 'M' || cmd == 'm') { - // Commit path. - if (p->npts > 0) - nsvg__addPath(p, closedFlag); - // Start new subpath. - nsvg__resetPath(p); - closedFlag = 0; - nargs = 0; - } else if (cmd == 'Z' || cmd == 'z') { - closedFlag = 1; - // Commit path. - if (p->npts > 0) { - // Move current point to first point - cpx = p->pts[0]; - cpy = p->pts[1]; - cpx2 = cpx; cpy2 = cpy; - nsvg__addPath(p, closedFlag); - } - // Start new subpath. - nsvg__resetPath(p); - nsvg__moveTo(p, cpx, cpy); - closedFlag = 0; - nargs = 0; - } - } - } - // Commit path. - if (p->npts) - nsvg__addPath(p, closedFlag); - } - - nsvg__addShape(p); -} - -static void nsvg__parseRect(NSVGparser* p, const char** attr) -{ - float x = 0.0f; - float y = 0.0f; - float w = 0.0f; - float h = 0.0f; - float rx = -1.0f; // marks not set - float ry = -1.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); - if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); - } - } - - if (rx < 0.0f && ry > 0.0f) rx = ry; - if (ry < 0.0f && rx > 0.0f) ry = rx; - if (rx < 0.0f) rx = 0.0f; - if (ry < 0.0f) ry = 0.0f; - if (rx > w/2.0f) rx = w/2.0f; - if (ry > h/2.0f) ry = h/2.0f; - - if (w != 0.0f && h != 0.0f) { - nsvg__resetPath(p); - - if (rx < 0.00001f || ry < 0.0001f) { - nsvg__moveTo(p, x, y); - nsvg__lineTo(p, x+w, y); - nsvg__lineTo(p, x+w, y+h); - nsvg__lineTo(p, x, y+h); - } else { - // Rounded rectangle - nsvg__moveTo(p, x+rx, y); - nsvg__lineTo(p, x+w-rx, y); - nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); - nsvg__lineTo(p, x+w, y+h-ry); - nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); - nsvg__lineTo(p, x+rx, y+h); - nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); - nsvg__lineTo(p, x, y+ry); - nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); - } - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseCircle(NSVGparser* p, const char** attr) -{ - float cx = 0.0f; - float cy = 0.0f; - float r = 0.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); - } - } - - if (r > 0.0f) { - nsvg__resetPath(p); - - nsvg__moveTo(p, cx+r, cy); - nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); - nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); - nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); - nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseEllipse(NSVGparser* p, const char** attr) -{ - float cx = 0.0f; - float cy = 0.0f; - float rx = 0.0f; - float ry = 0.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); - } - } - - if (rx > 0.0f && ry > 0.0f) { - - nsvg__resetPath(p); - - nsvg__moveTo(p, cx+rx, cy); - nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); - nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); - nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); - nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseLine(NSVGparser* p, const char** attr) -{ - float x1 = 0.0; - float y1 = 0.0; - float x2 = 0.0; - float y2 = 0.0; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - } - } - - nsvg__resetPath(p); - - nsvg__moveTo(p, x1, y1); - nsvg__lineTo(p, x2, y2); - - nsvg__addPath(p, 0); - - nsvg__addShape(p); -} - -static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) -{ - int i; - const char* s; - float args[2]; - int nargs, npts = 0; - char item[64]; - - nsvg__resetPath(p); - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "points") == 0) { - s = attr[i + 1]; - nargs = 0; - while (*s) { - s = nsvg__getNextPathItem(s, item); - args[nargs++] = (float)nsvg__atof(item); - if (nargs >= 2) { - if (npts == 0) - nsvg__moveTo(p, args[0], args[1]); - else - nsvg__lineTo(p, args[0], args[1]); - nargs = 0; - npts++; - } - } - } - } - } - - nsvg__addPath(p, (char)closeFlag); - - nsvg__addShape(p); -} - -static void nsvg__parseSVG(NSVGparser* p, const char** attr) -{ - int i; - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "width") == 0) { - p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); - } else if (strcmp(attr[i], "height") == 0) { - p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); - } else if (strcmp(attr[i], "viewBox") == 0) { - sscanf(attr[i + 1], "%f%*[%%, \t]%f%*[%%, \t]%f%*[%%, \t]%f", &p->viewMinx, &p->viewMiny, &p->viewWidth, &p->viewHeight); - } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { - if (strstr(attr[i + 1], "none") != 0) { - // No uniform scaling - p->alignType = NSVG_ALIGN_NONE; - } else { - // Parse X align - if (strstr(attr[i + 1], "xMin") != 0) - p->alignX = NSVG_ALIGN_MIN; - else if (strstr(attr[i + 1], "xMid") != 0) - p->alignX = NSVG_ALIGN_MID; - else if (strstr(attr[i + 1], "xMax") != 0) - p->alignX = NSVG_ALIGN_MAX; - // Parse X align - if (strstr(attr[i + 1], "yMin") != 0) - p->alignY = NSVG_ALIGN_MIN; - else if (strstr(attr[i + 1], "yMid") != 0) - p->alignY = NSVG_ALIGN_MID; - else if (strstr(attr[i + 1], "yMax") != 0) - p->alignY = NSVG_ALIGN_MAX; - // Parse meet/slice - p->alignType = NSVG_ALIGN_MEET; - if (strstr(attr[i + 1], "slice") != 0) - p->alignType = NSVG_ALIGN_SLICE; - } - } - } - } -} - -static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) -{ - int i; - NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); - if (grad == NULL) return; - memset(grad, 0, sizeof(NSVGgradientData)); - grad->units = NSVG_OBJECT_SPACE; - grad->type = type; - if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { - grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); - grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { - grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - } - - nsvg__xformIdentity(grad->xform); - - for (i = 0; attr[i]; i += 2) { - if (strcmp(attr[i], "id") == 0) { - strncpy(grad->id, attr[i+1], 63); - grad->id[63] = '\0'; - } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "gradientUnits") == 0) { - if (strcmp(attr[i+1], "objectBoundingBox") == 0) - grad->units = NSVG_OBJECT_SPACE; - else - grad->units = NSVG_USER_SPACE; - } else if (strcmp(attr[i], "gradientTransform") == 0) { - nsvg__parseTransform(grad->xform, attr[i + 1]); - } else if (strcmp(attr[i], "cx") == 0) { - grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "cy") == 0) { - grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "r") == 0) { - grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "fx") == 0) { - grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "fy") == 0) { - grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "x1") == 0) { - grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "y1") == 0) { - grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "x2") == 0) { - grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "y2") == 0) { - grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "spreadMethod") == 0) { - if (strcmp(attr[i+1], "pad") == 0) - grad->spread = NSVG_SPREAD_PAD; - else if (strcmp(attr[i+1], "reflect") == 0) - grad->spread = NSVG_SPREAD_REFLECT; - else if (strcmp(attr[i+1], "repeat") == 0) - grad->spread = NSVG_SPREAD_REPEAT; - } else if (strcmp(attr[i], "xlink:href") == 0) { - const char *href = attr[i+1]; - strncpy(grad->ref, href+1, 62); - grad->ref[62] = '\0'; - } - } - } - - grad->next = p->gradients; - p->gradients = grad; -} - -static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) -{ - NSVGattrib* curAttr = nsvg__getAttr(p); - NSVGgradientData* grad; - NSVGgradientStop* stop; - int i, idx; - - curAttr->stopOffset = 0; - curAttr->stopColor = 0; - curAttr->stopOpacity = 1.0f; - - for (i = 0; attr[i]; i += 2) { - nsvg__parseAttr(p, attr[i], attr[i + 1]); - } - - // Add stop to the last gradient. - grad = p->gradients; - if (grad == NULL) return; - - grad->nstops++; - grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); - if (grad->stops == NULL) return; - - // Insert - idx = grad->nstops-1; - for (i = 0; i < grad->nstops-1; i++) { - if (curAttr->stopOffset < grad->stops[i].offset) { - idx = i; - break; - } - } - if (idx != grad->nstops-1) { - for (i = grad->nstops-1; i > idx; i--) - grad->stops[i] = grad->stops[i-1]; - } - - stop = &grad->stops[idx]; - stop->color = curAttr->stopColor; - stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; - stop->offset = curAttr->stopOffset; -} - -static void nsvg__startElement(void* ud, const char* el, const char** attr) -{ - NSVGparser* p = (NSVGparser*)ud; - - if (p->defsFlag) { - // Skip everything but gradients in defs - if (strcmp(el, "linearGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); - } else if (strcmp(el, "radialGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); - } else if (strcmp(el, "stop") == 0) { - nsvg__parseGradientStop(p, attr); - } - return; - } - - if (strcmp(el, "g") == 0) { - nsvg__pushAttr(p); - nsvg__parseAttribs(p, attr); - } else if (strcmp(el, "path") == 0) { - if (p->pathFlag) // Do not allow nested paths. - return; - nsvg__pushAttr(p); - nsvg__parsePath(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "rect") == 0) { - nsvg__pushAttr(p); - nsvg__parseRect(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "circle") == 0) { - nsvg__pushAttr(p); - nsvg__parseCircle(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "ellipse") == 0) { - nsvg__pushAttr(p); - nsvg__parseEllipse(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "line") == 0) { - nsvg__pushAttr(p); - nsvg__parseLine(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "polyline") == 0) { - nsvg__pushAttr(p); - nsvg__parsePoly(p, attr, 0); - nsvg__popAttr(p); - } else if (strcmp(el, "polygon") == 0) { - nsvg__pushAttr(p); - nsvg__parsePoly(p, attr, 1); - nsvg__popAttr(p); - } else if (strcmp(el, "linearGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); - } else if (strcmp(el, "radialGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); - } else if (strcmp(el, "stop") == 0) { - nsvg__parseGradientStop(p, attr); - } else if (strcmp(el, "defs") == 0) { - p->defsFlag = 1; - } else if (strcmp(el, "svg") == 0) { - nsvg__parseSVG(p, attr); - } -} - -static void nsvg__endElement(void* ud, const char* el) -{ - NSVGparser* p = (NSVGparser*)ud; - - if (strcmp(el, "g") == 0) { - nsvg__popAttr(p); - } else if (strcmp(el, "path") == 0) { - p->pathFlag = 0; - } else if (strcmp(el, "defs") == 0) { - p->defsFlag = 0; - } -} - -static void nsvg__content(void* ud, const char* s) -{ - NSVG_NOTUSED(ud); - NSVG_NOTUSED(s); - // empty -} - -static void nsvg__imageBounds(NSVGparser* p, float* bounds) -{ - NSVGshape* shape; - shape = p->image->shapes; - if (shape == NULL) { - bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; - return; - } - bounds[0] = shape->bounds[0]; - bounds[1] = shape->bounds[1]; - bounds[2] = shape->bounds[2]; - bounds[3] = shape->bounds[3]; - for (shape = shape->next; shape != NULL; shape = shape->next) { - bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); - bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); - bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); - bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); - } -} - -static float nsvg__viewAlign(float content, float container, int type) -{ - if (type == NSVG_ALIGN_MIN) - return 0; - else if (type == NSVG_ALIGN_MAX) - return container - content; - // mid - return (container - content) * 0.5f; -} - -static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) -{ - float t[6]; - nsvg__xformSetTranslation(t, tx, ty); - nsvg__xformMultiply (grad->xform, t); - - nsvg__xformSetScale(t, sx, sy); - nsvg__xformMultiply (grad->xform, t); -} - -static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) -{ - NSVGshape* shape; - NSVGpath* path; - float tx, ty, sx, sy, us, bounds[4], t[6], avgs; - int i; - float* pt; - - // Guess image size if not set completely. - nsvg__imageBounds(p, bounds); - - if (p->viewWidth == 0) { - if (p->image->width > 0) { - p->viewWidth = p->image->width; - } else { - p->viewMinx = bounds[0]; - p->viewWidth = bounds[2] - bounds[0]; - } - } - if (p->viewHeight == 0) { - if (p->image->height > 0) { - p->viewHeight = p->image->height; - } else { - p->viewMiny = bounds[1]; - p->viewHeight = bounds[3] - bounds[1]; - } - } - if (p->image->width == 0) - p->image->width = p->viewWidth; - if (p->image->height == 0) - p->image->height = p->viewHeight; - - tx = -p->viewMinx; - ty = -p->viewMiny; - sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; - sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; - // Unit scaling - us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); - - // Fix aspect ratio - if (p->alignType == NSVG_ALIGN_MEET) { - // fit whole image into viewbox - sx = sy = nsvg__minf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; - } else if (p->alignType == NSVG_ALIGN_SLICE) { - // fill whole viewbox with image - sx = sy = nsvg__maxf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; - } - - // Transform - sx *= us; - sy *= us; - avgs = (sx+sy) / 2.0f; - for (shape = p->image->shapes; shape != NULL; shape = shape->next) { - shape->bounds[0] = (shape->bounds[0] + tx) * sx; - shape->bounds[1] = (shape->bounds[1] + ty) * sy; - shape->bounds[2] = (shape->bounds[2] + tx) * sx; - shape->bounds[3] = (shape->bounds[3] + ty) * sy; - for (path = shape->paths; path != NULL; path = path->next) { - path->bounds[0] = (path->bounds[0] + tx) * sx; - path->bounds[1] = (path->bounds[1] + ty) * sy; - path->bounds[2] = (path->bounds[2] + tx) * sx; - path->bounds[3] = (path->bounds[3] + ty) * sy; - for (i =0; i < path->npts; i++) { - pt = &path->pts[i*2]; - pt[0] = (pt[0] + tx) * sx; - pt[1] = (pt[1] + ty) * sy; - } - } - - if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); - memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); - nsvg__xformInverse(shape->fill.gradient->xform, t); - } - if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); - memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); - nsvg__xformInverse(shape->stroke.gradient->xform, t); - } - - shape->strokeWidth *= avgs; - shape->strokeDashOffset *= avgs; - for (i = 0; i < shape->strokeDashCount; i++) - shape->strokeDashArray[i] *= avgs; - } -} - -NSVGimage* nsvgParse(char* input, const char* units, float dpi) -{ - NSVGparser* p; - NSVGimage* ret = 0; - - p = nsvg__createParser(); - if (p == NULL) { - return NULL; - } - p->dpi = dpi; - - nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); - - // Scale to viewBox - nsvg__scaleToViewbox(p, units); - - ret = p->image; - p->image = NULL; - - nsvg__deleteParser(p); - - return ret; -} - -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) -{ - FILE* fp = NULL; - size_t size; - char* data = NULL; - NSVGimage* image = NULL; - - fp = fopen(filename, "rb"); - if (!fp) goto error; - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, 0, SEEK_SET); - data = (char*)malloc(size+1); - if (data == NULL) goto error; - if (fread(data, 1, size, fp) != size) goto error; - data[size] = '\0'; // Must be null terminated. - fclose(fp); - image = nsvgParse(data, units, dpi); - free(data); - - return image; +static unsigned int nsvg__parseColorName(const char *str) { + int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); + + for (i = 0; i < ncolors; i++) { + if (strcmp(nsvg__colors[i].name, str) == 0) { + return nsvg__colors[i].color; + } + } + + return NSVG_RGB(128, 128, 128); +} + +static unsigned int nsvg__parseColor(const char *str) { + size_t len = 0; + while (*str == ' ') + ++str; + len = strlen(str); + if (len >= 1 && *str == '#') + return nsvg__parseColorHex(str); + else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') + return nsvg__parseColorRGB(str); + return nsvg__parseColorName(str); +} + +static float nsvg__parseOpacity(const char *str) { + float val = 0; + sscanf(str, "%f", &val); + if (val < 0.0f) + val = 0.0f; + if (val > 1.0f) + val = 1.0f; + return val; +} + +static float nsvg__parseMiterLimit(const char *str) { + float val = 0; + sscanf(str, "%f", &val); + if (val < 0.0f) + val = 0.0f; + return val; +} + +static int nsvg__parseUnits(const char *units) { + if (units[0] == 'p' && units[1] == 'x') + return NSVG_UNITS_PX; + else if (units[0] == 'p' && units[1] == 't') + return NSVG_UNITS_PT; + else if (units[0] == 'p' && units[1] == 'c') + return NSVG_UNITS_PC; + else if (units[0] == 'm' && units[1] == 'm') + return NSVG_UNITS_MM; + else if (units[0] == 'c' && units[1] == 'm') + return NSVG_UNITS_CM; + else if (units[0] == 'i' && units[1] == 'n') + return NSVG_UNITS_IN; + else if (units[0] == '%') + return NSVG_UNITS_PERCENT; + else if (units[0] == 'e' && units[1] == 'm') + return NSVG_UNITS_EM; + else if (units[0] == 'e' && units[1] == 'x') + return NSVG_UNITS_EX; + return NSVG_UNITS_USER; +} + +static NSVGcoordinate nsvg__parseCoordinateRaw(const char *str) { + NSVGcoordinate coord = {0, NSVG_UNITS_USER}; + char units[32] = ""; + sscanf(str, "%f%31s", &coord.value, units); + coord.units = nsvg__parseUnits(units); + return coord; +} + +static NSVGcoordinate nsvg__coord(float v, int units) { + NSVGcoordinate coord = {v, units}; + return coord; +} + +static float nsvg__parseCoordinate(NSVGparser *p, const char *str, float orig, float length) { + NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); + return nsvg__convertToPixels(p, coord, orig, length); +} + +static int nsvg__parseTransformArgs(const char *str, float *args, int maxNa, int *na) { + const char *end; + const char *ptr; + char it[64]; + + *na = 0; + ptr = str; + while (*ptr && *ptr != '(') + ++ptr; + if (*ptr == 0) + return 1; + end = ptr; + while (*end && *end != ')') + ++end; + if (*end == 0) + return 1; + + while (ptr < end) { + if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { + if (*na >= maxNa) + return 0; + ptr = nsvg__parseNumber(ptr, it, 64); + args[(*na)++] = (float)nsvg__atof(it); + } else { + ++ptr; + } + } + return (int)(end - str); +} + +static int nsvg__parseMatrix(float *xform, const char *str) { + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, t, 6, &na); + if (na != 6) + return len; + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseTranslate(float *xform, const char *str) { + float args[2]; + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) + args[1] = 0.0; + + nsvg__xformSetTranslation(t, args[0], args[1]); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseScale(float *xform, const char *str) { + float args[2]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) + args[1] = args[0]; + nsvg__xformSetScale(t, args[0], args[1]); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseSkewX(float *xform, const char *str) { + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewX(t, args[0] / 180.0f * NSVG_PI); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseSkewY(float *xform, const char *str) { + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewY(t, args[0] / 180.0f * NSVG_PI); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseRotate(float *xform, const char *str) { + float args[3]; + int na = 0; + float m[6]; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 3, &na); + if (na == 1) + args[1] = args[2] = 0.0f; + nsvg__xformIdentity(m); + + if (na > 1) { + nsvg__xformSetTranslation(t, -args[1], -args[2]); + nsvg__xformMultiply(m, t); + } + + nsvg__xformSetRotation(t, args[0] / 180.0f * NSVG_PI); + nsvg__xformMultiply(m, t); + + if (na > 1) { + nsvg__xformSetTranslation(t, args[1], args[2]); + nsvg__xformMultiply(m, t); + } + + memcpy(xform, m, sizeof(float) * 6); + + return len; +} + +static void nsvg__parseTransform(float *xform, const char *str) { + float t[6]; + nsvg__xformIdentity(xform); + while (*str) { + if (strncmp(str, "matrix", 6) == 0) + str += nsvg__parseMatrix(t, str); + else if (strncmp(str, "translate", 9) == 0) + str += nsvg__parseTranslate(t, str); + else if (strncmp(str, "scale", 5) == 0) + str += nsvg__parseScale(t, str); + else if (strncmp(str, "rotate", 6) == 0) + str += nsvg__parseRotate(t, str); + else if (strncmp(str, "skewX", 5) == 0) + str += nsvg__parseSkewX(t, str); + else if (strncmp(str, "skewY", 5) == 0) + str += nsvg__parseSkewY(t, str); + else { + ++str; + continue; + } + + nsvg__xformPremultiply(xform, t); + } +} + +static void nsvg__parseUrl(char *id, const char *str) { + int i = 0; + str += 4; // "url("; + if (*str == '#') + str++; + while (i < 63 && *str != ')') { + id[i] = *str++; + i++; + } + id[i] = '\0'; +} + +static char nsvg__parseLineCap(const char *str) { + if (strcmp(str, "butt") == 0) + return NSVG_CAP_BUTT; + else if (strcmp(str, "round") == 0) + return NSVG_CAP_ROUND; + else if (strcmp(str, "square") == 0) + return NSVG_CAP_SQUARE; + // TODO: handle inherit. + return NSVG_CAP_BUTT; +} + +static char nsvg__parseLineJoin(const char *str) { + if (strcmp(str, "miter") == 0) + return NSVG_JOIN_MITER; + else if (strcmp(str, "round") == 0) + return NSVG_JOIN_ROUND; + else if (strcmp(str, "bevel") == 0) + return NSVG_JOIN_BEVEL; + // TODO: handle inherit. + return NSVG_JOIN_MITER; +} + +static char nsvg__parseFillRule(const char *str) { + if (strcmp(str, "nonzero") == 0) + return NSVG_FILLRULE_NONZERO; + else if (strcmp(str, "evenodd") == 0) + return NSVG_FILLRULE_EVENODD; + // TODO: handle inherit. + return NSVG_FILLRULE_NONZERO; +} + +static const char *nsvg__getNextDashItem(const char *s, char *it) { + int n = 0; + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) + s++; + // Advance until whitespace, comma or end. + while (*s && (!nsvg__isspace(*s) && *s != ',')) { + if (n < 63) + it[n++] = *s; + s++; + } + it[n++] = '\0'; + return s; +} + +static int nsvg__parseStrokeDashArray(NSVGparser *p, const char *str, float *strokeDashArray) { + char item[64]; + int count = 0, i; + float sum = 0.0f; + + // Handle "none" + if (str[0] == 'n') + return 0; + + // Parse dashes + while (*str) { + str = nsvg__getNextDashItem(str, item); + if (!*item) + break; + if (count < NSVG_MAX_DASHES) + strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); + } + + for (i = 0; i < count; i++) + sum += strokeDashArray[i]; + if (sum <= 1e-6f) + count = 0; + + return count; +} + +static void nsvg__parseStyle(NSVGparser *p, const char *str); + +static int nsvg__parseAttr(NSVGparser *p, const char *name, const char *value) { + float xform[6]; + NSVGattrib *attr = nsvg__getAttr(p); + if (!attr) + return 0; + + if (strcmp(name, "style") == 0) { + nsvg__parseStyle(p, value); + } else if (strcmp(name, "display") == 0) { + if (strcmp(value, "none") == 0) + attr->visible = 0; + // Don't reset ->visible on display:inline, one display:none hides the whole subtree + + } else if (strcmp(name, "fill") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasFill = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasFill = 2; + nsvg__parseUrl(attr->fillGradient, value); + } else { + attr->hasFill = 1; + attr->fillColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "opacity") == 0) { + attr->opacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "fill-opacity") == 0) { + attr->fillOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasStroke = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasStroke = 2; + nsvg__parseUrl(attr->strokeGradient, value); + } else { + attr->hasStroke = 1; + attr->strokeColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "stroke-width") == 0) { + attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-dasharray") == 0) { + attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); + } else if (strcmp(name, "stroke-dashoffset") == 0) { + attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-opacity") == 0) { + attr->strokeOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke-linecap") == 0) { + attr->strokeLineCap = nsvg__parseLineCap(value); + } else if (strcmp(name, "stroke-linejoin") == 0) { + attr->strokeLineJoin = nsvg__parseLineJoin(value); + } else if (strcmp(name, "stroke-miterlimit") == 0) { + attr->miterLimit = nsvg__parseMiterLimit(value); + } else if (strcmp(name, "fill-rule") == 0) { + attr->fillRule = nsvg__parseFillRule(value); + } else if (strcmp(name, "font-size") == 0) { + attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "transform") == 0) { + nsvg__parseTransform(xform, value); + nsvg__xformPremultiply(attr->xform, xform); + } else if (strcmp(name, "stop-color") == 0) { + attr->stopColor = nsvg__parseColor(value); + } else if (strcmp(name, "stop-opacity") == 0) { + attr->stopOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "offset") == 0) { + attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); + } else if (strcmp(name, "id") == 0) { + strncpy(attr->id, value, 63); + attr->id[63] = '\0'; + } else { + return 0; + } + return 1; +} + +static int nsvg__parseNameValue(NSVGparser *p, const char *start, const char *end) { + const char *str; + const char *val; + char name[512]; + char value[512]; + int n; + + str = start; + while (str < end && *str != ':') + ++str; + + val = str; + + // Right Trim + while (str > start && (*str == ':' || nsvg__isspace(*str))) + --str; + ++str; + + n = (int)(str - start); + if (n > 511) + n = 511; + if (n) + memcpy(name, start, n); + name[n] = 0; + + while (val < end && (*val == ':' || nsvg__isspace(*val))) + ++val; + + n = (int)(end - val); + if (n > 511) + n = 511; + if (n) + memcpy(value, val, n); + value[n] = 0; + + return nsvg__parseAttr(p, name, value); +} + +static void nsvg__parseStyle(NSVGparser *p, const char *str) { + const char *start; + const char *end; + + while (*str) { + // Left Trim + while (*str && nsvg__isspace(*str)) + ++str; + start = str; + while (*str && *str != ';') + ++str; + end = str; + + // Right Trim + while (end > start && (*end == ';' || nsvg__isspace(*end))) + --end; + ++end; + + nsvg__parseNameValue(p, start, end); + if (*str) + ++str; + } +} + +static void nsvg__parseAttribs(NSVGparser *p, const char **attr) { + int i; + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "style") == 0) + nsvg__parseStyle(p, attr[i + 1]); + else + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } +} + +static int nsvg__getArgsPerElement(char cmd) { + switch (cmd) { + case 'v': + case 'V': + case 'h': + case 'H': + return 1; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + return 2; + case 'q': + case 'Q': + case 's': + case 'S': + return 4; + case 'c': + case 'C': + return 6; + case 'a': + case 'A': + return 7; + } + return 0; +} + +static void nsvg__pathMoveTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__moveTo(p, *cpx, *cpy); +} + +static void nsvg__pathLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathHLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) + *cpx += args[0]; + else + *cpx = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathVLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) + *cpy += args[0]; + else + *cpy = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathCubicBezTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, + int rel) { + float x2, y2, cx1, cy1, cx2, cy2; + + if (rel) { + cx1 = *cpx + args[0]; + cy1 = *cpy + args[1]; + cx2 = *cpx + args[2]; + cy2 = *cpy + args[3]; + x2 = *cpx + args[4]; + y2 = *cpy + args[5]; + } else { + cx1 = args[0]; + cy1 = args[1]; + cx2 = args[2]; + cy2 = args[3]; + x2 = args[4]; + y2 = args[5]; + } + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathCubicBezShortTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, + int rel) { + float x1, y1, x2, y2, cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx2 = *cpx + args[0]; + cy2 = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx2 = args[0]; + cy2 = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + cx1 = 2 * x1 - *cpx2; + cy1 = 2 * y1 - *cpy2; + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel) { + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx = *cpx + args[0]; + cy = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx = args[0]; + cy = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + // Convert to cubic bezier + cx1 = x1 + 2.0f / 3.0f * (cx - x1); + cy1 = y1 + 2.0f / 3.0f * (cy - y1); + cx2 = x2 + 2.0f / 3.0f * (cx - x2); + cy2 = y2 + 2.0f / 3.0f * (cy - y2); + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezShortTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, + int rel) { + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + x2 = *cpx + args[0]; + y2 = *cpy + args[1]; + } else { + x2 = args[0]; + y2 = args[1]; + } + + cx = 2 * x1 - *cpx2; + cy = 2 * y1 - *cpy2; + + // Convert to cubix bezier + cx1 = x1 + 2.0f / 3.0f * (cx - x1); + cy1 = y1 + 2.0f / 3.0f * (cy - y1); + cx2 = x2 + 2.0f / 3.0f * (cx - x2); + cy2 = y2 + 2.0f / 3.0f * (cy - y2); + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static float nsvg__sqr(float x) { return x * x; } +static float nsvg__vmag(float x, float y) { return sqrtf(x * x + y * y); } + +static float nsvg__vecrat(float ux, float uy, float vx, float vy) { + return (ux * vx + uy * vy) / (nsvg__vmag(ux, uy) * nsvg__vmag(vx, vy)); +} + +static float nsvg__vecang(float ux, float uy, float vx, float vy) { + float r = nsvg__vecrat(ux, uy, vx, vy); + if (r < -1.0f) + r = -1.0f; + if (r > 1.0f) + r = 1.0f; + return ((ux * vy < uy * vx) ? -1.0f : 1.0f) * acosf(r); +} + +static void nsvg__pathArcTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + // Ported from canvg (https://code.google.com/p/canvg/) + float rx, ry, rotx; + float x1, y1, x2, y2, cx, cy, dx, dy, d; + float x1p, y1p, cxp, cyp, s, sa, sb; + float ux, uy, vx, vy, a1, da; + float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; + float sinrx, cosrx; + int fa, fs; + int i, ndivs; + float hda, kappa; + + rx = fabsf(args[0]); // y radius + ry = fabsf(args[1]); // x radius + rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle + fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc + fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction + x1 = *cpx; // start point + y1 = *cpy; + if (rel) { // end point + x2 = *cpx + args[5]; + y2 = *cpy + args[6]; + } else { + x2 = args[5]; + y2 = args[6]; + } + + dx = x1 - x2; + dy = y1 - y2; + d = sqrtf(dx * dx + dy * dy); + if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { + // The arc degenerates to a line + nsvg__lineTo(p, x2, y2); + *cpx = x2; + *cpy = y2; + return; + } + + sinrx = sinf(rotx); + cosrx = cosf(rotx); + + // Convert to center point parameterization. + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + // 1) Compute x1', y1' + x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; + y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; + d = nsvg__sqr(x1p) / nsvg__sqr(rx) + nsvg__sqr(y1p) / nsvg__sqr(ry); + if (d > 1) { + d = sqrtf(d); + rx *= d; + ry *= d; + } + // 2) Compute cx', cy' + s = 0.0f; + sa = nsvg__sqr(rx) * nsvg__sqr(ry) - nsvg__sqr(rx) * nsvg__sqr(y1p) - nsvg__sqr(ry) * nsvg__sqr(x1p); + sb = nsvg__sqr(rx) * nsvg__sqr(y1p) + nsvg__sqr(ry) * nsvg__sqr(x1p); + if (sa < 0.0f) + sa = 0.0f; + if (sb > 0.0f) + s = sqrtf(sa / sb); + if (fa == fs) + s = -s; + cxp = s * rx * y1p / ry; + cyp = s * -ry * x1p / rx; + + // 3) Compute cx,cy from cx',cy' + cx = (x1 + x2) / 2.0f + cosrx * cxp - sinrx * cyp; + cy = (y1 + y2) / 2.0f + sinrx * cxp + cosrx * cyp; + + // 4) Calculate theta1, and delta theta. + ux = (x1p - cxp) / rx; + uy = (y1p - cyp) / ry; + vx = (-x1p - cxp) / rx; + vy = (-y1p - cyp) / ry; + a1 = nsvg__vecang(1.0f, 0.0f, ux, uy); // Initial angle + da = nsvg__vecang(ux, uy, vx, vy); // Delta angle + + // if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; + // if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; + + if (fs == 0 && da > 0) + da -= 2 * NSVG_PI; + else if (fs == 1 && da < 0) + da += 2 * NSVG_PI; + + // Approximate the arc using cubic spline segments. + t[0] = cosrx; + t[1] = sinrx; + t[2] = -sinrx; + t[3] = cosrx; + t[4] = cx; + t[5] = cy; + + // Split arc into max 90 degree segments. + // The loop assumes an iteration per end point (including start and end), this +1. + ndivs = (int)(fabsf(da) / (NSVG_PI * 0.5f) + 1.0f); + hda = (da / (float)ndivs) / 2.0f; + kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); + if (da < 0.0f) + kappa = -kappa; + + for (i = 0; i <= ndivs; i++) { + a = a1 + da * ((float)i / (float)ndivs); + dx = cosf(a); + dy = sinf(a); + nsvg__xformPoint(&x, &y, dx * rx, dy * ry, t); // position + nsvg__xformVec(&tanx, &tany, -dy * rx * kappa, dx * ry * kappa, t); // tangent + if (i > 0) + nsvg__cubicBezTo(p, px + ptanx, py + ptany, x - tanx, y - tany, x, y); + px = x; + py = y; + ptanx = tanx; + ptany = tany; + } + + *cpx = x2; + *cpy = y2; +} + +static void nsvg__parsePath(NSVGparser *p, const char **attr) { + const char *s = NULL; + char cmd = '\0'; + float args[10]; + int nargs; + int rargs = 0; + float cpx, cpy, cpx2, cpy2; + const char *tmp[4]; + char closedFlag; + int i; + char item[64]; + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "d") == 0) { + s = attr[i + 1]; + } else { + tmp[0] = attr[i]; + tmp[1] = attr[i + 1]; + tmp[2] = 0; + tmp[3] = 0; + nsvg__parseAttribs(p, tmp); + } + } + + if (s) { + nsvg__resetPath(p); + cpx = 0; + cpy = 0; + cpx2 = 0; + cpy2 = 0; + closedFlag = 0; + nargs = 0; + + while (*s) { + s = nsvg__getNextPathItem(s, item); + if (!*item) + break; + if (nsvg__isnum(item[0])) { + if (nargs < 10) + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= rargs) { + switch (cmd) { + case 'm': + case 'M': + nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); + // Moveto can be followed by multiple coordinate pairs, + // which should be treated as linetos. + cmd = (cmd == 'm') ? 'l' : 'L'; + rargs = nsvg__getArgsPerElement(cmd); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'l': + case 'L': + nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'H': + case 'h': + nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'V': + case 'v': + nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'C': + case 'c': + nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); + break; + case 'S': + case 's': + nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); + break; + case 'Q': + case 'q': + nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); + break; + case 'T': + case 't': + nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); + break; + case 'A': + case 'a': + nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + default: + if (nargs >= 2) { + cpx = args[nargs - 2]; + cpy = args[nargs - 1]; + cpx2 = cpx; + cpy2 = cpy; + } + break; + } + nargs = 0; + } + } else { + cmd = item[0]; + rargs = nsvg__getArgsPerElement(cmd); + if (cmd == 'M' || cmd == 'm') { + // Commit path. + if (p->npts > 0) + nsvg__addPath(p, closedFlag); + // Start new subpath. + nsvg__resetPath(p); + closedFlag = 0; + nargs = 0; + } else if (cmd == 'Z' || cmd == 'z') { + closedFlag = 1; + // Commit path. + if (p->npts > 0) { + // Move current point to first point + cpx = p->pts[0]; + cpy = p->pts[1]; + cpx2 = cpx; + cpy2 = cpy; + nsvg__addPath(p, closedFlag); + } + // Start new subpath. + nsvg__resetPath(p); + nsvg__moveTo(p, cpx, cpy); + closedFlag = 0; + nargs = 0; + } + } + } + // Commit path. + if (p->npts) + nsvg__addPath(p, closedFlag); + } + + nsvg__addShape(p); +} + +static void nsvg__parseRect(NSVGparser *p, const char **attr) { + float x = 0.0f; + float y = 0.0f; + float w = 0.0f; + float h = 0.0f; + float rx = -1.0f; // marks not set + float ry = -1.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x") == 0) + x = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y") == 0) + y = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "width") == 0) + w = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p)); + if (strcmp(attr[i], "height") == 0) + h = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) + rx = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) + ry = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx < 0.0f && ry > 0.0f) + rx = ry; + if (ry < 0.0f && rx > 0.0f) + ry = rx; + if (rx < 0.0f) + rx = 0.0f; + if (ry < 0.0f) + ry = 0.0f; + if (rx > w / 2.0f) + rx = w / 2.0f; + if (ry > h / 2.0f) + ry = h / 2.0f; + + if (w != 0.0f && h != 0.0f) { + nsvg__resetPath(p); + + if (rx < 0.00001f || ry < 0.0001f) { + nsvg__moveTo(p, x, y); + nsvg__lineTo(p, x + w, y); + nsvg__lineTo(p, x + w, y + h); + nsvg__lineTo(p, x, y + h); + } else { + // Rounded rectangle + nsvg__moveTo(p, x + rx, y); + nsvg__lineTo(p, x + w - rx, y); + nsvg__cubicBezTo(p, x + w - rx * (1 - NSVG_KAPPA90), y, x + w, y + ry * (1 - NSVG_KAPPA90), x + w, y + ry); + nsvg__lineTo(p, x + w, y + h - ry); + nsvg__cubicBezTo(p, x + w, y + h - ry * (1 - NSVG_KAPPA90), x + w - rx * (1 - NSVG_KAPPA90), y + h, + x + w - rx, y + h); + nsvg__lineTo(p, x + rx, y + h); + nsvg__cubicBezTo(p, x + rx * (1 - NSVG_KAPPA90), y + h, x, y + h - ry * (1 - NSVG_KAPPA90), x, y + h - ry); + nsvg__lineTo(p, x, y + ry); + nsvg__cubicBezTo(p, x, y + ry * (1 - NSVG_KAPPA90), x + rx * (1 - NSVG_KAPPA90), y, x + rx, y); + } + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseCircle(NSVGparser *p, const char **attr) { + float cx = 0.0f; + float cy = 0.0f; + float r = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) + cx = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) + cy = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "r") == 0) + r = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualLength(p))); + } + } + + if (r > 0.0f) { + nsvg__resetPath(p); + + nsvg__moveTo(p, cx + r, cy); + nsvg__cubicBezTo(p, cx + r, cy + r * NSVG_KAPPA90, cx + r * NSVG_KAPPA90, cy + r, cx, cy + r); + nsvg__cubicBezTo(p, cx - r * NSVG_KAPPA90, cy + r, cx - r, cy + r * NSVG_KAPPA90, cx - r, cy); + nsvg__cubicBezTo(p, cx - r, cy - r * NSVG_KAPPA90, cx - r * NSVG_KAPPA90, cy - r, cx, cy - r); + nsvg__cubicBezTo(p, cx + r * NSVG_KAPPA90, cy - r, cx + r, cy - r * NSVG_KAPPA90, cx + r, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseEllipse(NSVGparser *p, const char **attr) { + float cx = 0.0f; + float cy = 0.0f; + float rx = 0.0f; + float ry = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) + cx = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) + cy = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) + rx = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) + ry = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx > 0.0f && ry > 0.0f) { + + nsvg__resetPath(p); + + nsvg__moveTo(p, cx + rx, cy); + nsvg__cubicBezTo(p, cx + rx, cy + ry * NSVG_KAPPA90, cx + rx * NSVG_KAPPA90, cy + ry, cx, cy + ry); + nsvg__cubicBezTo(p, cx - rx * NSVG_KAPPA90, cy + ry, cx - rx, cy + ry * NSVG_KAPPA90, cx - rx, cy); + nsvg__cubicBezTo(p, cx - rx, cy - ry * NSVG_KAPPA90, cx - rx * NSVG_KAPPA90, cy - ry, cx, cy - ry); + nsvg__cubicBezTo(p, cx + rx * NSVG_KAPPA90, cy - ry, cx + rx, cy - ry * NSVG_KAPPA90, cx + rx, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseLine(NSVGparser *p, const char **attr) { + float x1 = 0.0; + float y1 = 0.0; + float x2 = 0.0; + float y2 = 0.0; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x1") == 0) + x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y1") == 0) + y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "x2") == 0) + x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y2") == 0) + y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + } + } + + nsvg__resetPath(p); + + nsvg__moveTo(p, x1, y1); + nsvg__lineTo(p, x2, y2); + + nsvg__addPath(p, 0); + + nsvg__addShape(p); +} + +static void nsvg__parsePoly(NSVGparser *p, const char **attr, int closeFlag) { + int i; + const char *s; + float args[2]; + int nargs, npts = 0; + char item[64]; + + nsvg__resetPath(p); + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "points") == 0) { + s = attr[i + 1]; + nargs = 0; + while (*s) { + s = nsvg__getNextPathItem(s, item); + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= 2) { + if (npts == 0) + nsvg__moveTo(p, args[0], args[1]); + else + nsvg__lineTo(p, args[0], args[1]); + nargs = 0; + npts++; + } + } + } + } + } + + nsvg__addPath(p, (char)closeFlag); + + nsvg__addShape(p); +} + +static void nsvg__parseSVG(NSVGparser *p, const char **attr) { + int i; + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "width") == 0) { + p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "height") == 0) { + p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "viewBox") == 0) { + sscanf(attr[i + 1], "%f%*[%%, \t]%f%*[%%, \t]%f%*[%%, \t]%f", &p->viewMinx, &p->viewMiny, &p->viewWidth, + &p->viewHeight); + } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { + if (strstr(attr[i + 1], "none") != 0) { + // No uniform scaling + p->alignType = NSVG_ALIGN_NONE; + } else { + // Parse X align + if (strstr(attr[i + 1], "xMin") != 0) + p->alignX = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "xMid") != 0) + p->alignX = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "xMax") != 0) + p->alignX = NSVG_ALIGN_MAX; + // Parse X align + if (strstr(attr[i + 1], "yMin") != 0) + p->alignY = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "yMid") != 0) + p->alignY = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "yMax") != 0) + p->alignY = NSVG_ALIGN_MAX; + // Parse meet/slice + p->alignType = NSVG_ALIGN_MEET; + if (strstr(attr[i + 1], "slice") != 0) + p->alignType = NSVG_ALIGN_SLICE; + } + } + } + } +} + +static void nsvg__parseGradient(NSVGparser *p, const char **attr, char type) { + int i; + NSVGgradientData *grad = (NSVGgradientData *)malloc(sizeof(NSVGgradientData)); + if (grad == NULL) + return; + memset(grad, 0, sizeof(NSVGgradientData)); + grad->units = NSVG_OBJECT_SPACE; + grad->type = type; + if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { + grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); + grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { + grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + } + + nsvg__xformIdentity(grad->xform); + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "id") == 0) { + strncpy(grad->id, attr[i + 1], 63); + grad->id[63] = '\0'; + } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "gradientUnits") == 0) { + if (strcmp(attr[i + 1], "objectBoundingBox") == 0) + grad->units = NSVG_OBJECT_SPACE; + else + grad->units = NSVG_USER_SPACE; + } else if (strcmp(attr[i], "gradientTransform") == 0) { + nsvg__parseTransform(grad->xform, attr[i + 1]); + } else if (strcmp(attr[i], "cx") == 0) { + grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "cy") == 0) { + grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "r") == 0) { + grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fx") == 0) { + grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fy") == 0) { + grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x1") == 0) { + grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y1") == 0) { + grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x2") == 0) { + grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y2") == 0) { + grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "spreadMethod") == 0) { + if (strcmp(attr[i + 1], "pad") == 0) + grad->spread = NSVG_SPREAD_PAD; + else if (strcmp(attr[i + 1], "reflect") == 0) + grad->spread = NSVG_SPREAD_REFLECT; + else if (strcmp(attr[i + 1], "repeat") == 0) + grad->spread = NSVG_SPREAD_REPEAT; + } else if (strcmp(attr[i], "xlink:href") == 0) { + const char *href = attr[i + 1]; + strncpy(grad->ref, href + 1, 62); + grad->ref[62] = '\0'; + } + } + } + + grad->next = p->gradients; + p->gradients = grad; +} + +static void nsvg__parseGradientStop(NSVGparser *p, const char **attr) { + NSVGattrib *curAttr = nsvg__getAttr(p); + NSVGgradientData *grad; + NSVGgradientStop *stop; + int i, idx; + + curAttr->stopOffset = 0; + curAttr->stopColor = 0; + curAttr->stopOpacity = 1.0f; + + for (i = 0; attr[i]; i += 2) { + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } + + // Add stop to the last gradient. + grad = p->gradients; + if (grad == NULL) + return; + + grad->nstops++; + grad->stops = (NSVGgradientStop *)realloc(grad->stops, sizeof(NSVGgradientStop) * grad->nstops); + if (grad->stops == NULL) + return; + + // Insert + idx = grad->nstops - 1; + for (i = 0; i < grad->nstops - 1; i++) { + if (curAttr->stopOffset < grad->stops[i].offset) { + idx = i; + break; + } + } + if (idx != grad->nstops - 1) { + for (i = grad->nstops - 1; i > idx; i--) + grad->stops[i] = grad->stops[i - 1]; + } + + stop = &grad->stops[idx]; + stop->color = curAttr->stopColor; + stop->color |= (unsigned int)(curAttr->stopOpacity * 255) << 24; + stop->offset = curAttr->stopOffset; +} + +static void nsvg__startElement(void *ud, const char *el, const char **attr) { + NSVGparser *p = (NSVGparser *)ud; + + if (p->defsFlag) { + // Skip everything but gradients in defs + if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } + return; + } + + if (strcmp(el, "g") == 0) { + nsvg__pushAttr(p); + nsvg__parseAttribs(p, attr); + } else if (strcmp(el, "path") == 0) { + if (p->pathFlag) // Do not allow nested paths. + return; + nsvg__pushAttr(p); + nsvg__parsePath(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "rect") == 0) { + nsvg__pushAttr(p); + nsvg__parseRect(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "circle") == 0) { + nsvg__pushAttr(p); + nsvg__parseCircle(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "ellipse") == 0) { + nsvg__pushAttr(p); + nsvg__parseEllipse(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "line") == 0) { + nsvg__pushAttr(p); + nsvg__parseLine(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "polyline") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 0); + nsvg__popAttr(p); + } else if (strcmp(el, "polygon") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 1); + nsvg__popAttr(p); + } else if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 1; + } else if (strcmp(el, "svg") == 0) { + nsvg__parseSVG(p, attr); + } +} + +static void nsvg__endElement(void *ud, const char *el) { + NSVGparser *p = (NSVGparser *)ud; + + if (strcmp(el, "g") == 0) { + nsvg__popAttr(p); + } else if (strcmp(el, "path") == 0) { + p->pathFlag = 0; + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 0; + } +} + +static void nsvg__content(void *ud, const char *s) { + NSVG_NOTUSED(ud); + NSVG_NOTUSED(s); + // empty +} + +static void nsvg__imageBounds(NSVGparser *p, float *bounds) { + NSVGshape *shape; + shape = p->image->shapes; + if (shape == NULL) { + bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; + return; + } + bounds[0] = shape->bounds[0]; + bounds[1] = shape->bounds[1]; + bounds[2] = shape->bounds[2]; + bounds[3] = shape->bounds[3]; + for (shape = shape->next; shape != NULL; shape = shape->next) { + bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); + bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); + bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); + bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); + } +} + +static float nsvg__viewAlign(float content, float container, int type) { + if (type == NSVG_ALIGN_MIN) + return 0; + else if (type == NSVG_ALIGN_MAX) + return container - content; + // mid + return (container - content) * 0.5f; +} + +static void nsvg__scaleGradient(NSVGgradient *grad, float tx, float ty, float sx, float sy) { + float t[6]; + nsvg__xformSetTranslation(t, tx, ty); + nsvg__xformMultiply(grad->xform, t); + + nsvg__xformSetScale(t, sx, sy); + nsvg__xformMultiply(grad->xform, t); +} + +static void nsvg__scaleToViewbox(NSVGparser *p, const char *units) { + NSVGshape *shape; + NSVGpath *path; + float tx, ty, sx, sy, us, bounds[4], t[6], avgs; + int i; + float *pt; + + // Guess image size if not set completely. + nsvg__imageBounds(p, bounds); + + if (p->viewWidth == 0) { + if (p->image->width > 0) { + p->viewWidth = p->image->width; + } else { + p->viewMinx = bounds[0]; + p->viewWidth = bounds[2] - bounds[0]; + } + } + if (p->viewHeight == 0) { + if (p->image->height > 0) { + p->viewHeight = p->image->height; + } else { + p->viewMiny = bounds[1]; + p->viewHeight = bounds[3] - bounds[1]; + } + } + if (p->image->width == 0) + p->image->width = p->viewWidth; + if (p->image->height == 0) + p->image->height = p->viewHeight; + + tx = -p->viewMinx; + ty = -p->viewMiny; + sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; + sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; + // Unit scaling + us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); + + // Fix aspect ratio + if (p->alignType == NSVG_ALIGN_MEET) { + // fit whole image into viewbox + sx = sy = nsvg__minf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth * sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight * sy, p->image->height, p->alignY) / sy; + } else if (p->alignType == NSVG_ALIGN_SLICE) { + // fill whole viewbox with image + sx = sy = nsvg__maxf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth * sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight * sy, p->image->height, p->alignY) / sy; + } + + // Transform + sx *= us; + sy *= us; + avgs = (sx + sy) / 2.0f; + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + shape->bounds[0] = (shape->bounds[0] + tx) * sx; + shape->bounds[1] = (shape->bounds[1] + ty) * sy; + shape->bounds[2] = (shape->bounds[2] + tx) * sx; + shape->bounds[3] = (shape->bounds[3] + ty) * sy; + for (path = shape->paths; path != NULL; path = path->next) { + path->bounds[0] = (path->bounds[0] + tx) * sx; + path->bounds[1] = (path->bounds[1] + ty) * sy; + path->bounds[2] = (path->bounds[2] + tx) * sx; + path->bounds[3] = (path->bounds[3] + ty) * sy; + for (i = 0; i < path->npts; i++) { + pt = &path->pts[i * 2]; + pt[0] = (pt[0] + tx) * sx; + pt[1] = (pt[1] + ty) * sy; + } + } + + if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->fill.gradient, tx, ty, sx, sy); + memcpy(t, shape->fill.gradient->xform, sizeof(float) * 6); + nsvg__xformInverse(shape->fill.gradient->xform, t); + } + if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->stroke.gradient, tx, ty, sx, sy); + memcpy(t, shape->stroke.gradient->xform, sizeof(float) * 6); + nsvg__xformInverse(shape->stroke.gradient->xform, t); + } + + shape->strokeWidth *= avgs; + shape->strokeDashOffset *= avgs; + for (i = 0; i < shape->strokeDashCount; i++) + shape->strokeDashArray[i] *= avgs; + } +} + +NSVGimage *nsvgParse(char *input, const char *units, float dpi) { + NSVGparser *p; + NSVGimage *ret = 0; + + p = nsvg__createParser(); + if (p == NULL) { + return NULL; + } + p->dpi = dpi; + + nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); + + // Scale to viewBox + nsvg__scaleToViewbox(p, units); + + ret = p->image; + p->image = NULL; + + nsvg__deleteParser(p); + + return ret; +} + +NSVGimage *nsvgParseFromFile(const char *filename, const char *units, float dpi) { + FILE *fp = NULL; + size_t size; + char *data = NULL; + NSVGimage *image = NULL; + + fp = fopen(filename, "rb"); + if (!fp) + goto error; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + data = (char *)malloc(size + 1); + if (data == NULL) + goto error; + if (fread(data, 1, size, fp) != size) + goto error; + data[size] = '\0'; // Must be null terminated. + fclose(fp); + image = nsvgParse(data, units, dpi); + free(data); + + return image; error: - if (fp) fclose(fp); - if (data) free(data); - if (image) nsvgDelete(image); - return NULL; -} - -void nsvgDelete(NSVGimage* image) -{ - NSVGshape *snext, *shape; - if (image == NULL) return; - shape = image->shapes; - while (shape != NULL) { - snext = shape->next; - nsvg__deletePaths(shape->paths); - nsvg__deletePaint(&shape->fill); - nsvg__deletePaint(&shape->stroke); - free(shape); - shape = snext; - } - free(image); + if (fp) + fclose(fp); + if (data) + free(data); + if (image) + nsvgDelete(image); + return NULL; +} + +void nsvgDelete(NSVGimage *image) { + NSVGshape *snext, *shape; + if (image == NULL) + return; + shape = image->shapes; + while (shape != NULL) { + snext = shape->next; + nsvg__deletePaths(shape->paths); + nsvg__deletePaint(&shape->fill); + nsvg__deletePaint(&shape->stroke); + free(shape); + shape = snext; + } + free(image); } #endif diff --git a/tests/common/rnd.c b/tests/common/rnd.c index 410a1ed..448bd0e 100644 --- a/tests/common/rnd.c +++ b/tests/common/rnd.c @@ -1,1009 +1,1259 @@ -static int _rnd_count = 9999; -static float _rnd[] = { 0.39540747, -0.841546, 0.52073574, 0.80399257, 0.95868486, 0.46164507, 0.5644759, 0.50258803, 0.1953517, 0.40522006, 0.7953865, -0.7795385, 0.6009604, 0.03921096, 0.56872225, 0.93369347, 0.7019503, 0.5392296, 0.2671585, 0.87286836, 0.28110227, -0.41505373, 0.8609184, 0.65234584, 0.18079561, 0.1345461, 0.26905555, 0.97823226, 0.9349287, 0.37662244, 0.47883937, -0.1831086, 0.63446456, 0.2549137, 0.8205819, 0.44705132, 0.7044422, 0.36040744, 0.29616997, 0.60375917, 0.21973382, -0.094351165, 0.3769042, 0.9975177, 0.6133292, 0.3379986, 0.88620085, 0.83456165, 0.16677794, 0.2749627, 0.28938183, -0.6274365, 0.058304083, 0.97233975, 0.48520145, 0.9803537, 0.9806276, 0.8683899, 0.62319696, 0.82413876, 0.19258952, -0.5862436, 0.5676593, 0.8187293, 0.9263807, 0.6122779, 0.14507395, 0.34604672, 0.21862903, 0.121670924, 0.22925124, -0.34154287, 0.2430596, 0.66339934, 0.6531345, 0.1867511, 0.038149532, 0.8634007, 0.039016694, 0.84279704, 0.24834526, -0.4344939, 0.8114543, 0.65996605, 0.08724063, 0.8514029, 0.12480451, 0.6621248, 0.76971227, 0.8402282, 0.46642372, -0.83605236, 0.73721045, 0.47203118, 0.41116965, 0.6334902, 0.52669185, 0.55817497, 0.07113702, 0.0010512439, 0.19292463, -0.5401541, 0.61593264, 0.045107026, 0.04571145, 0.94783896, 0.3843769, 0.39490476, 0.3192052, 0.29845035, 0.9422042, -0.11722695, 0.8293732, 0.7804, 0.5757935, 0.7580956, 0.7747893, 0.90769327, 0.73148865, 0.074977815, 0.4874734, -0.48294914, 0.5763345, 0.37840083, 0.6552472, 0.39319888, 0.6043324, 0.77102846, 0.25222966, 0.019644327, 0.6600592, -0.4799746, 0.7922636, 0.03796545, 0.64987236, 0.70819116, 0.81856126, 0.7663473, 0.6142546, 0.13940167, 0.46702597, -0.72989976, 0.34291962, 0.47126192, 0.89802396, 0.34919676, 0.0066791615, 0.95681053, 0.8962376, 0.653074, 0.85870093, -0.6189986, 0.8266863, 0.9961592, 0.5135778, 0.7099755, 0.9638197, 0.2375318, 0.3898598, 0.65251255, 0.34350657, -0.6133485, 0.14267509, 0.29956087, 0.6383911, 0.4622296, 0.3249633, 0.79140776, 0.13052759, 0.8676024, 0.93953437, -0.008441999, 0.2934387, 0.592087, 0.6079518, 0.75757366, 0.14002953, 0.10507256, 0.48037684, 0.30605045, 0.38651973, -0.64752185, 0.8747908, 0.59915566, 0.1609434, 0.04106063, 0.65328825, 0.79610443, 0.5243876, 0.9398969, 0.7443715, -0.5810295, 0.3764875, 0.961742, 0.7958951, 0.8536775, 0.58722466, 0.043358732, 0.8328708, 0.43579438, 0.024233455, -0.21527143, 0.8262829, 0.028635254, 0.71353966, 0.85025895, 0.3255599, 0.23459937, 0.38820738, 0.7560042, 0.569946, -0.8587471, 0.75715494, 0.083809346, 0.26599285, 0.6959847, 0.73855764, 0.54351944, 0.13861747, 0.59733045, 0.80894136, -0.52885884, 0.26702014, 0.1906307, 0.123230904, 0.35850486, 0.6319545, 0.3316967, 0.7961919, 0.7542743, 0.17034897, -0.0966708, 0.27220175, 0.04458247, 0.28181702, 0.1712483, 0.82123893, 0.8461555, 0.88561594, 0.3106845, 0.7155007, -0.4186889, 0.40789708, 0.76838344, 0.36995092, 0.8856244, 0.82387453, 0.29267815, 0.69574916, 0.099910386, 0.11511985, -0.04370523, 0.9047413, 0.23554033, 0.62685305, 0.4953746, 0.9482513, 0.63565224, 0.9054043, 0.3550348, 0.21830441, -0.9938632, 0.4384075, 0.633933, 0.5856552, 0.47327515, 0.58654535, 0.71257246, 0.80199236, 0.09474454, 0.8747458, -0.8924021, 0.6579035, 0.82793295, 0.88182974, 0.39025244, 0.12096177, 0.4986367, 0.8206798, 0.23760653, 0.53463036, -0.33927637, 0.6359475, 0.6962815, 0.6391545, 0.12664375, 0.19192953, 0.036661416, 0.41772944, 0.7864424, 0.222997, -0.18558672, 0.9407512, 0.5305812, 0.092380084, 0.7216375, 0.9802814, 0.77396405, 0.18272822, 0.89667577, 0.29907903, -0.11130205, 0.4906858, 0.60100466, 0.22516462, 0.22271773, 0.38580173, 0.07680829, 0.3537106, 0.23660058, 0.37441283, -0.4496146, 0.81497246, 0.6677978, 0.82040447, 0.879028, 0.35791573, 0.742126, 0.9947786, 0.45901147, 0.28134564, -0.54988396, 0.29484302, 0.015549939, 0.87174755, 0.68915904, 0.9516509, 0.12732233, 0.7355529, 0.16019227, 0.40997103, -0.34699774, 0.31590846, 0.924004, 0.93852746, 0.4233283, 0.84859055, 0.034942873, 0.47111684, 0.41643673, 0.740842, -0.115121245, 0.68295085, 0.18112887, 0.41202956, 0.77338237, 0.3706143, 0.27295336, 0.7101767, 0.21335205, 0.36372176, -0.2381554, 0.7791855, 0.72371674, 0.6153301, 0.7491951, 0.816459, 0.47513586, 0.7292571, 0.5360056, 0.2710668, -0.25847942, 0.3412554, 0.19351831, 0.8266295, 0.0274151, 0.13370614, 0.8909684, 0.72927034, 0.39707616, 0.030437447, -0.32297286, 0.27100918, 0.57834184, 0.71816945, 0.16622439, 0.8669331, 0.11371415, 0.6035204, 0.09836516, 0.31854475, -0.6786976, 0.41714564, 0.5222008, 0.7964705, 0.17181565, 0.56781226, 0.5921917, 0.30867395, 0.1893324, 0.6068693, -0.37345472, 0.3056858, 0.9351113, 0.14536993, 0.4823626, 0.7738658, 0.4894325, 0.35449934, 0.38461447, 0.6396763, -0.4796459, 0.54368305, 0.31310055, 0.18291461, 0.040748898, 0.9671462, 0.20084366, 0.0055472897, 0.4491057, 0.882262, -0.7027449, 0.87161547, 0.6308919, 0.21746083, 0.59236926, 0.8413338, 0.81905454, 0.3970478, 0.6548139, 0.45960286, -0.5415144, 0.58229446, 0.539938, 0.7902069, 0.6569827, 0.017287076, 0.33589792, 0.4329719, 0.23580688, 0.39235854, -0.3775006, 0.7592148, 0.2189059, 0.45868888, 0.83889884, 0.13501453, 0.10404509, 0.3392862, 0.7557216, 0.20466943, -0.36696857, 0.5866444, 0.85956824, 0.3070704, 0.9041244, 0.5018392, 0.67479384, 0.7176504, 0.5530007, 0.6410288, -0.9548113, 0.092384726, 0.69968545, 0.92501163, 0.09816185, 0.89735144, 0.0037450776, 0.52289367, 0.5259319, 0.023461822, -0.6312483, 0.7678718, 0.7697404, 0.05674718, 0.5047614, 0.9435301, 0.6527096, 0.17220303, 0.37856197, 0.45735472, -0.7372887, 0.47976837, 0.6413262, 0.45014447, 0.09263428, 0.95487, 0.7227262, 0.23286755, 0.8860825, 0.15514348, -0.34249324, 0.61824745, 0.8799712, 0.59477806, 0.43754727, 0.28511587, 0.059529364, 0.2938943, 0.36052704, 0.9415474, -0.13126945, 0.5811514, 0.8133543, 0.7322598, 0.5734211, 0.5990968, 0.816904, 0.80282104, 0.802309, 0.96059436, -0.8491296, 0.50259084, 0.33908847, 0.09564596, 0.9037401, 0.4750429, 0.45105854, 0.24954097, 0.8323773, 0.14329186, -0.17462522, 0.77087754, 0.63681114, 0.3707884, 0.6809686, 0.013000839, 0.8879006, 0.17496233, 0.61919993, 0.21964556, -0.8840007, 0.3588153, 0.81167597, 0.43701455, 0.32608527, 0.15613726, 0.666414, 0.9090664, 0.87672335, 0.4935375, -0.13796596, 0.9199052, 0.43055856, 0.9254882, 0.30601385, 0.8399024, 0.279159, 0.78432524, 0.69103795, 0.9625043, -0.83405733, 0.8099884, 0.46151695, 0.2172352, 0.7669222, 0.3603919, 0.9443403, 0.44256592, 0.0512912, 0.5604203, -0.7111962, 0.64194167, 0.18362112, 0.5826634, 0.07659364, 0.49031433, 0.6909148, 0.9020739, 0.7695607, 0.7476028, -0.80862886, 0.5419922, 0.3728176, 0.33883983, 0.005325912, 0.25472003, 0.34031895, 0.711323, 0.064774565, 0.8410662, -0.73384184, 0.10357534, 0.48392436, 0.65669554, 0.38558826, 0.07401231, 0.8972984, 0.5944408, 0.67009234, 0.96569335, -0.21179698, 0.22384812, 0.8577752, 0.31630307, 0.7823413, 0.49602425, 0.7362841, 0.84789515, 0.84889454, 0.8156995, -0.14898759, 0.3770851, 0.01476456, 0.94343513, 0.15387547, 0.29206514, 0.43717077, 0.12267711, 0.21190928, 0.5122022, -0.020072967, 0.23301727, 0.37779135, 0.21022503, 0.82657844, 0.60762084, 0.15801735, 0.52692556, 0.19707517, 0.0025813282, -0.59301597, 0.09647403, 0.23198159, 0.80386734, 0.5358059, 0.58478075, 0.684217, 0.056514528, 0.5564985, 0.50930166, -0.51843596, 0.4924238, 0.8624285, 0.24907504, 0.6920786, 0.35675675, 0.08881078, 0.5404892, 0.5028201, 0.0935231, -0.63684154, 0.77462125, 0.38253152, 0.15789017, 0.94562036, 0.97877973, 0.84605676, 0.64755017, 0.48972467, 0.17472044, -0.3380069, 0.2093585, 0.65081996, 0.8463132, 0.22268358, 0.052513562, 0.1451035, 0.21089722, 0.40762928, 0.5690947, -0.60784817, 0.38065624, 0.56617856, 0.70260763, 0.99376625, 0.52764916, 0.37058878, 0.1287163, 0.51814646, 0.4698217, -0.5188101, 0.61752814, 0.024105478, 0.103552066, 0.3657398, 0.81839466, 0.7139425, 0.07409142, 0.858247, 0.55702615, -0.738724, 0.03666682, 0.56678987, 0.38177812, 0.17129473, 0.30907747, 0.8416038, 0.016115308, 0.02639147, 0.639565, -0.21165326, 0.87791353, 0.13285992, 0.9337254, 0.48567492, 0.2561853, 0.20844269, 0.6799239, 0.16412394, 0.41797122, -0.60819095, 0.71734047, 0.12940371, 0.019902974, 0.6559104, 0.7204788, 0.18525302, 0.5472679, 0.4805734, 0.4042889, -0.33857107, 0.07101207, 0.35265025, 0.85060316, 0.8303707, 0.57118136, 0.8138664, 0.18440045, 0.5313129, 0.68468875, -0.68604535, 0.35447347, 0.10232483, 0.8785814, 0.25816843, 0.6408965, 0.48466823, 0.09038009, 0.6178771, 0.10955451, -0.609952, 0.034018606, 0.9099675, 0.44027576, 0.9488352, 0.021383535, 0.9072631, 0.5468869, 0.72586775, 0.45081598, -0.12382444, 0.29433593, 0.5355419, 0.62210256, 0.30099395, 0.14064118, 0.5252633, 0.28225678, 0.10335469, 0.91449356, -0.44231892, 0.024042243, 0.14861101, 0.47943518, 0.7319259, 0.2537175, 0.6150156, 0.25082228, 0.76173455, 0.01501382, -0.23581055, 0.09487294, 0.9293908, 0.3710189, 0.7943369, 0.30455244, 0.1610446, 0.9123745, 0.90176797, 0.80898714, -0.66391826, 0.2669795, 0.4585327, 0.08049692, 0.5608643, 0.3917094, 0.8189315, 0.48022225, 0.5775875, 0.11752723, -0.11563321, 0.20241146, 0.9870254, 0.70338356, 0.6672356, 0.5859097, 0.88540757, 0.4305323, 0.7083498, 0.69511765, -0.4063679, 0.6564408, 0.7851523, 0.71085393, 0.21500541, 0.028951503, 0.36494514, 0.16452302, 0.8277657, 0.9964415, -0.9795966, 0.6128888, 0.38048878, 0.29436752, 0.25057533, 0.17533945, 0.56550956, 0.06811409, 0.9185709, 0.3402165, -0.43478596, 0.13479339, 0.6732348, 0.64420736, 0.8993806, 0.033399098, 0.10784754, 0.22600721, 0.7037833, 0.20842715, -0.41914487, 0.7305123, 0.20402466, 0.2066503, 0.40261927, 0.007477421, 0.48182714, 0.74767876, 0.8654915, 0.5319128, -0.026764244, 0.6544085, 0.6524566, 0.58114594, 0.13793063, 0.50274444, 0.82192266, 0.6926579, 0.45280823, 0.49189615, -0.020400187, 0.8172935, 0.51196146, 0.36813334, 0.26033172, 0.27157453, 0.983206, 0.140945, 0.81147337, 0.18160632, -0.92110395, 0.13893794, 0.46073973, 0.6193385, 0.5772967, 0.2490843, 0.40886414, 0.1738385, 0.89174825, 0.24309792, -0.6935123, 0.8178308, 0.20262258, 0.38665804, 0.31345224, 0.78037745, 0.48233682, 0.09208888, 0.50627667, 0.3966362, -0.21147643, 0.41518968, 0.77319896, 0.21188715, 0.18802696, 0.60185134, 0.21855086, 0.8358913, 0.94631857, 0.13104475, -0.024271427, 0.34088212, 0.9362054, 0.6838852, 0.61080885, 0.8878263, 0.1936688, 0.03311803, 0.0038492912, 0.88884634, -0.09388026, 0.64808416, 0.8009096, 0.2097103, 0.79838383, 0.20256937, 0.61467093, 0.1253034, 0.054681093, 0.47995427, -0.7892377, 0.8911171, 0.6346683, 0.41483715, 0.9701299, 0.5059143, 0.36573896, 0.24885257, 0.43131158, 0.97544533, -0.03053343, 0.57297283, 0.2275199, 0.7607035, 0.21882649, 0.3526302, 0.8816254, 0.5187374, 0.77584916, 0.42562595, -0.58670866, 0.44921878, 0.08823959, 0.6174303, 0.30275592, 0.5633923, 0.61428005, 0.56348866, 0.41350332, 0.9854576, -0.9871804, 0.093247466, 0.7812102, 0.4663643, 0.34180707, 0.13315432, 0.70621383, 0.52136827, 0.7137553, 0.10489457, -0.52208734, 0.94481623, 0.60180646, 0.028403986, 0.8583129, 0.5209074, 0.42056426, 0.04020609, 0.9908838, 0.44575363, -0.32094392, 0.09593353, 0.34945422, 0.62905514, 0.89324564, 0.3400189, 0.80287755, 0.017237967, 0.112081215, 0.40673763, -0.8916342, 0.80225027, 0.83534926, 0.44585398, 0.98826486, 0.93728596, 0.79176265, 0.7611556, 0.41889647, 0.08567218, -0.64641637, 0.3602572, 0.80498207, 0.6709546, 0.9035386, 0.64189243, 0.84741235, 0.0598356, 0.7591174, 0.7818485, -0.142828, 0.574074, 0.5726049, 0.96774966, 0.6645137, 0.8912469, 0.74379325, 0.15215507, 0.5731187, 0.0017881524, -0.3302768, 0.6889758, 0.40928704, 0.30701768, 0.21326037, 0.71983707, 0.10946698, 0.1559525, 0.040139113, 0.92102695, -0.7291448, 0.6594087, 0.62130964, 0.9052116, 0.79933727, 0.9606867, 0.29095143, 0.6784996, 0.72551656, 0.2513532, -0.49260658, 0.74304193, 0.25812054, 0.33023268, 0.2639096, 0.31756023, 0.22964539, 0.86759955, 0.7813403, 0.097017966, -0.19349271, 0.63960755, 0.18803692, 0.4171083, 0.7553954, 0.95744056, 0.9509702, 0.4979644, 0.45769426, 0.18370152, -0.53242546, 0.69145983, 0.019696489, 0.8380905, 0.052703734, 0.48341933, 0.95276433, 0.6673932, 0.16841243, 0.70382696, -0.6002955, 0.06529366, 0.42663854, 0.32176548, 0.50918156, 0.58723485, 0.4308553, 0.079054326, 0.04310807, 0.89570016, -0.4901917, 0.24186741, 0.3746122, 0.94312114, 0.72753423, 0.08953723, 0.47137174, 0.20420133, 0.14981624, 0.8418967, -0.009716521, 0.79298705, 0.22080535, 0.541815, 0.71892774, 0.80114675, 0.72334546, 0.42003006, 0.27752897, 0.7804903, -0.36479586, 0.56225216, 0.69918716, 0.07751329, 0.4967225, 0.12819904, 0.212969, 0.86627144, 0.90792674, 0.16816054, -0.5265852, 0.8719159, 0.45485634, 0.56199414, 0.6935098, 0.29055804, 0.31684762, 0.07657534, 0.11055623, 0.9631665, -0.012047576, 0.74856305, 0.517577, 0.32651573, 0.69411045, 0.80730844, 0.8444883, 0.88482356, 0.60283774, 0.7080349, -0.8638894, 0.010825248, 0.80152535, 0.26261777, 0.53090423, 0.92793953, 0.54268026, 0.29709893, 0.44639865, 0.5993352, -0.8765682, 0.6051003, 0.2962746, 0.9816557, 0.31531146, 0.13780066, 0.3381307, 0.6588112, 0.84830517, 0.4283697, -0.48429912, 0.6467701, 0.30947384, 0.31436247, 0.7684427, 0.6162329, 0.044675153, 0.3726714, 0.38340282, 0.689414, -0.28371072, 0.32814547, 0.26343372, 0.19989188, 0.30427113, 0.51576, 0.07039049, 0.19223855, 0.031089857, 0.7655703, -0.7478778, 0.019748688, 0.63017666, 0.511221, 0.08659828, 0.40694728, 0.45228842, 0.53592134, 0.011204251, 0.5563098, -0.46917772, 0.18567711, 0.036518365, 0.17446801, 0.22373573, 0.21711932, 0.7013514, 0.48716292, 0.49417505, 0.9146714, -0.88326436, 0.17000887, 0.9136961, 0.7569846, 0.3156245, 0.54842275, 0.34166658, 0.09638273, 0.67738456, 0.7995515, -0.06741016, 0.14589214, 0.62772137, 0.08273488, 0.680492, 0.46455044, 0.016593413, 0.7982528, 0.22776419, 0.36149544, -0.16394442, 0.50875384, 0.36146715, 0.827093, 0.22023632, 0.098033614, 0.2916271, 0.088965714, 0.9761561, 0.08715181, -0.8144086, 0.5832276, 0.6980635, 0.11641844, 0.8823059, 0.5778689, 0.106052585, 0.8731921, 0.19559653, 0.5381755, -0.06528069, 0.3559057, 0.8585367, 0.21165277, 0.48889965, 0.32328558, 0.55795574, 0.95378345, 0.49397606, 0.7591853, -0.20052591, 0.9030986, 0.25939873, 0.13267961, 0.750727, 0.37451053, 0.8085417, 0.086603075, 0.5367483, 0.21759088, -0.25679567, 0.25270087, 0.120226584, 0.59023273, 0.9851429, 0.48418257, 0.44782865, 0.51130295, 0.20042898, 0.102623075, -0.35849786, 0.14340132, 0.6026563, 0.68958867, 0.29621476, 0.8080387, 0.6502171, 0.14981438, 0.3381934, 0.8969507, -0.54007787, 0.33784363, 0.59498966, 0.21697083, 0.8866259, 0.91130996, 0.32382888, 0.5653839, 0.36569145, 0.5077954, -0.76932716, 0.01944951, 0.3364438, 0.97800565, 0.28137985, 0.8125798, 0.2356791, 0.268304, 0.22650987, 0.00471706, -0.8754569, 0.04665282, 0.7533545, 0.39135298, 0.40068746, 0.05712457, 0.3004423, 0.56981003, 0.8364648, 0.9426883, -0.7242934, 0.65872735, 0.7484097, 0.63979757, 0.677513, 0.91895205, 0.6577112, 0.90325576, 0.70360684, 0.07383294, -0.1603537, 0.88244474, 0.14561148, 0.6926336, 0.3332959, 0.33904833, 0.80695754, 0.62465066, 0.40820882, 0.48363495, -0.5723596, 0.38191313, 0.9233045, 0.33347633, 0.021493766, 0.49342504, 0.5844891, 0.20363668, 0.81628335, 0.82950133, -0.6108677, 0.75401884, 0.728919, 0.42300317, 0.7835019, 0.11059984, 0.2710398, 0.6966462, 0.30049264, 0.3624278, -0.1548686, 0.33242336, 0.56469715, 0.15267694, 0.84436333, 0.9930122, 0.9010413, 0.06072089, 0.058057077, 0.061639126, -0.25016704, 0.6757917, 0.16160122, 0.3528299, 0.37032866, 0.34238032, 0.7354228, 0.41493335, 0.6183038, 0.18408795, -0.3344629, 0.45407453, 0.08697238, 0.8741055, 0.46296528, 0.40633488, 0.1535257, 0.7226083, 0.90913165, 0.22269607, -0.068008505, 0.1103113, 0.32415798, 0.045781024, 0.32876635, 0.23993625, 0.817216, 0.77062756, 0.48911297, 0.028481547, -0.5923837, 0.52376825, 0.14557959, 0.7546443, 0.5793343, 0.935076, 0.5924176, 0.37608913, 0.05267449, 0.44112164, -0.37517703, 0.85610646, 0.078342445, 0.11640469, 0.02796489, 0.70079404, 0.24545097, 0.69059163, 0.68971163, 0.43802848, -0.83948654, 0.17843302, 0.15158923, 0.835361, 0.99363065, 0.13985574, 0.3516337, 0.115820184, 0.02406358, 0.13039242, -0.5251643, 0.96479523, 0.92582035, 0.58982223, 0.59170425, 0.8106947, 0.30849496, 0.33232814, 0.2947712, 0.5278893, -0.8139172, 0.77743655, 0.6699338, 0.46801004, 0.84751904, 0.21190204, 0.031968854, 0.2077533, 0.017816134, 0.62797225, -0.99448526, 0.12662433, 0.080915935, 0.05108449, 0.18899502, 0.41395068, 0.372179, 0.3102186, 0.7610136, 0.43947858, -0.5834423, 0.47659743, 0.35202554, 0.9222821, 0.9159573, 0.4103818, 0.9302861, 0.4885202, 0.52470046, 0.21727021, -0.39229912, 0.91312283, 0.39582044, 0.16182233, 0.62411124, 0.062049974, 0.5084992, 0.6835792, 0.98784196, 0.78172857, -0.10788689, 0.1438804, 0.09800406, 0.3960913, 0.13590716, 0.39854, 0.8838793, 0.8747359, 0.40082723, 0.17775355, -0.43851566, 0.99827635, 0.5713145, 0.8552926, 0.94444704, 0.33731982, 0.42541102, 0.74765176, 0.55205274, 0.43713725, -0.28161594, 0.5434486, 0.68305284, 0.80054593, 0.23567316, 0.08136242, 0.7308039, 0.9190936, 0.42697325, 0.12694505, -0.9054515, 0.6885998, 0.32237664, 0.97928506, 0.33159167, 0.43956187, 0.3785934, 0.9559342, 0.7863749, 0.5174173, -0.5265025, 0.05555021, 0.08769297, 0.3469469, 0.77875453, 0.39402276, 0.34180835, 0.5405278, 0.21737531, 0.2867914, -0.636639, 0.76084745, 0.13152646, 0.5507047, 0.50011265, 0.5644382, 0.46082756, 0.29745814, 0.16041815, 0.054544732, -0.6677361, 0.9647857, 0.44776264, 0.27388218, 0.27230206, 0.74991584, 0.67589974, 0.59202945, 0.52370095, 0.50488514, -0.9587264, 0.46947676, 0.9612768, 0.034635436, 0.91063476, 0.22606573, 0.45575568, 0.33610594, 0.02179139, 0.8416504, -0.7395541, 0.19027609, 0.7017183, 0.14018182, 0.49030608, 0.14460404, 0.55707335, 0.7716719, 0.47917238, 0.76715344, -0.9787343, 0.08113525, 0.7955161, 0.7318302, 0.8496812, 0.5617168, 0.60778755, 0.81381077, 0.07464484, 0.028838681, -0.718123, 0.74977887, 0.016826851, 0.71249014, 0.32806498, 0.16716221, 0.7995706, 0.096891016, 0.64007, 0.27404693, -0.10868255, 0.12472161, 0.27566674, 0.31876773, 0.31499064, 0.47746003, 0.2630674, 0.30758083, 0.78357613, 0.12769802, -0.1928425, 0.90422785, 0.112857096, 0.7565475, 0.5261508, 0.8775912, 0.6739607, 0.22944665, 0.18495426, 0.3489179, -0.61827815, 0.6419449, 0.2614611, 0.9929527, 0.12352738, 0.98977524, 0.17344923, 0.9892281, 0.81211686, 0.32314387, -0.34503344, 0.46018234, 0.13160191, 0.20512545, 0.65847087, 0.8540127, 0.8054685, 0.47674835, 0.41683954, 0.37222117, -0.29864943, 0.30020675, 0.03023468, 0.94694686, 0.8359962, 0.8138952, 0.63692176, 0.26027933, 0.18633933, 0.45047382, -0.49320155, 0.570124, 0.91193676, 0.2911521, 0.65576875, 0.46673766, 0.8632605, 0.28271404, 0.19524036, 0.32521543, -0.30401078, 0.27383924, 0.495464, 0.46043226, 0.7826646, 0.7326602, 0.7726259, 0.90773165, 0.09807661, 0.6721381, -0.07212267, 0.1972123, 0.8126071, 0.8127331, 0.05026847, 0.3180714, 0.6117102, 0.31451428, 0.15695652, 0.30963218, -0.35285345, 0.9131699, 0.8028888, 0.36164302, 0.8299423, 0.7749095, 0.54824555, 0.8404498, 0.5493567, 0.19173324, -0.9907522, 0.5227545, 0.281508, 0.091624096, 0.06821037, 0.024810186, 0.80474275, 0.5698024, 0.16428226, 0.10333604, -0.04126928, 0.7291901, 0.16220273, 0.5142012, 0.37835112, 0.29598927, 0.75751686, 0.09920368, 0.24088362, 0.33769736, -0.85502744, 0.5487462, 0.12575752, 0.8856082, 0.972362, 0.3908409, 0.47095042, 0.13382097, 0.63048995, 0.007755094, -0.18441458, 0.9321761, 0.35837498, 0.9063434, 0.6813859, 0.5493682, 0.9157043, 0.720983, 0.7445227, 0.025458287, -0.5133287, 0.041907787, 0.15023202, 0.053620476, 0.2683629, 0.6236633, 0.75096714, 0.28868756, 0.98329186, 0.5339531, -0.017392641, 0.4490419, 0.5995662, 0.21165931, 0.3367058, 0.44200596, 0.39699697, 0.39589983, 0.11926211, 0.6773695, -0.5538598, 0.6709218, 0.93931246, 0.15652716, 0.9189215, 0.10909318, 0.37081516, 0.25585935, 0.83281535, 0.82898295, -0.38028497, 0.03653382, 0.35468096, 0.21542533, 0.8243687, 0.81311965, 0.39851424, 0.07213704, 0.61724526, 0.34869868, -0.63987374, 0.18226288, 0.15052907, 0.096536905, 0.99036247, 0.73537266, 0.3326099, 0.14671567, 0.5696376, 0.2393799, -0.15237123, 0.5198045, 0.6017209, 0.067153245, 0.47159854, 0.84240687, 0.1025953, 0.99370486, 0.134699, 0.15926972, -0.25284818, 0.4951078, 0.45587218, 0.15430894, 0.15366808, 0.9808588, 0.094360925, 0.38414088, 0.3872906, 0.52358615, -0.043491747, 0.32485992, 0.7786546, 0.7705634, 0.037495736, 0.37159687, 0.5203927, 0.8427756, 0.16616471, 0.18354878, -0.7764833, 0.22409947, 0.6862218, 0.59343547, 0.6766117, 0.8604805, 0.4348129, 0.2875277, 0.7438268, 0.9819619, -0.7105244, 0.4048094, 0.937438, 0.45797554, 0.09585048, 0.14476593, 0.7263907, 0.9962201, 0.9428688, 0.009503636, -0.6410118, 0.94846904, 0.7594251, 0.04605143, 0.19588815, 0.8275113, 0.7411499, 0.83115745, 0.02965751, 0.10000168, -0.32201412, 0.25981972, 0.82754016, 0.95115024, 0.38278645, 0.02874871, 0.808886, 0.8624367, 0.47769725, 0.29318756, -0.5460459, 0.8068332, 0.6403141, 0.4053287, 0.8130618, 0.63868237, 0.3874219, 0.320679, 0.67471296, 0.8927298, -0.64520615, 0.5241726, 0.89990675, 0.15666108, 0.54253703, 0.82801425, 0.46467438, 0.64017034, 0.39754733, 0.8491004, -0.11933059, 0.60365546, 0.25787023, 0.6438251, 0.65994775, 0.45070463, 0.57726926, 0.98628783, 0.075189106, 0.06710178, -0.33587992, 0.863954, 0.51852286, 0.64968127, 0.46345773, 0.83417857, 0.30815494, 0.35409638, 0.23298964, 0.5572058, -0.4400894, 0.4204709, 0.1564445, 0.13692771, 0.4547955, 0.7978415, 0.35991296, 0.67087907, 0.4086132, 0.5547722, -0.56407434, 0.16871567, 0.46488938, 0.62859684, 0.17385697, 0.94239044, 0.548963, 0.996489, 0.74538094, 0.36235714, -0.061413143, 0.40113407, 0.24548991, 0.6076112, 0.5568499, 0.78125215, 0.005649717, 0.2502255, 0.69320333, 0.70835847, -0.5198593, 0.110578, 0.4071807, 0.84034157, 0.40901098, 0.6988597, 0.44721094, 0.12094251, 0.1890296, 0.86210626, -0.09079167, 0.90639013, 0.5776746, 0.5204169, 0.50302744, 0.16716424, 0.39906463, 0.8899261, 0.47582427, 0.52106726, -0.2852156, 0.31166598, 0.6087155, 0.87063247, 0.49579263, 0.03895533, 0.174981, 0.5488333, 0.5800778, 0.67354333, -0.7921918, 0.10968746, 0.97767574, 0.70025474, 0.034912895, 0.45349634, 0.761535, 0.6245478, 0.21958585, 0.47499728, -0.4951795, 0.42802048, 0.80745935, 0.8832747, 0.27156547, 0.15502298, 0.8234595, 0.725073, 0.10458374, 0.38968566, -0.38218752, 0.11572367, 0.77440125, 0.17213607, 0.42314288, 0.2081933, 0.5018625, 0.5365482, 0.3445489, 0.37005565, -0.5238787, 0.8983776, 0.5408647, 0.51548624, 0.06991447, 0.9811042, 0.9287144, 0.8774199, 0.48550403, 0.04953112, -0.40562928, 0.7745168, 0.6703402, 0.00082698837, 0.025887761, 0.8571951, 0.5042066, 0.7254408, 0.59906703, 0.34076965, -0.21549584, 0.449908, 0.44424957, 0.19039217, 0.29135585, 0.67646813, 0.33528623, 0.80553967, 0.27711186, 0.8267196, -0.95163375, 0.22498675, 0.2799989, 0.8495302, 0.9511186, 0.5968019, 0.8871558, 0.2919731, 0.8133602, 0.29046127, -0.22630857, 0.9460396, 0.23956898, 0.05505262, 0.98405635, 0.60767066, 0.4453835, 0.77357423, 0.14624831, 0.5659478, -0.7039867, 0.7764218, 0.9374812, 0.0037792725, 0.1545598, 0.073970705, 0.45412806, 0.35047254, 0.2241304, 0.39344636, -0.645818, 0.12317476, 0.600308, 0.65878445, 0.09789734, 0.18064253, 0.49451795, 0.82080996, 0.049708407, 0.42908588, -0.9700393, 0.2122335, 0.9120806, 0.30860576, 0.11446109, 0.26945624, 0.21033902, 0.38919696, 0.20633578, 0.6836851, -0.23108464, 0.56171197, 0.6592914, 0.7111641, 0.122732915, 0.175212, 0.28750554, 0.2762196, 0.69497037, 0.87714785, -0.14267384, 0.53668326, 0.06784272, 0.41991386, 0.6446433, 0.10313381, 0.34573162, 0.58078456, 0.9571553, 0.8034138, -0.11315275, 0.62457347, 0.7238658, 0.71716243, 0.59590846, 0.4917532, 0.8643412, 0.62887543, 0.88931817, 0.8851036, -0.86363167, 0.064931095, 0.14413676, 0.54044527, 0.16236171, 0.084106006, 0.4638834, 0.8891439, 0.5360515, 0.9226853, -0.893137, 0.21829833, 0.12583959, 0.17256053, 0.28641203, 0.4333561, 0.14439079, 0.49216673, 0.6639625, 0.011327274, -0.9237246, 0.62955445, 0.43204167, 0.40292194, 0.5705324, 0.6065112, 0.83784616, 0.94212896, 0.115255654, 0.6309797, -0.3108708, 0.6586301, 0.38690144, 0.8098668, 0.013516203, 0.07774274, 0.39254647, 0.52739745, 0.25755215, 0.5605373, -0.6392504, 0.4565877, 0.044733036, 0.034469932, 0.91027683, 0.8948544, 0.4987339, 0.5513053, 0.4307504, 0.16255233, -0.3473624, 0.3721745, 0.96491295, 0.8779909, 0.961379, 0.2340772, 0.6328894, 0.7412148, 0.9699129, 0.55585057, -0.24625985, 0.52175444, 0.77388823, 0.9050718, 0.61181456, 0.23450689, 0.8313969, 0.31597278, 0.15904433, 0.20866929, -0.04080962, 0.6169933, 0.23461457, 0.1034252, 0.37207687, 0.4671369, 0.58482146, 0.39757174, 0.4926451, 0.67567796, -0.107777245, 0.28654084, 0.5113785, 0.9527033, 0.28361735, 0.9386963, 0.6937171, 0.50891054, 0.84848785, 0.779439, -0.44485334, 0.65133166, 0.55748457, 0.7017016, 0.3142774, 0.11749596, 0.68269944, 0.13966125, 0.42265537, 0.6757699, -0.06345752, 0.18276113, 0.39226097, 0.2220811, 0.12174272, 0.7303691, 0.13755992, 0.8614878, 0.50591403, 0.4942421, -0.64925575, 0.23531766, 0.24856968, 0.29423487, 0.44807333, 0.959719, 0.010375906, 0.82118493, 0.6214544, 0.67311823, -0.5407898, 0.3224864, 0.46748495, 0.37960532, 0.76381594, 0.38947794, 0.05950873, 0.53291297, 0.7891478, 0.2545809, -0.7844374, 0.44516018, 0.97491634, 0.81687516, 0.61222047, 0.9250161, 0.89427984, 0.28929746, 0.83096063, 0.5532483, -0.8011364, 0.8322293, 0.0029964554, 0.35424575, 0.13018323, 0.20953566, 0.402762, 0.2632497, 0.25362825, 0.3545584, -0.10712006, 0.8615145, 0.51820683, 0.7495371, 0.13498017, 0.74097115, 0.7152762, 0.0126556605, 0.45826513, 0.73226476, -0.67086035, 0.6046469, 0.07234, 0.25133318, 0.70980465, 0.20409557, 0.2604013, 0.43169454, 0.6820144, 0.5230572, -0.065439165, 0.72107846, 0.99022436, 0.06820616, 0.87198186, 0.70856047, 0.31948993, 0.11323921, 0.24942209, 0.5542803, -0.9867159, 0.79625905, 0.27928472, 0.4345894, 0.14746083, 0.9229229, 0.9269534, 0.22537923, 0.681895, 0.8712493, -0.20973994, 0.8816242, 0.83103234, 0.098695815, 0.88238794, 0.19648944, 0.75988936, 0.75166327, 0.64444107, 0.9260877, -0.94913435, 0.9710675, 0.5812353, 0.7305711, 0.28911924, 0.3860416, 0.87129015, 0.45000067, 0.87755525, 0.42641973, -0.4214812, 0.60203695, 0.7632336, 0.90398484, 0.74554884, 0.8746013, 0.32536224, 0.6377506, 0.10387234, 0.7868817, -0.2771422, 0.035022065, 0.74979955, 0.8107651, 0.31331727, 0.18381497, 0.8900461, 0.89152855, 0.18581823, 0.6754924, -0.9486711, 0.5678266, 0.4687981, 0.32333443, 0.60514593, 0.015648454, 0.21502374, 0.5487136, 0.14547014, 0.76141924, -0.05163277, 0.4769527, 0.34782398, 0.25547525, 0.44976813, 0.607703, 0.11839061, 0.9270475, 0.35314697, 0.007786621, -0.8711272, 0.12213872, 0.64779097, 0.8575594, 0.64894545, 0.9141123, 0.22126794, 0.77047014, 0.4172538, 0.10530428, -0.4959955, 0.97976166, 0.26418245, 0.20206283, 0.47774863, 0.85365456, 0.13323887, 0.43989918, 0.29883888, 0.7299004, -0.65957755, 0.7766486, 0.49228048, 0.34245312, 0.7352489, 0.8001895, 0.6871981, 0.49432427, 0.360997, 0.70561427, -0.06542435, 0.96299857, 0.5383816, 0.1780316, 0.8043652, 0.82653236, 0.92003566, 0.6112387, 0.67438895, 0.6910336, -0.79438055, 0.44455358, 0.13145985, 0.04016586, 0.26542372, 0.07187113, 0.21277027, 0.14576113, 0.77772665, 0.59611356, -0.47446412, 0.6784915, 0.62820864, 0.62324655, 0.34820905, 0.094478644, 0.62985826, 0.30533785, 0.122310445, 0.84875596, -0.22691421, 0.7269437, 0.40947318, 0.7116395, 0.039879926, 0.5329969, 0.44138008, 0.08615084, 0.39769763, 0.65121627, -0.93361884, 0.52200013, 0.7655102, 0.60780525, 0.9355199, 0.21502401, 0.64518875, 0.45211464, 0.0770294, 0.6633778, -0.5874192, 0.541437, 0.7165977, 0.7648834, 0.2311502, 0.3869329, 0.33478996, 0.915135, 0.82982254, 0.70988655, -0.19667415, 0.6146979, 0.4889283, 0.825633, 0.46411943, 0.067436874, 0.035080392, 0.41982034, 0.0002859342, 0.7324268, -0.630491, 0.12661943, 0.7480635, 0.12651038, 0.6624947, 0.952464, 0.9129812, 0.020403363, 0.6877267, 0.13318504, -0.44928992, 0.1777436, 0.22830844, 0.45893264, 0.2613367, 0.68547726, 0.010346001, 0.6445898, 0.4804893, 0.652947, -0.19820693, 0.52624506, 0.25632828, 0.687811, 0.4545421, 0.31892103, 0.033071853, 0.9398772, 0.14368583, 0.868083, -0.17994362, 0.2253684, 0.4518287, 0.34460258, 0.032886766, 0.4607998, 0.7933734, 0.59008723, 0.10238874, 0.27868623, -0.47395167, 0.3143866, 0.22740832, 0.6966375, 0.26059666, 0.018930554, 0.3863894, 0.029995646, 0.5642963, 0.7786422, -0.05709087, 0.39049065, 0.939331, 0.3473389, 0.53421986, 0.10424597, 0.8702912, 0.060252476, 0.6719683, 0.34357366, -0.9193921, 0.97310406, 0.8767175, 0.8196437, 0.9532414, 0.22392152, 0.7259149, 0.88370585, 0.42604586, 0.80053693, -0.8921038, 0.42025873, 0.54220104, 0.2018031, 0.17899537, 0.8838203, 0.29883677, 0.5596908, 0.42721438, 0.43561155, -0.9325316, 0.0030762074, 0.37558094, 0.36504367, 0.8109921, 0.78945297, 0.2860374, 0.10448979, 0.8103827, 0.9286408, -0.59050864, 0.733121, 0.91811895, 0.75881505, 0.35929412, 0.50084764, 0.4376691, 0.40776464, 0.7433961, 0.036675144, -0.29301566, 0.5026836, 0.6039498, 0.7637594, 0.8865383, 0.6368321, 0.8482896, 0.7375279, 0.16834354, 0.65039957, -0.8054092, 0.31060037, 0.6330381, 0.23635677, 0.41104206, 0.9163159, 0.5975231, 0.51167387, 0.008651535, 0.16378845, -0.93788415, 0.62142515, 0.07332315, 0.49740508, 0.21002825, 0.15898286, 0.5021398, 0.78338593, 0.842509, 0.67814773, -0.44615123, 0.8910721, 0.81629467, 0.39053923, 0.14259589, 0.42984807, 0.39912644, 0.61182153, 0.47850534, 0.17416, -0.94116336, 0.5485095, 0.93614626, 0.15998314, 0.12323159, 0.27990827, 0.10008287, 0.6817622, 0.34777302, 0.4429782, -0.9033245, 0.92599523, 0.39911312, 0.57960767, 0.09879101, 0.6715905, 0.4293604, 0.1065447, 0.55373114, 0.72755545, -0.13469236, 0.06490368, 0.89501894, 0.4901958, 0.20424834, 0.9143371, 0.4943057, 0.24249884, 0.093760885, 0.98119396, -0.5171895, 0.98570156, 0.03316852, 0.83449155, 0.22262509, 0.38937467, 0.6852789, 0.91334003, 0.3741735, 0.93012, -0.05889999, 0.8203776, 0.43561292, 0.3995308, 0.77482325, 0.52015597, 0.491959, 0.23668702, 0.29174823, 0.47100535, -0.0004876647, 0.29258174, 0.058090426, 0.75094986, 0.039467655, 0.8762597, 0.65349054, 0.44595045, 0.9557348, 0.20889449, -0.78560257, 0.857584, 0.5880013, 0.36657903, 0.9257887, 0.917623, 0.89282674, 0.56462157, 0.35698256, 0.70941633, -0.9863116, 0.51602036, 0.7323712, 0.62361115, 0.6686555, 0.31431475, 0.62929076, 0.4954881, 0.71537256, 0.68409234, -0.4223781, 0.2576187, 0.9507506, 0.6227555, 0.98070633, 0.22460775, 0.9276111, 0.28221866, 0.79502386, 0.34636542, -0.73588413, 0.23932843, 0.95760524, 0.165279, 0.1445174, 0.20131597, 0.23237628, 0.069033906, 0.47374207, 0.85720026, -0.62732923, 0.9273374, 0.8797045, 0.5823319, 0.48469374, 0.48446727, 0.5602105, 0.43447927, 0.08229436, 0.7251529, -0.24696892, 0.15800244, 0.7305779, 0.27164242, 0.78651637, 0.52798384, 0.9068334, 0.9652458, 0.3858727, 0.701181, -0.9900118, 0.61060804, 0.7695977, 0.010617126, 0.97353226, 0.74698323, 0.5584152, 0.56709224, 0.47909376, 0.46733952, -0.08193848, 0.56025684, 0.021746036, 0.8581723, 0.056763105, 0.49504068, 0.37791422, 0.36841872, 0.13806179, 0.49623904, -0.66439724, 0.49313185, 0.19992432, 0.06987098, 0.09939649, 0.5778817, 0.50875056, 0.6859628, 0.3787626, 0.6165335, -0.29448256, 0.2671305, 0.6831612, 0.77256113, 0.86718845, 0.016721206, 0.1577397, 0.86908734, 0.60879964, 0.73771054, -0.9260521, 0.9931183, 0.9553855, 0.6149548, 0.6432144, 0.6867121, 0.1362564, 0.8724056, 0.21487932, 0.2914757, -0.15006965, 0.53841466, 0.827184, 0.88963366, 0.03678374, 0.49687997, 0.41068372, 0.69972676, 0.9112206, 0.39565054, -0.23823264, 0.8724524, 0.18832962, 0.8625602, 0.17285694, 0.814808, 0.87709564, 0.24918492, 0.99098384, 0.0400419, -0.337301, 0.50882685, 0.7596191, 0.4003513, 0.5701869, 0.67127895, 0.5377463, 0.58496946, 0.42665657, 0.4126844, -0.4416253, 0.63634497, 0.47108346, 0.08728689, 0.4664639, 0.75606793, 0.4399465, 0.79352754, 0.7357774, 0.3703085, -0.6060375, 0.45801297, 0.9578667, 0.2131491, 0.49947786, 0.05359975, 0.8047887, 0.092825316, 0.4420979, 0.82840645, -0.80961645, 0.8870715, 0.88142174, 0.17483743, 0.95417476, 0.6412428, 0.7787956, 0.4268327, 0.31944674, 0.3655048, -0.9591336, 0.82571423, 0.2730702, 0.49853623, 0.95402527, 0.6018877, 0.4013689, 0.10104273, 0.39609635, 0.41678905, -0.37486148, 0.083568096, 0.5134075, 0.6206753, 0.43400443, 0.879288, 0.5509602, 0.54647, 0.9008734, 0.5165872, -0.86649024, 0.44492102, 0.14287159, 0.59825015, 0.60306793, 0.5545538, 0.7549232, 0.29624605, 0.13311216, 0.8252211, -0.97727233, 0.013113789, 0.4740808, 0.37027258, 0.41117483, 0.7803232, 0.18494278, 0.45933047, 0.25912383, 0.89759016, -0.65223086, 0.70374596, 0.696729, 0.02530885, 0.45354494, 0.72604835, 0.37366393, 0.2607464, 0.740833, 0.07488672, -0.09028263, 0.23232558, 0.5259593, 0.80285954, 0.49901456, 0.5142126, 0.6828427, 0.67482007, 0.8954683, 0.39947143, -0.8469645, 0.10512285, 0.96793056, 0.5708752, 0.43951672, 0.3617477, 0.6094873, 0.14313498, 0.2095005, 0.6536812, -0.69434524, 0.09162968, 0.28734615, 0.0032832306, 0.86435634, 0.1627443, 0.748192, 0.11756273, 0.14470519, 0.8770196, -0.1808899, 0.49417683, 0.55541307, 0.05822544, 0.73493844, 0.7449467, 0.48715448, 0.67122126, 0.871258, 0.8969622, -0.097480536, 0.5101227, 0.5638622, 0.8596524, 0.050625734, 0.547108, 0.7358154, 0.12585375, 0.5857921, 0.09179724, -0.11656108, 0.23052894, 0.051245883, 0.08715177, 0.38054147, 0.99865294, 0.9449794, 0.52267605, 0.93850327, 0.33627024, -0.7660206, 0.56527996, 0.5301148, 0.018448701, 0.21858154, 0.3527876, 0.5497098, 0.90970516, 0.8359368, 0.69457, -0.8745932, 0.93826604, 0.27187696, 0.3125383, 0.5562007, 0.1842225, 0.5277675, 0.42769375, 0.9526575, 0.3172483, -0.42692894, 0.6223383, 0.5317706, 0.05290796, 0.7604585, 0.95036095, 0.44293094, 0.46826127, 0.67768395, 0.7362855, -0.7999673, 0.96447843, 0.732718, 0.53498775, 0.13094164, 0.5322006, 0.9800079, 0.5454135, 0.64107084, 0.6978381, -0.9973982, 0.82611024, 0.28991696, 0.8912221, 0.21720403, 0.17829505, 0.95865196, 0.7387076, 0.5309511, 0.19631897, -0.47088546, 0.5172857, 0.5700186, 0.6212549, 0.90934134, 0.14368229, 0.033509336, 0.4772069, 0.25799018, 0.26822057, -0.9098567, 0.08144851, 0.23202117, 0.09965124, 0.8946027, 0.91011477, 0.20554802, 0.7368892, 0.18159665, 0.024000084, -0.20421462, 0.982354, 0.7866229, 0.2548194, 0.31985012, 0.6008187, 0.33242133, 0.64054847, 0.8357039, 0.58216345, -0.991709, 0.70422333, 0.93731016, 0.481365, 0.26540005, 0.2826816, 0.39445987, 0.1114631, 0.6256465, 0.9872593, -0.49869126, 0.502801, 0.2874233, 0.37285027, 0.78798145, 0.9159497, 0.5940891, 0.19026573, 0.99661946, 0.30708927, -0.972747, 0.22176278, 0.55711097, 0.50695103, 0.99210435, 0.48853147, 0.73066276, 0.31519917, 0.3014048, 0.30852264, -0.81126094, 0.39296088, 0.641503, 0.6758267, 0.27651158, 0.20563333, 0.14413832, 0.7506562, 0.83425117, 0.6119211, -0.5156549, 0.094084926, 0.111242734, 0.1943373, 0.52530885, 0.70141363, 0.6949307, 0.41377264, 0.46683794, 0.4039004, -0.006729609, 0.14215559, 0.643929, 0.52861464, 0.6094164, 0.7699462, 0.1471124, 0.43035918, 0.4892606, 0.7768686, -0.5520188, 0.07926069, 0.8100583, 0.31712383, 0.17599839, 0.105730385, 0.861298, 0.6115966, 0.096338674, 0.5823481, -0.77181137, 0.8434329, 0.35601455, 0.38469836, 0.79143435, 0.8786621, 0.11052005, 0.36277366, 0.9816422, 0.29069075, -0.7936008, 0.31689015, 0.84836125, 0.8975044, 0.30179304, 0.66910535, 0.7490319, 0.1128883, 0.06641029, 0.5065654, -0.058520928, 0.71377915, 0.26139554, 0.057382602, 0.059902266, 0.4363942, 0.28402662, 0.7941189, 0.018338913, 0.41957843, -0.84011555, 0.083334126, 0.31743395, 0.88448983, 0.632089, 0.16329671, 0.78614104, 0.2592306, 0.7371803, 0.7307543, -0.65942615, 0.7843387, 0.448717, 0.19856988, 0.9832678, 0.23512867, 0.23089947, 0.9125539, 0.015330798, 0.50689304, -0.3566985, 0.74840975, 0.5451863, 0.5897733, 0.5238272, 0.05803223, 0.5820373, 0.29863194, 0.3247961, 0.35504016, -0.5946355, 0.31640115, 0.34443474, 0.56206375, 0.45057517, 0.71026665, 0.99945617, 0.9638714, 0.26541534, 0.13849631, -0.8829643, 0.48980126, 0.375708, 0.33565596, 0.84713924, 0.2741822, 0.26506215, 0.06282568, 0.07411481, 0.8247736, -0.20549475, 0.37147272, 0.7787881, 0.5114459, 0.06287994, 0.09170583, 0.53814787, 0.72766066, 0.36066267, 0.5740568, -0.58125937, 0.4875091, 0.93443453, 0.38214013, 0.13611887, 0.343025, 0.439904, 0.88665324, 0.7479947, 0.27300113, -0.23567249, 0.26702806, 0.64713854, 0.8768345, 0.62392867, 0.8668972, 0.37270173, 0.20953032, 0.74263406, 0.249645, -0.79297006, 0.51921165, 0.22451714, 0.50002253, 0.14954542, 0.22316273, 0.53761303, 0.83298886, 0.4991838, 0.35886934, -0.17211881, 0.2717955, 0.6032087, 0.6913585, 0.5572369, 0.3954552, 0.55536675, 0.9935679, 0.19953707, 0.5041142, -0.83427817, 0.3784089, 0.314831, 0.80111367, 0.58910114, 0.93846667, 0.7243342, 0.90195364, 0.8875172, 0.19598271, -0.7190041, 0.3286175, 0.9850266, 0.11101766, 0.78108674, 0.06204771, 0.26299196, 0.434412, 0.23259473, 0.9129562, -0.805412, 0.6069152, 0.38746944, 0.38912535, 0.10088234, 0.96387696, 0.6638193, 0.95578, 0.31959754, 0.22847345, -0.3115305, 0.37913388, 0.009993258, 0.23851983, 0.4153668, 0.41456118, 0.20438069, 0.42340347, 0.9109214, 0.21107873, -0.49882856, 0.6356594, 0.94547164, 0.3032011, 0.6398653, 0.84350127, 0.28676888, 0.49219108, 0.91027176, 0.49518922, -0.13246326, 0.120954745, 0.76097316, 0.28658092, 0.6987022, 0.22736304, 0.99093944, 0.9257056, 0.7002313, 0.6252242, -0.27464733, 0.76855415, 0.5823561, 0.6590438, 0.8844522, 0.3398702, 0.31862426, 0.7465068, 0.6956509, 0.36652556, -0.857667, 0.8395885, 0.5234906, 0.021515984, 0.4141276, 0.16975257, 0.66144353, 0.084268354, 0.74926007, 0.25738105, -0.67710805, 0.17162827, 0.045508236, 0.8244083, 0.0960102, 0.19057575, 0.6181607, 0.72341233, 0.5398176, 0.18800376, -0.4236217, 0.27867505, 0.7231721, 0.28569725, 0.9364314, 0.73027444, 0.05330333, 0.28642786, 0.4187489, 0.29999506, -0.524877, 0.5402621, 0.7965402, 0.54374623, 0.6375222, 0.29287475, 0.59746414, 0.73945713, 0.87245333, 0.5289497, -0.56591946, 0.9066711, 0.17644554, 0.4428503, 0.94811606, 0.10301907, 0.7230459, 0.75794774, 0.5630336, 0.69387645, -0.7217095, 0.5952119, 0.20668921, 0.5076471, 0.9429038, 0.57899195, 0.116416365, 0.23779334, 0.08508458, 0.6838532, -0.11644924, 0.3750157, 0.6655195, 0.44926503, 0.73250407, 0.13684598, 0.37508807, 0.50176203, 0.1868861, 0.80313545, -0.59311163, 0.8787036, 0.850959, 0.0108679095, 0.62208426, 0.5169506, 0.10222952, 0.28032187, 0.3375812, 0.83341235, -0.0072284974, 0.2953556, 0.7233943, 0.7248724, 0.5782856, 0.9296651, 0.3335729, 0.28889313, 0.6008424, 0.05853025, -0.17645839, 0.3596708, 0.6543726, 0.18860014, 0.41250044, 0.19090378, 0.24115163, 0.7271805, 0.7103462, 0.8112701, -0.727931, 0.22128391, 0.5710617, 0.7598981, 0.10076484, 0.8430059, 0.7442529, 0.1958213, 0.8855628, 0.4259532, -0.47676244, 0.8360945, 0.90021217, 0.25167224, 0.67662466, 0.8210937, 0.6516214, 0.940647, 0.8709795, 0.802839, -0.8032731, 0.08619493, 0.9009196, 0.12835586, 0.62667704, 0.2334408, 0.224331, 0.6623589, 0.59836745, 0.4311805, -0.27579898, 0.37504902, 0.5699756, 0.5263111, 0.10548131, 0.7859446, 0.72429395, 0.96349615, 0.6241076, 0.7352797, -0.18541217, 0.13775158, 0.40333033, 0.17488916, 0.5817678, 0.34036386, 0.45945865, 0.40270033, 0.51197547, 0.59140676, -0.5392824, 0.3005046, 0.85620105, 0.9075073, 0.007996995, 0.6417361, 0.3203643, 0.44270578, 0.13322107, 0.86732405, -0.6186749, 0.08189404, 0.59745383, 0.4543823, 0.15015423, 0.10171343, 0.2661189, 0.37390104, 0.14619094, 0.8906801, -0.096799746, 0.68812525, 0.31653944, 0.13569976, 0.6174268, 0.6655215, 0.6828646, 0.72603047, 0.54658806, 0.28631318, -0.77398217, 0.8216307, 0.15038341, 0.0069607063, 0.8918981, 0.97529435, 0.518848, 0.6624684, 0.5183141, 0.46374524, -0.4655803, 0.28158814, 0.83027506, 0.75678355, 0.11660483, 0.10351813, 0.54029775, 0.948948, 0.024734931, 0.48005438, -0.074244976, 0.0855576, 0.2565094, 0.62129533, 0.49460703, 0.85115707, 0.98396516, 0.7205013, 0.2900805, 0.34247547, -0.9588715, 0.5943338, 0.89611775, 0.8469079, 0.09334188, 0.79704416, 0.9315106, 0.59049314, 0.5624842, 0.17485987, -0.5828654, 0.60365057, 0.85558695, 0.6824457, 0.4250998, 0.8152116, 0.8578502, 0.55975586, 0.01909494, 0.5139087, -0.12522376, 0.73391664, 0.7012955, 0.06653367, 0.2120682, 0.6884245, 0.5651213, 0.5290881, 0.51235366, 0.040741026, -0.9913292, 0.7983467, 0.3723879, 0.17583862, 0.50487375, 0.87124646, 0.3854704, 0.9833672, 0.66344166, 0.31956065, -0.1720075, 0.94980466, 0.38646382, 0.8498751, 0.89718896, 0.4705944, 0.22997065, 0.57406366, 0.19619557, 0.67939544, -0.9933069, 0.4242093, 0.70140636, 0.7761718, 0.21725173, 0.22495484, 0.89303833, 0.82958406, 0.6348397, 0.40491733, -0.23192288, 0.40242258, 0.07813944, 0.5217432, 0.18353066, 0.7845187, 0.23126268, 0.6797483, 0.17757194, 0.55385333, -0.42974123, 0.874483, 0.8963142, 0.6995343, 0.34190118, 0.17541912, 0.34745282, 0.85142046, 0.16934472, 0.7414738, -0.4584539, 0.99105763, 0.33289248, 0.8329583, 0.04743413, 0.5671199, 0.09694037, 0.5962161, 0.9585869, 0.2799189, -0.9782081, 0.5558863, 0.3485275, 0.25852436, 0.08763776, 0.76958495, 0.8716652, 0.86472064, 0.6663444, 0.1126702, -0.23933174, 0.55022234, 0.39649174, 0.64234227, 0.24965419, 0.118823886, 0.5278951, 0.0018720366, 0.43427062, 0.04183261, -0.877502, 0.04161787, 0.66023934, 0.8933659, 0.9464634, 0.24086526, 0.069530085, 0.24518117, 0.47430903, 0.61641073, -0.6875784, 0.6350466, 0.7211614, 0.89765304, 0.5756452, 0.87385494, 0.5259555, 0.63778985, 0.6118965, 0.5723162, -0.3037539, 0.48273215, 0.18507604, 0.05667453, 0.5021421, 0.90823156, 0.59456587, 0.69055027, 0.5833041, 0.92861027, -0.039224792, 0.095068336, 0.16194543, 0.9167543, 0.40241688, 0.93659025, 0.895647, 0.4551616, 0.31206095, 0.8467725, -0.7000548, 0.62648404, 0.39041162, 0.049933646, 0.42509183, 0.6042851, 0.8290609, 0.49883872, 0.06669706, 0.37579927, -0.5928684, 0.89010525, 0.3899755, 0.8619544, 0.7380787, 0.39476988, 0.8565418, 0.6035648, 0.39122385, 0.038231853, -0.64629936, 0.37897983, 0.6618771, 0.54569876, 0.577186, 0.59251004, 0.47310117, 0.8044071, 0.49523613, 0.6390549, -0.97820795, 0.07079393, 0.3257289, 0.765124, 0.8722614, 0.6772699, 0.092320524, 0.1351424, 0.6315827, 0.89785695, -0.07917066, 0.09572715, 0.6238532, 0.20750481, 0.33574188, 0.14911953, 0.70509285, 0.29999104, 0.1786756, 0.0076469877, -0.08004845, 0.29208216, 0.063937746, 0.27382907, 0.20047311, 0.32107502, 0.96460694, 0.84471285, 0.47274768, 0.8325818, -0.13118395, 0.024653764, 0.0036025788, 0.42764217, 0.39759132, 0.52207446, 0.56437635, 0.62485147, 0.989693, 0.060808785, -0.30244938, 0.7213994, 0.9719821, 0.49336693, 0.9590612, 0.5505722, 0.75512666, 0.4543723, 0.2099569, 0.42806646, -0.8874172, 0.17311013, 0.6257315, 0.48758915, 0.55900645, 0.68612576, 0.0068561803, 0.051899806, 0.56465095, 0.5511864, -0.71266294, 0.2476077, 0.6623947, 0.7990009, 0.76667297, 0.054516893, 0.092124574, 0.19621104, 0.80991346, 0.8136675, -0.58474314, 0.08024137, 0.31029803, 0.117866814, 0.70519763, 0.35864902, 0.32010004, 0.5705708, 0.3147679, 0.64990085, -0.56594837, 0.51023465, 0.6347559, 0.044681232, 0.94516456, 0.9580738, 0.39892223, 0.51601344, 0.8686357, 0.71146554, -0.51521826, 0.51247656, 0.06020054, 0.43850663, 0.3481458, 0.054841675, 0.059004717, 0.1729812, 0.7266939, 0.9045443, -0.45844766, 0.5589156, 0.6444588, 0.39628944, 0.8433233, 0.8071758, 0.8628121, 0.5078647, 0.78239155, 0.20035744, -0.36602575, 0.43628535, 0.7371319, 0.91475004, 0.985238, 0.20242831, 0.61285174, 0.6177135, 0.8538363, 0.8085992, -0.65559465, 0.57611114, 0.32757533, 0.09844793, 0.2984492, 0.07226656, 0.020040827, 0.87179136, 0.769721, 0.65035594, -0.2996443, 0.14711884, 0.8438769, 0.4102236, 0.1914532, 0.007032739, 0.8657759, 0.23846649, 0.20135792, 0.13798875, -0.09526171, 0.8910575, 0.7336219, 0.6682783, 0.34543982, 0.078932896, 0.77534467, 0.14545049, 0.45326862, 0.14571752, -0.44198993, 0.44129124, 0.31914487, 0.9180948, 0.24894963, 0.8823365, 0.23134027, 0.54601085, 0.09784024, 0.7710568, -0.787135, 0.99102074, 0.73814374, 0.13203558, 0.90071315, 0.2189069, 0.5924085, 0.32690832, 0.7232968, 0.97820526, -0.33665246, 0.37438527, 0.41635555, 0.71584755, 0.7133375, 0.76453716, 0.84248924, 0.6592971, 0.7530081, 0.2195163, -0.29692188, 0.87459034, 0.41852275, 0.62400347, 0.20836602, 0.8583531, 0.82797396, 0.9257821, 0.16127396, 0.3091167, -0.77569246, 0.31976497, 0.14062625, 0.43030116, 0.35085374, 0.104240976, 0.15291376, 0.6015863, 0.76756513, 0.12653293, -0.48652443, 0.44843635, 0.42215365, 0.47506335, 0.80906504, 0.06760467, 0.02493567, 0.6032973, 0.20475733, 0.48441246, -0.039847255, 0.5720432, 0.7930028, 0.8783239, 0.47413486, 0.91254467, 0.57249796, 0.11414025, 0.9236696, 0.042360075, -0.39093295, 0.6666264, 0.16563436, 0.41418016, 0.20251282, 0.016887465, 0.23375902, 0.9860544, 0.36499384, 0.60909647, -0.6116234, 0.24090295, 0.891732, 0.6264752, 0.7329919, 0.8484855, 0.45243672, 0.9434594, 0.8149384, 0.14076136, -0.8334174, 0.22467664, 0.72102475, 0.6768615, 0.26926944, 0.20364925, 0.52676225, 0.2623023, 0.95616627, 0.43830907, -0.531743, 0.03877351, 0.67791677, 0.72520506, 0.7356, 0.81989807, 0.282802, 0.007973485, 0.27255052, 0.7921776, -0.8338457, 0.038881265, 0.23830348, 0.59566087, 0.872789, 0.7989443, 0.68031126, 0.16652757, 0.14533207, 0.62564933, -0.46010798, 0.6290386, 0.29920182, 0.7829082, 0.20894268, 0.16625631, 0.94560164, 0.48877287, 0.14491072, 0.9988636, -0.49012524, 0.9714567, 0.029888112, 0.92668474, 0.07735347, 0.5728499, 0.5629862, 0.16652691, 0.8908752, 0.91309386, -0.56568354, 0.44446322, 0.67090887, 0.022760825, 0.3069157, 0.7945361, 0.9863731, 0.12536389, 0.80407244, 0.47032514, -0.523338, 0.36023465, 0.11697024, 0.33051696, 0.9782011, 0.9027044, 0.7395717, 0.89500856, 0.51626235, 0.5693437, -0.8742964, 0.7940291, 0.86306274, 0.27368698, 0.30205235, 0.86238897, 0.008993154, 0.31161872, 0.5183074, 0.29993913, -0.2359581, 0.51378435, 0.27565238, 0.23223823, 0.059965752, 0.01564475, 0.9581297, 0.276441, 0.4759925, 0.41440654, -0.17988315, 0.82023776, 0.68470037, 0.6745856, 0.47552556, 0.12989059, 0.85448647, 0.69937116, 0.94848365, 0.17464903, -0.83327824, 0.6679777, 0.65026456, 0.32153153, 0.038797423, 0.7716544, 0.58140045, 0.3972219, 0.7207085, 0.44452676, -0.78554296, 0.67475444, 0.6070565, 0.50413334, 0.23436703, 0.009553685, 0.08458229, 0.884732, 0.27055123, 0.96255636, -0.9445748, 0.46313068, 0.41901603, 0.10185582, 0.38946053, 0.05405868, 0.10932874, 0.18847717, 0.79816145, 0.17216177, -0.007902476, 0.30962202, 0.36313507, 0.34365836, 0.46666092, 0.5679804, 0.8635198, 0.9541208, 0.19344081, 0.2883113, -0.4342443, 0.5609078, 0.55573255, 0.03146575, 0.6288636, 0.50512874, 0.21318124, 0.18056706, 0.44021857, 0.46597186, -0.045308296, 0.96975446, 0.42881992, 0.9859273, 0.23007429, 0.37014756, 0.24896163, 0.54840875, 0.932071, 0.98473877, -0.6623257, 0.39292327, 0.5990605, 0.5485467, 0.4366243, 0.47592095, 0.31161934, 0.26339814, 0.037472416, 0.6663866, -0.1460339, 0.13046144, 0.6912912, 0.9822399, 0.528312, 0.38366696, 0.90739816, 0.3875503, 0.47299224, 0.88433176, -0.8408774, 0.92876166, 0.7482586, 0.33218956, 0.12685347, 0.038148023, 0.8808021, 0.37720776, 0.11358407, 0.09651337, -0.3190188, 0.31511107, 0.022049852, 0.20870206, 0.6259856, 0.041321024, 0.9618473, 0.007185834, 0.5948415, 0.15294261, -0.19350938, 0.9497831, 0.14309464, 0.77383196, 0.31993797, 0.91484684, 0.27846324, 0.44658, 0.45761526, 0.8464073, -0.46274942, 0.86141133, 0.075416476, 0.0477392, 0.14386131, 0.733564, 0.64466465, 0.26687092, 0.42169324, 0.39847627, -0.5951189, 0.9344116, 0.14981407, 0.94095904, 0.3473678, 0.83092284, 0.108411595, 0.48258916, 0.3562543, 0.48699102, -0.42181966, 0.9002123, 0.7927088, 0.32004964, 0.6908224, 0.8910943, 0.78566706, 0.9744266, 0.012251603, 0.21200661, -0.7596848, 0.4342221, 0.9195925, 0.26717675, 0.63376397, 0.45760745, 0.2396946, 0.97431064, 0.06484076, 0.8924216, -0.39665636, 0.6949764, 0.5854926, 0.1963652, 0.5578238, 0.2590978, 0.799969, 0.2021356, 0.42646417, 0.48901513, -0.8064353, 0.7958741, 0.0903257, 0.9706242, 0.42458767, 0.56253713, 0.068702534, 0.75536686, 0.3569168, 0.25276697, -0.94789696, 0.670238, 0.2546193, 0.2096866, 0.6387915, 0.16089676, 0.01481907, 0.8826373, 0.3071951, 0.8897603, -0.59122825, 0.13410094, 0.4177484, 0.4638327, 0.09033466, 0.72684324, 0.3147197, 0.5963436, 0.76222587, 0.43172458, -0.091125324, 0.58353144, 0.5479625, 0.52323645, 0.40557137, 0.9638107, 0.3438964, 0.9489683, 0.8425891, 0.07122685, -0.38890493, 0.48432773, 0.61739385, 0.8120738, 0.9445246, 0.7264184, 0.4403571, 0.375806, 0.55757374, 0.396927, -0.24427874, 0.9173317, 0.8949405, 0.5367038, 0.8977869, 0.6723343, 0.3781257, 0.626493, 0.88028955, 0.6977444, -0.24781741, 0.4723589, 0.993141, 0.9251922, 0.16164163, 0.36436552, 0.12227554, 0.73138285, 0.80411524, 0.6749808, -0.8170004, 0.06585078, 0.040048227, 0.23596825, 0.5008554, 0.10690048, 0.51670706, 0.6056746, 0.5193081, 0.3639163, -0.28648618, 0.9389137, 0.03876988, 0.36529887, 0.18744585, 0.17379361, 0.68859094, 0.011258623, 0.62544954, 0.733237, -0.585685, 0.7174034, 0.06867873, 0.14484468, 0.82340944, 0.916546, 0.49118677, 0.6922017, 0.65043217, 0.58015907, -0.60414284, 0.70897424, 0.57169074, 0.8825929, 0.5799266, 0.17842796, 0.8772835, 0.65897226, 0.03584844, 0.7908864, -0.15562724, 0.7724511, 0.10718488, 0.5163733, 0.41125825, 0.3089037, 0.43358904, 0.62784207, 0.73774636, 0.98784804, -0.6757746, 0.111016914, 0.10593328, 0.07087821, 0.08929581, 0.09959695, 0.99717206, 0.89520353, 0.4125588, 0.5843094, -0.6157137, 0.82450545, 0.95524246, 0.939149, 0.7597735, 0.5775119, 0.36722296, 0.15617695, 0.78537226, 0.009017896, -0.29651013, 0.029618707, 0.97541016, 0.83456314, 0.5776098, 0.8132339, 0.6102185, 0.55230546, 0.73358643, 0.51450574, -0.48295695, 0.86334467, 0.9544553, 0.6625841, 0.90438455, 0.49312592, 0.603041, 0.50081253, 0.7932971, 0.4803297, -0.1812559, 0.9820799, 0.24641345, 0.45153904, 0.1751727, 0.3311218, 0.81720865, 0.16803588, 0.7565998, 0.8337463, -0.9416807, 0.2774121, 0.8424698, 0.7287285, 0.6913379, 0.64615583, 0.13560674, 0.27137014, 0.4932684, 0.27606192, -0.48937842, 0.4448666, 0.16161712, 0.89805305, 0.10135246, 0.75236905, 0.87005013, 0.29265827, 0.034764472, 0.26664755, -0.9744709, 0.86641043, 0.3628798, 0.30504256, 0.827762, 0.31443018, 0.7832053, 0.5238711, 0.65939045, 0.246488, -0.9960252, 0.44218266, 0.7957057, 0.8998401, 0.572825, 0.20554484, 0.020874852, 0.22572684, 0.97124624, 0.2582287, -0.35751918, 0.33167085, 0.007544129, 0.5172352, 0.99095124, 0.73638934, 0.8204628, 0.34836042, 0.3501866, 0.4228037, -0.46107167, 0.5245504, 0.1332714, 0.48995224, 0.8592754, 0.07527029, 0.91453224, 0.53742725, 0.90096647, 0.3769077, -0.8629506, 0.6117356, 0.61197966, 0.2467804, 0.2800367, 0.047195755, 0.6491609, 0.261777, 0.32522804, 0.8958076, -0.7314942, 0.6443233, 0.32141203, 0.7765358, 0.90912837, 0.6428001, 0.85886633, 0.8456446, 0.31409132, 0.09137268, -0.49396735, 0.43484485, 0.17368458, 0.23658675, 0.78541636, 0.47147486, 0.30891126, 0.30575344, 0.040564716, 0.49755472, -0.2910126, 0.48344758, 0.32476038, 0.59433854, 0.39527807, 0.7457836, 0.71969116, 0.76076376, 0.23719852, 0.9437555, -0.087228395, 0.55868584, 0.023132376, 0.45437896, 0.6913095, 0.8167484, 0.20313835, 0.35673562, 0.58082384, 0.2164753, -0.21640398, 0.06888765, 0.22333595, 0.8095938, 0.88294035, 0.42810574, 0.43805102, 0.37539294, 0.46136406, 0.80856186, -0.7382845, 0.34340748, 0.2212123, 0.8276733, 0.60479504, 0.24804658, 0.3195629, 0.7270735, 0.3812577, 0.16334477, -0.92310894, 0.09810257, 0.6084461, 0.37033582, 0.004144284, 0.9352815, 0.41171247, 0.71930563, 0.54527724, 0.968668, -0.2683365, 0.9521756, 0.7249296, 0.8240894, 0.28115076, 0.22212493, 0.26011166, 0.5151666, 0.71139824, 0.9671723, -0.3077326, 0.3442982, 0.29939967, 0.42863667, 0.20547101, 0.7438209, 0.33747354, 0.19545908, 0.8495839, 0.44326293, -0.49718547, 0.4760649, 0.97547793, 0.4174791, 0.29336637, 0.11830141, 0.46044156, 0.85300016, 0.8054495, 0.9476588, -0.016393282, 0.7187454, 0.8301157, 0.49269608, 0.5402253, 0.78610885, 0.6184779, 0.39712286, 0.54652256, 0.3826701, -0.98793495, 0.80439633, 0.015675247, 0.4140854, 0.85561216, 0.5788107, 0.7987029, 0.17980942, 0.16486481, 0.26032335, -0.597808, 0.2162534, 0.86972165, 0.102014296, 0.47148252, 0.7922716, 0.97669774, 0.3074505, 0.53072304, 0.16284934, -0.7616834, 0.40711153, 0.7097171, 0.7637394, 0.950779, 0.58898723, 0.5141825, 0.8067036, 0.88841134, 0.41936216, -0.12534304, 0.94035065, 0.6489365, 0.46691382, 0.45532802, 0.69278914, 0.46038964, 0.56139255, 0.56186694, 0.7145557, -0.31959853, 0.28063214, 0.6881353, 0.54512614, 0.3498508, 0.8001399, 0.8490237, 0.7281014, 0.021213572, 0.7479538, -0.8094111, 0.31102738, 0.8663998, 0.38367322, 0.6209867, 0.5808234, 0.09467922, 0.25193584, 0.46330634, 0.26662496, -0.06462818, 0.99199927, 0.29139808, 0.74550265, 0.13498032, 0.65745735, 0.5673169, 0.40280786, 0.64668626, 0.7786934, -0.33188194, 0.4153052, 0.7455836, 0.8161674, 0.8432508, 0.48105124, 0.7189762, 0.16459095, 0.41388863, 0.15063916, -0.73996353, 0.78608114, 0.78549004, 0.14045759, 0.609951, 0.8143157, 0.07395084, 0.26526332, 0.8459271, 0.8745046, -0.5981099, 0.20845382, 0.098086186, 0.29524195, 0.6499275, 0.32759923, 0.98923403, 0.9426327, 0.41014582, 0.6923934, -0.23282301, 0.44621587, 0.08141512, 0.24252021, 0.4160718, 0.3941059, 0.5654438, 0.050232418, 0.5404224, 0.13993548, -0.8618472, 0.9300883, 0.8380472, 0.31266716, 0.52666146, 0.27854705, 0.20650926, 0.1509405, 0.13555165, 0.32066464, -0.5835065, 0.30205357, 0.5568808, 0.7721817, 0.18058343, 0.123428136, 0.31721902, 0.45034164, 0.16623993, 0.5156516, -0.4918172, 0.7763435, 0.75444514, 0.7214952, 0.91781616, 0.29374766, 0.704666, 0.5429698, 0.7243858, 0.21584511, -0.24887188, 0.02371842, 0.7248409, 0.7059916, 0.012657363, 0.6680217, 0.37040663, 0.785419, 0.7685805, 0.37138042, -0.12108998, 0.83829355, 0.80708104, 0.08948117, 0.108886935, 0.93076944, 0.8893351, 0.30923343, 0.061936773, 0.29264367, -0.07688689, 0.11510216, 0.8839925, 0.02477082, 0.64811826, 0.08550372, 0.17564313, 0.11655201, 0.39485103, 0.23291379, -0.57388103, 0.6635394, 0.42655468, 0.9197065, 0.071792774, 0.5597881, 0.57721263, 0.8508891, 0.75952435, 0.5125618, -0.75302154, 0.53180003, 0.6817611, 0.79485947, 0.3945616, 0.6535236, 0.9692625, 0.66496396, 0.61260825, 0.98704666, -0.40441254, 0.3954326, 0.48103306, 0.43174213, 0.13895822, 0.13376972, 0.13972592, 0.7000701, 0.05787335, 0.92715365, -0.49237853, 0.2538546, 0.390568, 0.5356667, 0.7974994, 0.45755056, 0.41173887, 0.8873745, 0.017688395, 0.54909885, -0.3535568, 0.038445998, 0.54970914, 0.549375, 0.5396221, 0.54508686, 0.43334106, 0.089132994, 0.6302092, 0.99459463, -0.11624123, 0.5106792, 0.50394374, 0.40780434, 0.8285013, 0.17844845, 0.18250638, 0.99481255, 0.7807483, 0.93802303, -0.42006215, 0.87714255, 0.7930158, 0.8323707, 0.020183232, 0.4991669, 0.14123203, 0.1460944, 0.9973601, 0.93701106, -0.24178477, 0.081888, 0.64727557, 0.06350941, 0.6334899, 0.36596653, 0.84572345, 0.931658, 0.89212, 0.59387136, -0.70042866, 0.050592937, 0.06986087, 0.063278705, 0.81091243, 0.98169935, 0.74991083, 0.98276365, 0.7071655, 0.6190509, -0.27504414, 0.41692632, 0.106626175, 0.07966534, 0.12903668, 0.47641423, 0.24543023, 0.71733844, 0.5291918, 0.040455237, -0.40385485, 0.28724664, 0.091772884, 0.69319814, 0.7528099, 0.034353238, 0.8634036, 0.44043434, 0.77431446, 0.46253473, -0.332725, 0.25084835, 0.10269255, 0.18687698, 0.23759438, 0.36946923, 0.8072817, 0.72973704, 0.021458272, 0.038483858, -0.7492561, 0.1584684, 0.43892893, 0.37830916, 0.6619669, 0.8248584, 0.9752618, 0.5676102, 0.93447274, 0.15707563, -0.120536305, 0.12838502, 0.40246627, 0.8516648, 0.19001648, 0.41318202, 0.95882004, 0.3766627, 0.31046882, 0.7765592, -0.11829578, 0.3094765, 0.20844917, 0.24463072, 0.28632593, 0.024195805, 0.31423378, 0.9197492, 0.84207094, 0.75956744, -0.66913253, 0.5156932, 0.6958802, 0.4907079, 0.29119918, 0.24538647, 0.8483177, 0.7134637, 0.031231258, 0.92795146, -0.059091415, 0.29579335, 0.5059616, 0.6172388, 0.34199843, 0.20433997, 0.84838206, 0.2510278, 0.9968605, 0.82441235, -0.41064918, 0.43061897, 0.41926822, 0.2448991, 0.92018807, 0.43977955, 0.95001924, 0.19429821, 0.09198324, 0.63777107, -0.51062465, 0.055512622, 0.72553927, 0.17490527, 0.48794308, 0.60484314, 0.43250486, 0.91175836, 0.5604656, 0.94463, -0.56486434, 0.24535634, 0.34543145, 0.38251737, 0.7174677, 0.82250243, 0.8035149, 0.59121037, 0.9026323, 0.081985965, -0.17581372, 0.06320599, 0.9228887, 0.017658591, 0.3489183, 0.23851357, 0.096424945, 0.45098105, 0.57051986, 0.8514196, -0.29536724, 0.6540195, 0.62148046, 0.39346015, 0.41732678, 0.0035787956, 0.5702541, 0.33105636, 0.12929575, 0.7371553, -0.7718351, 0.93662375, 0.6905622, 0.052230474, 0.25954804, 0.16529284, 0.08518753, 0.03675085, 0.52743137, 0.097685665, -0.6362647, 0.35880888, 0.2916659, 0.009997273, 0.46195737, 0.4474187, 0.13262391, 0.7078807, 0.825987, 0.24942951, -0.5084182, 0.9815238, 0.3412385, 0.70904595, 0.6492628, 0.9108448, 0.62387586, 0.9519713, 0.9651906, 0.71388894, -0.25224832, 0.4724585, 0.4619146, 0.16547702, 0.31015086, 0.23919, 0.37264377, 0.8706582, 0.7581105, 0.18362544, -0.15332605, 0.05967409, 0.9235497, 0.47283417, 0.21515496, 0.93655837, 0.3623536, 0.6114832, 0.93150276, 0.9699081, -0.8709549, 0.8623734, 0.5050694, 0.87986624, 0.2287371, 0.7903113, 0.5953852, 0.98151624, 0.40296772, 0.34870324, -0.541417, 0.13321623, 0.07156025, 0.81354237, 0.84543735, 0.16380614, 0.8968943, 0.12618889, 0.6998464, 0.22276738, -0.07477489, 0.2619657, 0.94977015, 0.6423615, 0.09610346, 0.4487441, 0.05797409, 0.8684043, 0.49389097, 0.7127044, -0.54849124, 0.012392659, 0.020468513, 0.99528253, 0.8429341, 0.3898749, 0.96738917, 0.58204836, 0.9367399, 0.5198395, -0.6438048, 0.39112753, 0.46769053, 0.40940732, 0.64220846, 0.02010981, 0.9881138, 0.11000732, 0.6273968, 0.051348828, -0.039664086, 0.2361647, 0.91163677, 0.7087354, 0.8951332, 0.6089892, 0.91260326, 0.86270785, 0.7837628, 0.779993, -0.73233724, 0.72698087, 0.48762527, 0.69026333, 0.800212, 0.5290243, 0.11274772, 0.07627774, 0.9706083, 0.45556244, -0.19641699, 0.31484595, 0.18944897, 0.18000686, 0.5789626, 0.6836474, 0.79427516, 0.54036283, 0.00015307916, 0.07599365, -0.46063024, 0.94796675, 0.24100749, 0.44254217, 0.67304033, 0.31232652, 0.10075587, 0.31173313, 0.100149296, 0.23394488, -0.47727165, 0.10468131, 0.79828554, 0.1567469, 0.78750235, 0.9168239, 0.9035022, 0.7774272, 0.6091953, 0.11318414, -0.9073621, 0.9118361, 0.139399, 0.17183441, 0.85493183, 0.7248181, 0.04671574, 0.7316299, 0.1297728, 0.21148583, -0.814714, 0.37224042, 0.8625547, 0.70776916, 0.31936276, 0.7843705, 0.4859734, 0.04508312, 0.017223012, 0.4878855, -0.42826846, 0.8010146, 0.97612846, 0.73666346, 0.9782908, 0.09173568, 0.51656044, 0.032702066, 0.3925045, 0.6621387, -0.7801451, 0.01684795, 0.93116754, 0.886969, 0.16863157, 0.54879415, 0.80856776, 0.06917309, 0.5876103, 0.94822216, -0.26561078, 0.36912593, 0.18196031, 0.8886635, 0.41923082, 0.1050312, 0.24212655, 0.09051639, 0.8373841, 0.0031318855, -0.4308505, 0.8584191, 0.7602042, 0.121309794, 0.68491566, 0.10634747, 0.9357077, 0.4027356, 0.19354361, 0.7631962, -0.2082577, 0.014013676, 0.3391254, 0.46763408, 0.43134072, 0.7978661, 0.44107288, 0.9755858, 0.5391376, 0.7705686, -0.9758027, 0.4168003, 0.4574728, 0.06900084, 0.22227472, 0.059142508, 0.6190543, 0.08746498, 0.3174326, 0.8732596, -0.84960914, 0.42604402, 0.19531794, 0.38937265, 0.2312882, 0.921726, 0.25664374, 0.8098577, 0.20205325, 0.06228409, -0.61308646, 0.40583217, 0.8756295, 0.8244142, 0.7399645, 0.2515971, 0.030000538, 0.7143262, 0.45732272, 0.6213647, -0.6639583, 0.26654074, 0.5513788, 0.0668155, 0.02732918, 0.014050223, 0.40094635, 0.69120336, 0.8990351, 0.6257732, -0.48729318, 0.8482427, 0.08530297, 0.320284, 0.91358703, 0.7822137, 0.8186957, 0.94975275, 0.2363459, 0.50961477, -0.54122233, 0.63121516, 0.77353257, 0.4768535, 0.15748215, 0.56997055, 0.54117084, 0.6330586, 0.32903638, 0.9706776, -0.02914197, 0.90472806, 0.6301423, 0.69606787, 0.20930128, 0.5830684, 0.8746652, 0.12850243, 0.36204344, 0.21723796, -0.5207796, 0.5654404, 0.9108227, 0.57628006, 0.5749909, 0.7648438, 0.3205292, 0.5553455, 0.91082716, 0.9577508, -0.43290135, 0.08024777, 0.47798032, 0.94770795, 0.0801424, 0.03274318, 0.49300817, 0.07452531, 0.90933335, 0.45735866, -0.4728794, 0.7678877, 0.362167, 0.9283575, 0.5966312, 0.5825651, 0.21810043, 0.3892351, 0.11098274, 0.33051863, -0.9075484, 0.6901933, 0.5877093, 0.019107932, 0.9888351, 0.9757819, 0.72039247, 0.19725248, 0.90186256, 0.39263836, -0.24944134, 0.98582536, 0.72223145, 0.3712856, 0.5377763, 0.9488942, 0.42674774, 0.68243426, 0.6159255, 0.1765581, -0.09006023, 0.8001399, 0.21916907, 0.9046848, 0.74435854, 0.7528919, 0.20327342, 0.9824652, 0.9796489, 0.9924258, -0.5467434, 0.9312941, 0.44436273, 0.58030856, 0.05020233, 0.742708, 0.49253845, 0.4588724, 0.95887285, 0.10436046, -0.31235072, 0.29575568, 0.17266272, 0.516695, 0.20791732, 0.48705408, 0.045656245, 0.9908814, 0.3905812, 0.647737, -0.15581739, 0.5356661, 0.77330965, 0.93442464, 0.2404584, 0.10740854, 0.47102425, 0.6830245, 0.27474937, 0.2359432, -0.7725085, 0.73792726, 0.21760361, 0.9094368, 0.845895, 0.31814724, 0.5414626, 0.14192294, 0.32108325, 0.7950682, -0.45635575, 0.96787536, 0.72356147, 0.511565, 0.8642074, 0.79430455, 0.62747717, 0.70247406, 0.6967675, 0.2573045, -0.7072357, 0.212392, 0.591884, 0.33191186, 0.8366084, 0.01107724, 0.15798447, 0.5099381, 0.33985013, 0.9427938, -0.27168378, 0.8095139, 0.18412302, 0.72292966, 0.33185193, 0.5744235, 0.078152075, 0.2632259, 0.67080003, 0.8897701, -0.94559145, 0.9037333, 0.66979814, 0.595513, 0.19138126, 0.18794204, 0.8121047, 0.26174462, 0.07021725, 0.44615385, -0.47993135, 0.76855016, 0.986257, 0.017444894, 0.5287075, 0.5601165, 0.1460432, 0.88569176, 0.07282839, 0.8348177, -0.16016278, 0.031524524, 0.80207276, 0.37828946, 0.52338445, 0.6468418, 0.7837523, 0.00063179433, 0.17971309, 0.2897839, -0.7161524, 0.3642513, 0.031674027, 0.8069974, 0.31171304, 0.8035024, 0.54259384, 0.9963711, 0.14053062, 0.6486664, -0.19897254, 0.8962398, 0.43972084, 0.8936963, 0.46286246, 0.5031336, 0.8232569, 0.16667813, 0.19422211, 0.7717354, -0.42838028, 0.19246033, 0.19039753, 0.8359823, 0.7296073, 0.9140669, 0.10166052, 0.29150867, 0.07212853, 0.54453945, -0.40418974, 0.8114729, 0.08203155, 0.78043336, 0.7300014, 0.11568007, 0.73687613, 0.1792596, 0.70573187, 0.7252052, -0.017522655, 0.14967212, 0.7451611, 0.42416203, 0.6358452, 0.26392296, 0.59180367, 0.9083765, 0.915427, 0.020250821, -0.8235849, 0.6170742, 0.80640966, 0.40797767, 0.86140364, 0.52369213, 0.17385374, 0.19569172, 0.07739012, 0.3976461, -0.70184183, 0.2510852, 0.92424256, 0.59599113, 0.24447663, 0.38749963, 0.81420827, 0.6592875, 0.16369487, 0.34718236, -0.76625746, 0.6439973, 0.46094626, 0.46901694, 0.75421274, 0.27870816, 0.44729918, 0.76623553, 0.20013711, 0.46568435, -0.32226324, 0.193284, 0.37608168, 0.051877704, 0.72095454, 0.7871155, 0.0050632227, 0.6740539, 0.9190297, 0.20630927, -0.94182634, 0.5411844, 0.10186948, 0.30808574, 0.023363324, 0.7664375, 0.22542956, 0.14916998, 0.17968538, 0.24834555, -0.44971466, 0.93251616, 0.74468166, 0.56824464, 0.25399336, 0.17958756, 0.15612793, 0.33739275, 0.6537649, 0.5826955, -0.07639295, 0.40761822, 0.9955546, 0.6117058, 0.07538286, 0.50855786, 0.8750035, 0.8723649, 0.8750366, 0.4573611, -0.38243642, 0.1401544, 0.7402578, 0.9573856, 0.40535605, 0.22507304, 0.54212785, 0.1528605, 0.44565362, 0.98777527, -0.05327858, 0.2981292, 0.5865501, 0.9517916, 0.015969688, 0.38974705, 0.44860238, 0.807837, 0.79788435, 0.541367, -0.6309876, 0.6676705, 0.02028897, 0.33633423, 0.12991633, 0.5342081, 0.5456298, 0.4901637, 0.2327029, 0.5148055, -0.89143395, 0.35306472, 0.27413338, 0.7223243, 0.86590916, 0.30956024, 0.1922584, 0.787296, 0.1628886, 0.02892033, -0.6374597, 0.0032674163, 0.89173913, 0.66598964, 0.5294169, 0.77826375, 0.8210681, 0.043763056, 0.5957361, 0.6856358, -0.05995547, 0.06716649, 0.07448051, 0.3336696, 0.8263735, 0.7147659, 0.11986544, 0.40392354, 0.8274693, 0.87114793, -0.67944324, 0.051964145, 0.9201576, 0.9308481, 0.096341334, 0.70021385, 0.02399584, 0.8642258, 0.08588241, 0.70640945, -0.19748867, 0.6613063, 0.6449484, 0.768964, 0.9039073, 0.6277202, 0.77593136, 0.35429934, 0.8069173, 0.3516526, -0.71314, 0.50186676, 0.8944276, 0.5470671, 0.45485002, 0.82426745, 0.2785842, 0.9404638, 0.8959508, 0.15114321, -0.18969482, 0.78833485, 0.9598267, 0.29174066, 0.3494771, 0.5854956, 0.0831098, 0.960891, 0.56964827, 0.829203, -0.7542679, 0.9568423, 0.9578806, 0.88932663, 0.48814714, 0.39864913, 0.42221805, 0.3055165, 0.42976233, 0.19865331, -0.93883455, 0.7655661, 0.5970062, 0.4758167, 0.15800795, 0.17757647, 0.15753652, 0.3730905, 0.47599813, 0.27207386, -0.42162967, 0.08353208, 0.96827507, 0.9347392, 0.51671463, 0.40915382, 0.7014796, 0.35320777, 0.4194869, 0.3184117, -0.5446104, 0.81504035, 0.78465104, 0.9777143, 0.5973847, 0.7562977, 0.54398614, 0.0051009622, 0.05891997, 0.05620089, -0.4020494, 0.9730677, 0.5107014, 0.69729745, 0.21230865, 0.4241287, 0.19132863, 0.48401004, 0.1337327, 0.17190064, -0.42795905, 0.7100193, 0.48489287, 0.29757443, 0.40757337, 0.67073584, 0.98856723, 0.023141444, 0.37261203, 0.07899332, -0.6971695, 0.06901029, 0.8860296, 0.11135061, 0.65404296, 0.12379419, 0.98091507, 0.6192919, 0.878432, 0.40171024, -0.63359034, 0.15243557, 0.31417054, 0.41979724, 0.87002444, 0.44856197, 0.5728306, 0.2709776, 0.7224305, 0.09258589, -0.21782517, 0.21746957, 0.21947508, 0.24758625, 0.8904527, 0.8345911, 0.3301475, 0.48707664, 0.57014096, 0.92664886, -0.7677305, 0.5208447, 0.6324889, 0.97992665, 0.35903138, 0.3330391, 0.0870381, 0.39935082, 0.043254532, 0.08851445, -0.44321367, 0.57203674, 0.60557806, 0.73202246, 0.5383103, 0.27552348, 0.39584875, 0.06509563, 0.42754996, 0.95901144, -0.09790518, 0.7175897, 0.3007109, 0.28002614, 0.86116815, 0.47969994, 0.8495352, 0.63844335, 0.22089794, 0.8194518, -0.7936467, 0.4938384, 0.049150985, 0.9517831, 0.6339798, 0.11274567, 0.51994663, 0.3342439, 0.060765848, 0.53698534, -0.36152387, 0.17347981, 0.22772305, 0.6339161, 0.6493722, 0.64578843, 0.6118915, 0.48745263, 0.70927596, 0.6149292, -0.43874234, 0.26505187, 0.05952667, 0.6111295, 0.8287437, 0.050140806, 0.22013378, 0.35246277, 0.1187585, 0.87933147, -0.4835039, 0.44859475, 0.1784529, 0.2238027, 0.29486778, 0.9493753, 0.52288574, 0.65379494, 0.09804267, 0.42556462, -0.75557685, 0.061604857, 0.0043297815, 0.8905646, 0.59748757, 0.92442536, 0.4898666, 0.6667948, 0.6306539, 0.21537969, -0.8678084, 0.3620826, 0.9291674, 0.6059688, 0.3807095, 0.5285948, 0.43431175, 0.43802148, 0.123039424, 0.583839, -0.8926119, 0.16748385, 0.2154854, 0.18143441, 0.05348144, 0.9129291, 0.99502695, 0.003920352, 0.33904833, 0.69999695, -0.12290272, 0.9580966, 0.38940993, 0.2837113, 0.85935235, 0.37713748, 0.2607221, 0.16896206, 0.013641968, 0.90431833, -0.5602742, 0.553339, 0.72180885, 0.9033788, 0.011523027, 0.1214213, 0.51942736, 0.57248414, 0.8430932, 0.76627296, -0.5150635, 0.084864266, 0.5307555, 0.51420367, 0.5329527, 0.588093, 0.84611946, 0.82289535, 0.83708316, 0.68455845, -0.9293985, 0.48594627, 0.32774645, 0.930657, 0.092476964, 0.9097118, 0.97267264, 0.6454561, 0.74661636, 0.003572011, -0.2678727, 0.2653497, 0.4243795, 0.2187211, 0.023564778, 0.3392729, 0.44567502, 0.31210658, 0.16991138, 0.9320601, -0.39350176, 0.42254278, 0.16082714, 0.57277536, 0.18493341, 0.03803846, 0.4273411, 0.87520623, 0.7507586, 0.27125937, -0.531018, 0.43782672, 0.33187887, 0.32908353, 0.97491986, 0.07432794, 0.22559255, 0.7911518, 0.8109018, 0.10181122, -0.14874865, 0.8739713, 0.8258678, 0.83952117, 0.49840027, 0.24971384, 0.6604848, 0.3120344, 0.4906389, 0.19367984, -0.14241797, 0.5340129, 0.65298396, 0.90502304, 0.2910567, 0.50685567, 0.3251191, 0.7549711, 0.7457236, 0.054438505, -0.4823707, 0.09746641, 0.8946975, 0.47535703, 0.472554, 0.83004594, 0.9334708, 0.09529597, 0.24380124, 0.9492368, -0.11368034, 0.6545232, 0.5012047, 0.06810016, 0.7833115, 0.5195305, 0.59667504, 0.32130596, 0.07437508, 0.9352196, -0.3775537, 0.11530671, 0.38456735, 0.5570788, 0.12884142, 0.9970051, 0.7848427, 0.42685586, 0.03802683, 0.4680642, -0.7492088, 0.47062147, 0.045428254, 0.75646335, 0.6194405, 0.05128224, 0.9792738, 0.35051075, 0.3669672, 0.66835433, -0.31624305, 0.56518877, 0.06823316, 0.5414021, 0.0799995, 0.4878948, 0.032808155, 0.5848838, 0.12171154, 0.7715262, -0.9101807, 0.0038131434, 0.680596, 0.810504, 0.67688483, 0.36706397, 0.7128991, 0.3376187, 0.3465156, 0.47554886, -0.04520323, 0.5066149, 0.05726915, 0.77573705, 0.200028, 0.6430589, 0.6090949, 0.7447414, 0.44865963, 0.73202926, -0.5402566, 0.24616429, 0.9543388, 0.40602076, 0.61897653, 0.8123649, 0.047073558, 0.8431653, 0.47707924, 0.6409466, -0.964197, 0.1999589, 0.3051443, 0.2665006, 0.5578835, 0.7453957, 0.7900255, 0.23492423, 0.07957853, 0.25237653, -0.33838317, 0.6416551, 0.0039951354, 0.89141834, 0.62315106, 0.80962807, 0.50791967, 0.29249611, 0.34137407, 0.4369406, -0.8787999, 0.28806677, 0.1362242, 0.3896823, 0.23126958, 0.66401637, 0.049474377, 0.27457523, 0.19152752, 0.8645199, -0.31999043, 0.8697338, 0.8605395, 0.70556897, 0.5113519, 0.84524435, 0.20147063, 0.79076856, 0.21785353, 0.4546323, -0.8530334, 0.3741707, 0.66516286, 0.1962831, 0.3936461, 0.89860153, 0.24216916, 0.062920436, 0.7828697, 0.8093484, -0.30444527, 0.75457746, 0.5017912, 0.040138636, 0.7621467, 0.6761302, 0.06373471, 0.915462, 0.035231, 0.89386714, -0.6959213, 0.51545024, 0.04339671, 0.21505861, 0.9323861, 0.46864936, 0.7811156, 0.29842615, 0.38006642, 0.7779068, -0.60815746, 0.7171511, 0.07464257, 0.88674176, 0.5839072, 0.5046292, 0.6229039, 0.9399411, 0.9960362, 0.33266804, -0.42184722, 0.9865539, 0.49170554, 0.38217908, 0.5600747, 0.565413, 0.36794263, 0.82040083, 0.94342226, 0.8352217, -0.78150964, 0.2860086, 0.75553757, 0.32398638, 0.758711, 0.3375832, 0.33077398, 0.45010427, 0.26389697, 0.92499673, -0.11748593, 0.943743, 0.682854, 0.004962936, 0.20119096, 0.58729416, 0.67993486, 0.6150494, 0.45623145, 0.25751752, -0.053226303, 0.12379362, 0.91942585, 0.702563, 0.47201994, 0.7093674, 0.023744669, 0.66121763, 0.65498394, 0.36697313, -0.10070673, 0.96071476, 0.3550039, 0.54484475, 0.99639714, 0.32214886, 0.96161354, 0.7506562, 0.12803078, 0.24632397, -0.17385522, 0.17279965, 0.6760441, 0.071039446, 0.2151821, 0.4781042, 0.30369994, 0.48674262, 0.18098812, 0.97278047, -0.8854781, 0.7528932, 0.3641694, 0.68590474, 0.7819954, 0.657716, 0.36658275, 0.05297459, 0.85196644, 0.049343612, -0.31383854, 0.6695563, 0.7951203, 0.89692384, 0.82429004, 0.15677115, 0.5887391, 0.13800927, 0.0085657975, 0.8790421, -0.6256806, 0.9292787, 0.48701864, 0.20990747, 0.083662316, 0.88042665, 0.4477495, 0.8483864, 0.48738086, 0.99391574, -0.40566745, 0.537002, 0.4802295, 0.6822035, 0.48149505, 0.34781352, 0.5965454, 0.66909915, 0.76284933, 0.33868113, -0.9555661, 0.90863895, 0.89868975, 0.07868716, 0.93248546, 0.50429887, 0.37767935, 0.77912027, 0.24674945, 0.05841095, -0.8893651, 0.16569066, 0.4781768, 0.301946, 0.34709984, 0.9561994, 0.26587456, 0.15426192, 0.6022424, 0.9015687, -0.20996648, 0.51819634, 0.5655937, 0.8580507, 0.64367616, 0.7768365, 0.18932684, 0.11291685, 0.4154288, 0.4764765, -0.5602257, 0.91964, 0.37515992, 0.6698847, 0.923476, 0.7170417, 0.030588947, 0.40833148, 0.27742204, 0.57936347, -0.5027473, 0.6686292, 0.60163695, 0.42896992, 0.10455062, 0.2399768, 0.058825243, 0.17828348, 0.3351036, 0.5252956, -0.08193896, 0.44228348, 0.06685673, 0.8612806, 0.12871465, 0.43736976, 0.34304523, 0.040639006, 0.435011, 0.15564895, -0.314972, 0.2647625, 0.36369145, 0.770273, 0.4981852, 0.96972513, 0.79053074, 0.80829215, 0.37847006, 0.63005817, -0.9256105, 0.85754305, 0.8768399, 0.022878975, 0.3988214, 0.54133725, 0.9165594, 0.1366238, 0.7535001, 0.40369937, -0.71801126, 0.011043364, 0.77781326, 0.89013314, 0.39453754, 0.11794228, 0.85278326, 0.5138793, 0.54117, 0.4861062, -0.37399647, 0.98994994, 0.9733205, 0.12177309, 0.26439142, 0.23798482, 0.30493778, 0.83136404, 0.9307847, 0.13482551, -0.44944605, 0.25053307, 0.7998134, 0.70504546, 0.5996852, 0.22439589, 0.5654436, 0.043977752, 0.4624592, 0.5873774, -0.52081037, 0.20642142, 0.2871389, 0.031311635, 0.43763772, 0.30392867, 0.48694924, 0.4735583, 0.37573543, 0.3802429, -0.11694187, 0.27665144, 0.26712215, 0.89236385, 0.25606167, 0.93566054, 0.8842226, 0.7550668, 0.7584876, 0.16083659, -0.23639946, 0.08519537, 0.20583908, 0.6186746, 0.9542533, 0.46747816, 0.21122995, 0.07276781, 0.29044798, 0.17014165, -0.5524987, 0.8088055, 0.0514201, 0.9537926, 0.9652958, 0.16757506, 0.70281106, 0.94200885, 0.6841354, 0.96046275, -0.7510356, 0.8313795, 0.45562857, 0.5505418, 0.017883644, 0.17279461, 0.9834109, 0.90744954, 0.44898376, 0.66402465, -0.34017327, 0.81037676, 0.28549019, 0.3016226, 0.35097796, 0.43561503, 0.00058234343, 0.6684643, 0.07705832, 0.97015953, -0.092698716, 0.41418144, 0.18311031, 0.20559378, 0.82774425, 0.30813637, 0.22523133, 0.31332958, 0.92706805, 0.08848662, -0.23284948, 0.9422138, 0.07093142, 0.7980248, 0.409801, 0.40501997, 0.6295668, 0.6552973, 0.600791, 0.7814587, -0.48406723, 0.3037804, 0.62378407, 0.62642336, 0.82996833, 0.7421219, 0.5233153, 0.74979746, 0.6028146, 0.5296808, -0.16699271, 0.03434674, 0.86495054, 0.71397585, 0.86776406, 0.33685416, 0.6482692, 0.2500348, 0.7227976, 0.70974725, -0.9475633, 0.6700813, 0.9803815, 0.36049715, 0.43117517, 0.39795953, 0.7394454, 0.4874654, 0.8918216, 0.94595796, -0.8060482, 0.3452851, 0.06767335, 0.29559964, 0.4860923, 0.7889183, 0.7903974, 0.556687, 0.3756254, 0.08562232, -0.7848211, 0.47543386, 0.71051496, 0.3973873, 0.9214939, 0.19850273, 0.07726323, 0.3569556, 0.9302608, 0.072946854, -0.7567508, 0.37953198, 0.9324997, 0.89104366, 0.8338954, 0.8139859, 0.32339892, 0.2632869, 0.19524816, 0.43200883, -0.002676534, 0.035849903, 0.8579759, 0.65685666, 0.7236325, 0.82170767, 0.9666734, 0.5693509, 0.22788355, 0.07884572, -0.54645675, 0.09158218, 0.8744094, 0.63717526, 0.9249262, 0.47212943, 0.9595664, 0.58299416, 0.43900326, 0.23267244, -0.3206963, 0.3824898, 0.55720466, 0.8188748, 0.18920717, 0.42651626, 0.41278538, 0.17662966, 0.46170422, 0.6721064, -0.4655194, 0.5271105, 0.3614388, 0.94361657, 0.08294579, 0.74897116, 0.617458, 0.053658314, 0.67375475, 0.09978627, -0.23182935, 0.50791234, 0.12907204, 0.85141504, 0.5264901, 0.66516864, 0.50512254, 0.29532441, 0.9661175, 0.36176598, -0.8544195, 0.7404047, 0.82428366, 0.96257573, 0.11131253, 0.62018675, 0.47864527, 0.039101128, 0.46764946, 0.29711628, -0.40892226, 0.7900437, 0.10764668, 0.55577713, 0.6133263, 0.019346252, 0.73014337, 0.9307928, 0.5542295, 0.17595504, -0.8546715, 0.90590805, 0.9092394, 0.33921698, 0.0008430821, 0.81278396, 0.25341776, 0.7057896, 0.29238465, 0.52403855, -0.9213937, 0.11746097, 0.21051219, 0.09993823, 0.8176869, 0.72511464, 0.70282686, 0.3988631, 0.83230406, 0.46275905, -0.2703259, 0.57835686, 0.58600885, 0.3766385, 0.690864, 0.44178563, 0.40026566, 0.5732949, 0.23808873, 0.50714386, -0.9350253, 0.57432973, 0.74109495, 0.79016244, 0.5070945, 0.9485114, 0.8311653, 0.48506665, 0.9617326, 0.29852858, -0.366769, 0.77285564, 0.74671644, 0.94361097, 0.3757226, 0.29146126, 0.57953155, 0.007708449, 0.7380902, 0.88821167, -0.31651938, 0.33128026, 0.09848877, 0.09147043, 0.90562916, 0.27631462, 0.31989923, 0.53260094, 0.648353, 0.5590575, -0.4125183, 0.68012285, 0.4677009, 0.7852408, 0.5890133, 0.34706393, 0.37636602, 0.42034975, 0.5928437, 0.86917543, -0.89394933, 0.21776019, 0.43713045, 0.5337755, 0.09599007, 0.49747026, 0.83164036, 0.6423979, 0.00091591524, 0.39940274, -0.8622541, 0.3925572, 0.83520466, 0.3498771, 0.19062445, 0.603745, 0.475841, 0.6496245, 0.8845333, 0.2307799, -0.6286122, 0.29856437, 0.83671373, 0.40267518, 0.8860103, 0.6866461, 0.30515477, 0.9614757, 0.3545977, 0.028658632, -0.9150952, 0.15918177, 0.41486475, 0.8689148, 0.9942623, 0.0987592, 0.8941498, 0.5647133, 0.99548036, 0.40815887, -0.44467425, 0.6775013, 0.531685, 0.24895021, 0.69680333, 0.019961093, 0.8449182, 0.1178238, 0.59461635, 0.98526824, -0.871223, 0.7267415, 0.53581643, 0.3620638, 0.24056326, 0.59538496, 0.38104647, 0.034455262, 0.6477652, 0.40934396, -0.19231549, 0.8701647, 0.28780022, 0.97225726, 0.48430753, 0.7030723, 0.9776925, 0.9662899, 0.3556148, 0.09186526, -0.7095952, 0.9111277, 0.65414417, 0.47637445, 0.78610563, 0.9511109, 0.7668794, 0.5877635, 0.7058718, 0.8660492, -0.8417279, 0.18733096, 0.3668593, 0.36932942, 0.15743567, 0.18835372, 0.62336534, 0.05280094, 0.6283515, 0.3988773, -0.7177127, 0.85969454, 0.9169481, 0.5861364, 0.21584338, 0.5745095, 0.3897011, 0.55942774, 0.7646427, 0.993731, -0.042268623, 0.8786283, 0.762209, 0.5027511, 0.27567303, 0.9600953, 0.072597355, 0.059442017, 0.57595813, 0.2894524, -0.82850564, 0.793283, 0.32858342, 0.78171605, 0.56761605, 0.0049845274, 0.50330544, 0.9184708, 0.8148216, 0.29595378, -0.07970701, 0.92489153, 0.33793837, 0.9567375, 0.37415254, 0.84990066, 0.9941796, 0.06800775, 0.26053104, 0.21159613, -0.5614098, 0.20745164, 0.8231208, 0.7121408, 0.82378054, 0.9630996, 0.42512196, 0.8641082, 0.09365638, 0.19734041, -0.11575636, 0.5639233, 0.4768428, 0.33889914, 0.5703717, 0.9244297, 0.5311111, 0.13523202, 0.01852037, 0.21085885, -0.071204096, 0.4712303, 0.74460614, 0.4686889, 0.914024, 0.117377095, 0.54068995, 0.80547154, 0.12859856, 0.4257724, -0.9659156, 0.0045896024, 0.798911, 0.36436203, 0.7280426, 0.621054, 0.9701622, 0.6164426, 0.9579355, 0.6045164, -0.5798626, 0.63919723, 0.82481444, 0.61748123, 0.18019743, 0.5157837, 0.44804874, 0.99903923, 0.3863658, 0.44972283, -0.31878954, 0.85894763, 0.049487386, 0.04967219, 0.14039204, 0.09017946, 0.4628455, 0.3544319, 0.7981168, 0.70640343, -0.42240968, 0.6196504, 0.73550963, 0.667884, 0.23142478, 0.11116676, 0.7650123, 0.112480775, 0.6108565, 0.9493177, -0.9542675, 0.9146685, 0.17729652, 0.41400397, 0.6309963, 0.43200687, 0.6464159, 0.12712492, 0.2884915, 0.3982403, -0.66932833, 0.54165065, 0.4191057, 0.67887574, 0.10698286, 0.10696802, 0.9551022, 0.7492388, 0.22396998, 0.63786316, -0.15820846, 0.6157303, 0.8183258, 0.25153205, 0.18210672, 0.9602121, 0.9036876, 0.15693043, 0.38605642, 0.06903067, -0.7507714, 0.33556795, 0.38818276, 0.43704808, 0.4954553, 0.40412104, 0.6816511, 0.63548344, 0.4186759, 0.70838517, -0.44376358, 0.3357206, 0.06594042, 0.39987648, 0.037075095, 0.88075906, 0.20054473, 0.05663389, 0.5609011, 0.124456756, -0.15606454, 0.015773552, 0.88851076, 0.9729933, 0.79110926, 0.33853722, 0.09634267, 0.9257645, 0.23189723, 0.6707842, -0.52831924, 0.48948547, 0.7410685, 0.2194608, 0.6474689, 0.3337604, 0.15346791, 0.98205763, 0.18342042, 0.70286185, -0.42531693, 0.3196188, 0.3305629, 0.5155848, 0.19409959, 0.82248783, 0.5497899, 0.41844934, 0.21445695, 0.3013477, -0.7596674, 0.8470537, 0.5960293, 0.26159966, 0.91296613, 0.7349978, 0.44705716, 0.41518942, 0.6459388, 0.1569181, -0.30777836, 0.7558866, 0.4035862, 0.7478917, 0.18006596, 0.9542781, 0.5946521, 0.8464796, 0.75240755, 0.7033147, -0.7272911, 0.2184871, 0.87321347, 0.8580393, 0.69913983, 0.83644575, 0.68521065, 0.372926, 0.77889377, 0.96862143, -0.7887473, 0.67789334, 0.7113075, 0.93054956, 0.9111168, 0.6812655, 0.89345616, 0.47946882, 0.30649468, 0.9124711, -0.88670325, 0.7382785, 0.33611885, 0.026502334, 0.39508346, 0.6694303, 0.9160326, 0.5826711, 0.33551884, 0.23982148, -0.22783574, 0.70331025, 0.6660418, 0.51114225, 0.57405657, 0.5411803, 0.9738403, 0.73799, 0.5624598, 0.07652036, -0.04978715, 0.07413118, 0.6362957, 0.6773174, 0.36817077, 0.629885, 0.044579085, 0.47303665, 0.836775, 0.49880046, -0.06082195, 0.115183294, 0.53998494, 0.83993644, 0.81661147, 0.98901266, 0.88236827, 0.84671116, 0.46295583, 0.029709496, -0.9204132, 0.10253954, 0.03740714, 0.5390723, 0.74078566, 0.08543706, 0.011851499, 0.20016527, 0.356493, 0.36993647, -0.70742524, 0.15546617, 0.917009, 0.22997431, 0.86268395, 0.81257206, 0.1019828, 0.65880144, 0.6583316, 0.7651984, -0.6248512, 0.44299594, 0.74589616, 0.8367184, 0.17899951, 0.11265245, 0.16332534, 0.8261054, 0.6945308, 0.5850439, -0.65881205, 0.12712914, 0.27503416, 0.53275037, 0.15610719, 0.9472476, 0.036724042, 0.0972234, 0.9365317, 0.2827337, -0.6180335, 0.8444138, 0.116543666, 0.46683854, 0.7913752, 0.9053558, 0.19817433, 0.3100106, 0.9772525, 0.0040394296, -0.8870298, 0.22356682, 0.18837956, 0.6977574, 0.40485826, 0.47741726, 0.35664338, 0.20068875, 0.36007276, 0.62813324, -0.92211175, 0.1857461, 0.5056345, 0.7714491, 0.7111244, 0.5802961, 0.880432, 0.3842586, 0.07386713, 0.9154364, -0.775848, 0.0047594067, 0.7222697, 0.37559786, 0.14716488, 0.7804374, 0.32645226, 0.27905762, 0.04534316, 0.27364373, -0.9144781, 0.8533147, 0.84885293, 0.6904914, 0.6980141, 0.43524522, 0.93874955, 0.57727677, 0.1278921, 0.67868996, -0.5906042, 0.8360353, 0.73715067, 0.30839851, 0.360622, 0.43228745, 0.33877933, 0.3450946, 0.7557141, 0.21107915, -0.024923787, 0.8139157, 0.23614348, 0.061816096, 0.22819144, 0.88227046, 0.5012971, 0.8127817, 0.55059254, 0.6244208, -0.15096499, 0.07758577, 0.15534559, 0.08642902, 0.7136551, 0.068797, 0.33689317, 0.8151431, 0.073435, 0.27587917, -0.6415465, 0.30315524, 0.25636652, 0.3951772, 0.32483214, 0.9398127, 0.26760876, 0.41387123, 0.014975904, 0.7148774, -0.4416581, 0.9813577, 0.5233435, 0.83426404, 0.24871995, 0.100562416, 0.6171712, 0.78703684, 0.4622999, 0.8157436, -0.93394816, 0.1259679, 0.026684225, 0.50347126, 0.527725, 0.5130184, 0.6806897, 0.6507216, 0.59474343, 0.29182497, -0.09539426, 0.52363616, 0.27165958, 0.47983494, 0.56953263, 0.72176856, 0.5575492, 0.8409663, 0.73698395, 0.28837872, -0.6146617, 0.08742587, 0.7978058, 0.8357151, 0.18276273, 0.16960731, 0.55424225, 0.32108158, 0.83770907, 0.61309266, -0.45162576, 0.54985636, 0.35284323, 0.25769138, 0.34193105, 0.5155786, 0.27647102, 0.75289524, 0.86745226, 0.8118137, -0.259123, 0.61688715, 0.8191278, 0.7231509, 0.6194832, 0.9180219, 0.7096981, 0.043508567, 0.26473138, 0.5269514, -0.5430132, 0.77620494, 0.05005288, 0.1739212, 0.20108196, 0.8465223, 0.32816213, 0.19096912, 0.32070854, 0.35811764, -0.9587762, 0.3596081, 0.81301254, 0.9816507, 0.84019923, 0.54553795, 0.17079297, 0.013968218, 0.13790388, 0.053954035, -0.44529754, 0.80465394, 0.9735141, 0.92517024, 0.029255724, 0.99777454, 0.26829806, 0.07465485, 0.21623193, 0.2647408, -0.45990923, 0.5107337, 0.056350194, 0.31075767, 0.07007945, 0.6754208, 0.49980345, 0.17892201, 0.056609415, 0.4954088, -0.18741646, 0.08550189, 0.4321867, 0.5093346, 0.85303754, 0.89951485, 0.8038746, 0.8374771, 0.88295174, 0.073945254, -0.7472289, 0.69572985, 0.90560466, 0.21077734, 0.08165387, 0.7383593, 0.80269086, 0.12488264, 0.14466548, 0.20330743, -0.5782242, 0.2535073, 0.9747372, 0.055967752, 0.8982084, 0.44804245, 0.30325794, 0.50225484, 0.91157126, 0.16477837, -0.045734458, 0.99187094, 0.9573588, 0.6424951, 0.8665376, 0.35979563, 0.37246728, 0.46417946, 0.0721327, 0.12974085, -0.19389993, 0.430821, 0.19170313, 0.14228667, 0.51751184, 0.76417935, 0.605129, 0.8455728, 0.2291038, 0.3317202, -0.87272996, 0.37492082, 0.034256544, 0.853302, 0.9171846, 0.9339092, 0.11076469, 0.37621894, 0.6111262, 0.40499508, -0.5962569, 0.30161974, 0.92590576, 0.7181733, 0.028210793, 0.755358, 0.7383711, 0.2631096, 0.34423977, 0.7218582, -0.365892, 0.3385114, 0.05274994, 0.014924624, 0.0094075035, 0.1474032, 0.061804168, 0.8324505, 0.5384559, 0.13402902, -0.84291345, 0.45768508, 0.27315107, 0.5798511, 0.29204842, 0.6708136, 0.9576144, 0.10405682, 0.7253105, 0.9326284, -0.24903095, 0.99624836, 0.8530533, 0.6671376, 0.5334839, 0.8922802, 0.50491524, 0.47352976, 0.114075884, 0.76215386, -0.025808325, 0.34201944, 0.50133306, 0.5072456, 0.9658282, 0.53421855, 0.32217088, 0.019331919, 0.8438945, 0.7697814, -0.872105, 0.27831417, 0.837763, 0.47709718, 0.56208163, 0.13857186, 0.028468672, 0.34605467, 0.42612493, 0.35739717, -0.79774356, 0.63431424, 0.5377991, 0.4116114, 0.4728273, 0.36964366, 0.48545814, 0.3856123, 0.48144072, 0.11712731, -0.64248794, 0.5882744, 0.71837467, 0.77630204, 0.1082207, 0.500894, 0.956352, 0.7659055, 0.6140229, 0.75782984, -0.34864277, 0.9382825, 0.26016235, 0.9555291, 0.06052337, 0.9707168, 0.15848531, 0.3759561, 0.10505597, 0.39491206, -0.86381155, 0.15886053, 0.047404833, 0.7566787, 0.96441025, 0.3914941, 0.8042203, 0.08972167, 0.0344183, 0.59618455, -0.0487604, 0.93655854, 0.5378912, 0.7267672, 0.12729345, 0.2838306, 0.5599395, 0.06146098, 0.3688765, 0.061187647, -0.18221985, 0.2625632, 0.7320318, 0.6682951, 0.008754399, 0.85946107, 0.3741519, 0.58227, 0.35108802, 0.5021105, -0.21115834, 0.10950206, 0.28055635, 0.08652866, 0.25331578, 0.48362744, 0.5408696, 0.9616959, 0.8118918, 0.7167266, -0.6966737, 0.8666303, 0.73148715, 0.017838325, 0.7090695, 0.4120842, 0.40039128, 0.5333952, 0.8282356, 0.77669275, -0.41077727, 0.09702433, 0.007079605, 0.043868326, 0.21269222, 0.6012483, 0.42682874, 0.37910977, 0.7479243, 0.10494917, -0.01734221, 0.22195028, 0.73863363, 0.5323078, 0.38502622, 0.93925834, 0.6560022, 0.45136255, 0.47345138, 0.643666, -0.74296105, 0.5982436, 0.24956919, 0.65214986, 0.36451396, 0.31558952, 0.531076, 0.71419346, 0.9592256, 0.5966702, -0.45906982, 0.8407567, 0.7540344, 0.5743953, 0.09133322, 0.114134, 0.10242245, 0.23668802, 0.87383646, 0.6520674, -0.056798704, 0.16175981, 0.2137716, 0.7069426, 0.6993844, 0.4747234, 0.1279967, 0.19917937, 0.6328121, 0.76981115, -0.756082, 0.94902873, 0.059943788, 0.1845696, 0.03373171, 0.8125337, 0.84745514, 0.35492972, 0.67935437, 0.8971027, -0.07017233, 0.7126353, 0.41988418, 0.15125412, 0.6458793, 0.1765855, 0.46791586, 0.16423836, 0.4409746, 0.27089223, -0.83683586, 0.4193142, 0.5775261, 0.82138395, 0.58686733, 0.58120126, 0.384472, 0.54262656, 0.95276546, 0.8897906, -0.1875928, 0.33189663, 0.08138137, 0.18941447, 0.8405882, 0.51004106, 0.7808129, 0.5694648, 0.54066354, 0.27879953, -0.26667887, 0.74749273, 0.55733365, 0.97673374, 0.5818951, 0.34416345, 0.74187565, 0.06251747, 0.061063267, 0.5227989, -0.0068075284, 0.96375835, 0.75820476, 0.36191988, 0.93297523, 0.3367678, 0.37150264, 0.23855984, 0.5977023, 0.45253047, -0.42806166, 0.30482855, 0.40216422, 0.7895638, 0.7095099, 0.7382757, 0.6312539, 0.23046969, 0.3106659, 0.13583827, -0.39577258, 0.89845103, 0.6235748, 0.16217506, 0.004213362, 0.08934315, 0.86198056, 0.60079235, 0.23948883, 0.24270387, -0.8393256, 0.32195452, 0.4815633, 0.4299666, 0.8829831, 0.22383447, 0.57369184, 0.7194615, 0.2564392, 0.5038204, -0.13853844, 0.5422531, 0.97176254, 0.0881331, 0.85073787, 0.9618503, 0.3453285, 0.76776993, 0.26722383, 0.8436194, -0.7129096, 0.51140594, 0.75185156, 0.925225, 0.1270263, 0.10835649, 0.34018353, 0.5960297, 0.35770652, 0.8436321, -0.47478724, 0.7707103, 0.999071, 0.35499844, 0.6132049, 0.106107146, 0.82326525, 0.97219765, 0.9065807, 0.48567542, -0.16458383, 0.9117924, 0.9740305, 0.8068454, 0.99729985, 0.8535195, 0.9266885, 0.5354417, 0.3114372, 0.04236306, -0.7440147, 0.09421062, 0.3335685, 0.3958694, 0.52979434, 0.32791966, 0.57010293, 0.5563383, 0.30294028, 0.77462655, -0.88365096, 0.97766215, 0.36175498, 0.41280714, 0.029033197, 0.36782816, 0.5431821, 0.61676407, 0.47492823, 0.7446307, -0.13858505, 0.37313086, 0.86118925, 0.7815484, 0.6790356, 0.8011172, 0.53737545, 0.94500613, 0.92792517, 0.27350682, -0.18166798, 0.8047418, 0.2845925, 0.31534344, 0.09961744, 0.38057664, 0.43714178, 0.6032016, 0.82520413, 0.28528523, -0.5360042, 0.26692694, 0.66925734, 0.13195412, 0.6020245, 0.18692169, 0.5500374, 0.5612233, 0.77781224, 0.62947166, -0.31033742, 0.30992442, 0.060513485, 0.5668065, 0.903778, 0.3708838, 0.2330214, 0.55202013, 0.71683383, 0.72867715, -0.79054415, 0.6250968, 0.62841314, 0.029433481, 0.59295857, 0.07890911, 0.69306964, 0.046411548, 0.3131897, 0.6484566, -0.9306864, 0.93998045, 0.79156, 0.189643, 0.20862652, 0.8716581, 0.7038735, 0.7292351, 0.1795239, 0.49211392, -0.25107977, 0.9761521, 0.16719387, 0.29845348, 0.9631694, 0.87174356, 0.74422836, 0.7177861, 0.41156542, 0.72873366, -0.14755523, 0.88512164, 0.8863678, 0.096526965, 0.49474105, 0.9109074, 0.6385138, 0.63982385, 0.53899556, 0.5231154, -0.49385205, 0.5036258, 0.24803366, 0.12935568, 0.6987853, 0.37035698, 0.5183644, 0.8708705, 0.35817996, 0.032119915, -0.66701025, 0.5037863, 0.37249622, 0.22471993, 0.47759736, 0.81439203, 0.45790294, 0.32995966, 0.06626411, 0.721215, -0.33468077, 0.97528356, 0.6348461, 0.584456, 0.50090134, 0.04556473, 0.053612676, 0.695033, 0.69490194, 0.29771915, -0.23314431, 0.064049676, 0.19023955, 0.6564085, 0.99826187, 0.7474539, 0.7281185, 0.037838195, 0.5996682, 0.5928124, -0.35337916, 0.87335783, 0.3596061, 0.37944552, 0.06172341, 0.6437689, 0.51262546, 0.66164786, 0.6189296, 0.680349, -0.45300442, 0.3085541, 0.57355976, 0.81778055, 0.18843463, 0.51856846, 0.8687797, 0.6635776, 0.6284543, 0.6532206, -0.3167443, 0.8233314, 0.17596854, 0.06046078, 0.7989756, 0.6029606, 0.31354675, 0.7160877, 0.22645807, 0.7301434, -0.086273566, 0.42006475, 0.7302915, 0.4734517, 0.36783585, 0.4613229, 0.6156775, 0.2554006, 0.5227326, 0.8571324, -0.53293926, 0.39196482, 0.07610343, 0.014552955, 0.84471476, 0.9245902, 0.49048993, 0.37245902, 0.4679739, 0.47969338, -0.8786742, 0.06454086, 0.40938383, 0.9464476, 0.2760681, 0.5300478, 0.6973893, 0.2991453, 0.5804699, 0.45876285, -0.33022216, 0.79653776, 0.43518978, 0.8887862, 0.59407544, 0.032939672, 0.5782626, 0.10010804, 0.44994467, 0.7271117, -0.902891, 0.6133791, 0.140845, 0.77132195, 0.12028129, 0.9247795, 0.74722797, 0.16141559, 0.21574605, 0.8743854, -0.11247064, 0.9410877, 0.24811381, 0.74676466, 0.8514692, 0.021732707, 0.010680916, 0.7838439, 0.19738361, 0.8377881, -0.7639336, 0.31653216, 0.6749307, 0.06396978, 0.52691025, 0.7364015, 0.956775, 0.18731725, 0.42047754, 0.8117751, -0.34632754, 0.39038187, 0.9225143, 0.7408622, 0.57680243, 0.2652951, 0.92369586, 0.6380619, 0.82616633, 0.35128862, -0.7828198, 0.5359737, 0.08339928, 0.7060845, 0.3462922, 0.38913444, 0.54842395, 0.6884251, 0.037316978, 0.5723427, -0.022258755, 0.79441875, 0.90272444, 0.61215657, 0.9631781, 0.5863588, 0.9384484, 0.07687521, 0.24441172, 0.38387978, -0.96800447, 0.5599107, 0.74093807, 0.403971, 0.5280579, 0.72208875, 0.018573398, 0.5072516, 0.16996226, 0.58617413, -0.09803684, 0.37261903, 0.95767754, 0.84609497, 0.05496832, 0.22795987, 0.23313288, 0.9688462, 0.7176776, 0.1377758, -0.18797757, 0.26834992, 0.15000027, 0.8481348, 0.7895163, 0.5519088, 0.48765746, 0.31035778, 0.77768403, 0.9904436, -0.32684666, 0.84682065, 0.39365014, 0.44228655, 0.38328415, 0.22290905, 0.79503566, 0.6794283, 0.17802662, 0.62420344, -0.37056103, 0.041172326, 0.51846284, 0.45114288, 0.47430587, 0.6496397, 0.8367412, 0.05662944, 0.5571883, 0.7352182, -0.35322595, 0.9696022, 0.35919765, 0.10663593, 0.19590221, 0.6996546, 0.40991047, 0.89280325, 0.6144547, 0.9761491, -0.23443131, 0.70821565, 0.7295676, 0.17951865, 0.25932744, 0.25121617, 0.97896886, 0.515391, 0.46281084, 0.83205926, -0.4329242, 0.55370456, 0.7908196, 0.093474135, 0.7672148, 0.14680524, 0.74988705, 0.69885737, 0.37382892, 0.13987659, -0.7151676, 0.431028, 0.75316954, 0.04246583, 0.63721764, 0.35724443, 0.48762304, 0.28701422, 0.24638435, 0.6836296, -0.8129986, 0.9022324, 0.064973645, 0.20187753, 0.38977212, 0.6623454, 0.31160477, 0.3389442, 0.19181544, 0.2230897, -0.6706708, 0.32135025, 0.5938186, 0.725129, 0.30229402, 0.7995213, 0.17878264, 0.2657235, 0.33942115, 0.04909697, -0.94976753, 0.7110531, 0.5189743, 0.47457805, 0.2609815, 0.8034033, 0.9550461, 0.6871017, 0.542301, 0.90208304, -0.76359314, 0.6919547, 0.2690066, 0.77918124, 0.019060668, 0.5306918, 0.48873094, 0.58894205, 0.703702, 0.104869366, -0.8352005, 0.41094282, 0.507042, 0.15073924, 0.46920577, 0.3938173, 0.8372094, 0.028040525, 0.7401718, 0.8376963, -0.17846179, 0.22189952, 0.9475931, 0.19728738, 0.7338621, 0.101945534, 0.3832581, 0.59039557, 0.94089603, 0.5863688, -0.7072993, 0.624503, 0.7966432, 0.28973243, 0.45949653, 0.9787162, 0.052343633, 0.81463736, 0.70606834, 0.7716022, -0.31079042, 0.5898406, 0.5620215, 0.23455179, 0.21389648, 0.5388247, 0.2040111, 0.36823508, 0.0053723096, 0.8671642, -0.9661939, 0.9270056, 0.94692993, 0.7046047, 0.72362125, 0.5416936, 0.7443616, 0.07171923, 0.04531915, 0.91711515, -0.1474337, 0.89833534, 0.648046, 0.11733318, 0.39757007, 0.21069747, 0.6142996, 0.21730955, 0.6912427, 0.49048957, -0.34147367, 0.022572042, 0.3219722, 0.9685696, 0.5269059, 0.5886212, 0.659878, 0.7130413, 0.98339087, 0.19503741, -0.89793444, 0.015023004, 0.5850233, 0.07373183, 0.62017494, 0.7802937, 0.6775731, 0.09203854, 0.5661112, 0.9178029, -0.2343546, 0.9806244, 0.7693182, 0.7889532, 0.6241685, 0.41245508, 0.9417946, 0.44468832, 0.8369817, 0.0031990237, -0.9245251, 0.98670155, 0.6769924, 0.51488274, 0.5256905, 0.9436219, 0.6050334, 0.97836035, 0.17769879, 0.13500004, -0.8818156, 0.0313203, 0.08832834, 0.8502817, 0.019180698, 0.13241069, 0.31331208, 0.5743142, 0.49715826, 0.6172764, -0.5331244, 0.5222611, 0.6511984, 0.7734398, 0.256135, 0.3608493, 0.25325385, 0.533019, 0.34440103, 0.114450805, -0.6468266, 0.2151897, 0.8760596, 0.9801919, 0.27051234, 0.9112329, 0.3380306, 0.07014053, 0.54804134, 0.6765531, -0.1752603, 0.69921273, 0.9143398, 0.43111116, 0.035987273, 0.2030343, 0.8922961, 0.91903645, 0.76977247, 0.49175784, -0.099143006, 0.3674804, 0.94753003, 0.21970531, 0.47007462, 0.40226397, 0.3355032, 0.9035526, 0.25874776, 0.16484123, -0.69036806, 0.07201438, 0.63395935, 0.063247986, 0.48817343, 0.6666259, 0.15526073, 0.10813647, 0.5797694, 0.10794782, -0.79438007, 0.24317154, 0.026272861, 0.8206052, 0.4420161, 0.8339117, 0.6079213, 0.22008722, 0.73745257, 0.053100668, -0.46855322, 0.33421737, 0.76324654, 0.8526432, 0.015307797, 0.27934623, 0.26765963, 0.65635425, 0.51011723, 0.86824834, -0.57572967, 0.43447804, 0.8113928, 0.38320008, 0.986185, 0.10324592, 0.06525337, 0.85109174, 0.94293773, 0.36936134, -0.047773577, 0.7841596, 0.33926708, 0.66182464, 0.69737774, 0.85597146, 0.34120753, 0.12692484, 0.7776892, 0.63616294, -0.79434264, 0.11541597, 0.16610004, 0.2056471, 0.696288, 0.35615066, 0.30876786, 0.78131616, 0.04794019, 0.2088272, -0.39896628, 0.49890646, 0.59801924, 0.711521, 0.5322181, 0.35990205, 0.43177876, 0.6430728, 0.8344202, 0.33877015, -0.76865834, 0.75682956, 0.2771495, 0.3680912, 0.005327093, 0.68439364, 0.9949503, 0.10142185, 0.15526544, 0.15933633, -0.9381387, 0.14073479, 0.87866503, 0.8739543, 0.07390571, 0.46031374, 0.268378, 0.6057457, 0.68691206, 0.6300343, -0.79447806, 0.28393722, 0.80315155, 0.73411053, 0.9703951, 0.5488671, 0.18614037, 0.6277461, 0.12960654, 0.33747572, -0.4241927, 0.6981348, 0.29250467, 0.43891907, 0.8675046, 0.037513115, 0.8382665, 0.79800886, 0.20032, 0.011894401, -0.3612004, 0.207346, 0.6260507, 0.88860387, 0.27068847, 0.25823146, 0.62024146, 0.72406495, 0.6376153, 0.0719044, -0.09152406, 0.82603306, 0.9561607, 0.20438583, 0.5442921, 0.4847211, 0.95367795, 0.54303896, 0.3976961, 0.45646, -0.49825326, 0.3672042, 0.9718153, 0.81778973, 0.73514366, 0.24000394, 0.8482301, 0.43974596, 0.006449677, 0.036392592, -0.62204725, 0.47036913, 0.4054257, 0.67501765, 0.26883397, 0.58713204, 0.6578865, 0.91454774, 0.46342203, 0.7121636, -0.92862564, 0.46207544, 0.9901308, 0.057702154, 0.24595165, 0.5981596, 0.74197406, 0.08811883, 0.894627, 0.38278353, -0.08383514, 0.2952275, 0.40031275, 0.74386, 0.5136412, 0.9939962, 0.2355307, 0.808261, 0.15346022, 0.030684536, -0.41000134, 0.1804955, 0.71761525, 0.6012227, 0.44985715, 0.6211549, 0.4206074, 0.28114304, 0.9355519, 0.95716006, -0.82683456, 0.03913026, 0.07961693, 0.6855325, 0.52783436, 0.036177807, 0.3770734, 0.91411316, 0.5718381, 0.13698402, -0.4980299, 0.76011133, 0.545119, 0.62366617, 0.95255744, 0.32681978, 0.07005637, 0.66156566, 0.16137652, 0.27483776, -0.35160136, 0.8496255, 0.7610875, 0.4327375, 0.30216226, 0.74813014, 0.74446017, 0.38890806, 0.607845, 0.62479675, -0.17755221, 0.46083102, 0.15256695, 0.9374669, 0.5559489, 0.04470488, 0.21561056, 0.7147803, 0.21602567, 0.47746333, -0.6169228, 0.32141757, 0.23642296, 0.016476203, 0.53265464, 0.64989, 0.6353765, 0.0939491, 0.64866525, 0.12303737, -0.5510985, 0.7590417, 0.11976651, 0.6607141, 0.6055587, 0.9772091, 0.27804276, 0.64687943, 0.38337022, 0.7797042, -0.29171762, 0.9881654, 0.30626813, 0.94704133, 0.9594318, 0.037198868, 0.60754436, 0.60765207, 0.06771721, 0.9078526, -0.1112092, 0.3552761, 0.44554, 0.6839132, 0.657915, 0.030183792, 0.6132026, 0.74461126, 0.9000829, 0.6522722, -0.112753615, 0.6505111, 0.74024284, 0.48480767, 0.073698185, 0.4185105, 0.3410645, 0.49185285, 0.33190826, 0.5787399, -0.7666621, 0.5687311, 0.33141005, 0.43632144, 0.18574573, 0.6287574, 0.01514944, 0.28938162, 0.057044394, 0.49545577, -0.042345677, 0.027724478, 0.026231889, 0.74081266, 0.011828165, 0.19582245, 0.31350172, 0.43585333, 0.0027991086, 0.5753749, -0.36400652, 0.5334315, 0.74679655, 0.731098, 0.6669506, 0.6412065, 0.24792254, 0.8214605, 0.8733431, 0.54092133, -0.6961343, 0.115691505, 0.27574378, 0.48897734, 0.14119047, 0.5424781, 0.02386607, 0.009218562, 0.49816743, 0.029157575, -0.015034353, 0.32382092, 0.6875669, 0.40462708, 0.6099266, 0.08502913, 0.6242792, 0.9994301, 0.4729795, 0.87787575, -0.10500878, 0.90521115, 0.48905376, 0.7565334, 0.21473333, 0.23323065, 0.8219346, 0.60031205, 0.76937085, 0.5445392, -0.38083488, 0.19368897, 0.41603848, 0.51612306, 0.7993214, 0.92665416, 0.75198066, 0.5372545, 0.5996222, 0.4693501, -0.17195638, 0.30428314, 0.9376859, 0.9736415, 0.5603405, 0.040185597, 0.8458646, 0.34216946, 0.12117143, 0.58192146, -0.016927328, 0.24849239, 0.34848097, 0.99546736, 0.43591255, 0.7909232, 0.62663776, 0.51921046, 0.274244, 0.9079598, -0.72054344, 0.42355403, 0.2398477, 0.95362824, 0.6483227, 0.8213454, 0.90778244, 0.17144382, 0.6053057, 0.68327236, -0.33304846, 0.08702466, 0.39980793, 0.0036293846, 0.7059194, 0.80072564, 0.96752524, 0.5154122, 0.19619283, 0.17454775, -0.38736606, 0.47976512, 0.4791406, 0.1874494, 0.52761185, 0.13234249, 0.845208, 0.4205711, 0.08021053, 0.00839825, -0.3000164, 0.23277025, 0.26301053, 0.6916624, 0.74880666, 0.74840236, 0.064435445, 0.98405766, 0.32531884, 0.73899513, -0.13240317, 0.6744208, 0.7368638, 0.43789902, 0.24887301, 0.9299027, 0.8486845, 0.34485158, 0.289548, 0.6351869, -0.82339793, 0.11122555, 0.3230176, 0.09969627, 0.52059376, 0.24077836, 0.9444134, 0.05239831, 0.42601636, 0.5159802, -0.9761374, 0.48721132, 0.09123329, 0.59690744, 0.383256, 0.1002782, 0.8240141, 0.70814556, 0.25482276, 0.957517, -0.7362902, 0.9834676, 0.19009337, 0.45719767, 0.042144574, 0.71294534, 0.7429013, 0.041241586, 0.9385764, 0.59770924, -0.28365803, 0.50035644, 0.13102308, 0.44502363, 0.18500035, 0.18879086, 0.90975267, 0.16331425, 0.17106864, 0.50802827, -0.80398893, 0.012037134, 0.55804133, 0.8093386, 0.7628578, 0.64519185, 0.58318746, 0.1399564, 0.05464305, 0.14859481, -0.10588853, 0.14053893, 0.09002884, 0.332031, 0.89889675, 0.8399303, 0.9211322, 0.86581993, 0.057551697, 0.8076484, -0.49787706, 0.90317184, 0.113821924, 0.82830715, 0.23232217, 0.47578096, 0.35618824, 0.64620966, 0.41190708, 0.19446513, -0.19052555, 0.6606999, 0.5370769, 0.74679446, 0.15352806, 0.72425306, 0.42542627, 0.3807547, 0.6943399, 0.39695272, -0.12975785, 0.6029449, 0.98659855, 0.78998154, 0.4918207, 0.1431191, 0.41032755, 0.7989921, 0.5461269, 0.34507003, -0.26765865, 0.043932725, 0.105762556, 0.36342022, 0.010151213, 0.90081716, 0.89821523, 0.7297342, 0.5770165, 0.2870768, -0.28900358, 0.9369778, 0.72804934, 0.86017793, 0.95806926, 0.44518864, 0.60346204, 0.34323436, 0.17850293, 0.17464367, -0.41450405, 0.5403775, 0.17148003, 0.660599, 0.6778906, 0.89493215, 0.9165733, 0.32384035, 0.33648646, 0.08920308, -0.06545341, 0.5571962, 0.10008278, 0.06683705, 0.92680645, 0.14659283, 0.5549373, 0.17365667, 0.73664325, 0.25271094, -0.8260378, 0.69569206, 0.80373824, 0.4072631, 0.10794914, 0.19278006, 0.8748956, 0.12642062, 0.8319123, 0.04663203, -0.53965706, 0.06709321, 0.6204891, 0.37148324, 0.93056595, 0.7272812, 0.8724527, 0.44516358, 0.68552965, 0.11521906, -0.98424387, 0.57437485, 0.39324772, 0.48781338, 0.22162339, 0.7318074, 0.836895, 0.66121227, 0.9333714, 0.81147647, -0.89025134, 0.42980537, 0.6065911, 0.925792, 0.3486058, 0.718812, 0.7366392, 0.7642169, 0.55264986, 0.4851105, -0.02003657, 0.79015267, 0.49192804, 0.28985444, 0.54954606, 0.9983602, 0.936707, 0.72859955, 0.13627109, 0.1995253, -0.27414012, 0.10977373, 0.48812705, 0.6214242, 0.26846707, 0.251663, 0.30244434, 0.31592485, 0.18563971, 0.3761417, -0.35588506, 0.2136833, 0.19304918, 0.020435851, 0.1563807, 0.10985168, 0.46050212, 0.69469714, 0.022877397, 0.211754, -0.99064195, 0.10823577, 0.89251375, 0.20041913, 0.09518249, 0.19409119, 0.082446806, 0.1033933, 0.93826735, 0.22326319, -0.7951004, 0.108295456, 0.5249412, 0.7338461, 0.53733635, 0.7804776, 0.94167835, 0.9851669, 0.6573249, 0.09694284, -0.41636762, 0.42071435, 0.5785772, 0.17650813, 0.12922545, 0.8063533, 0.5971035, 0.4714922, 0.13347372, 0.43969434, -0.53785807, 0.2420099, 0.70572215, 0.9245171, 0.20888333, 0.16590436, 0.21725997, 0.2877079, 0.5262417, 0.07437589, -0.16921617, 0.19905105, 0.3776575, 0.96237653, 0.58104134, 0.2475896, 0.6887421, 0.459203, 0.48309952, 0.3759031, -0.16817336, 0.47533524, 0.037372224, 0.92593455, 0.7953864, 0.5699276, 0.52965856, 0.7160056, 0.07119369, 0.28882924, -0.5969877, 0.6109546, 0.96991956, 0.498573, 0.68540514, 0.5530905, 0.40257332, 0.6004241, 0.52496284, 0.37143198, -0.56321764, 0.6539704, 0.45892516, 0.58294904, 0.9277267, 0.21731657, 0.043056846, 0.6162007, 0.5954668, 0.88163584, -0.11761114, 0.13790047, 0.98839265, 0.7575706, 0.271521, 0.06252285, 0.20463766, 0.7797876, 0.1291307, 0.6389557, -0.6362458, 0.5012543, 0.21651421, 0.23741248, 0.4773882, 0.5582616, 0.22913149, 0.8790845, 0.27697143, 0.02795082, -0.8450163, 0.08831802, 0.9342402, 0.11166756, 0.8126855, 0.51420295, 0.016410068, 0.4544232, 0.99820787, 0.5780698, -0.5268707, 0.9134579, 0.12053883, 0.18955784, 0.1712181, 0.45908722, 0.62256193, 0.21234894, 0.227052, 0.62288225, -0.34845284, 0.6227857, 0.4712934, 0.8860071, 0.73518616, 0.06196327, 0.4374562, 0.22151268, 0.10556084, 0.3694651, -0.9881851, 0.16397232, 0.3392293, 0.56751597, 0.036619555, 0.029293122, 0.20366028, 0.87672514, 0.94488513, 0.757318, -0.04611278, 0.75021446, 0.78157973, 0.5510609, 0.112084985, 0.7227879, 0.38071552, 0.026956385, 0.0661944, 0.01830097, -0.93569964, 0.016782548, 0.6520325, 0.65408915, 0.67949796, 0.22223058, 0.6170246, 0.048233118, 0.37648138, 0.7507222, -0.07674675, 0.7948974, 0.34886235, 0.6287428, 0.5898847, 0.36289844, 0.5742286, 0.55302286, 0.15293828, 0.14192496, -0.25542694, 0.74583685, 0.26746377, 0.46973395, 0.5767695, 0.59823835, 0.841206, 0.9202325, 0.7739221, 0.012398226, -0.6812478, 0.4104998, 0.15531828, 0.087259874, 0.43376547, 0.9714025, 0.5119398, 0.68514013, 0.888018, 0.814389, -0.4122685, 0.15542716, 0.5002437, 0.19416295, 0.6805713, 0.2512154, 0.4013521, 0.15283692, 0.96117616, 0.7491866, -0.14855935, 0.8276927, 0.8740181, 0.92426944, 0.762874, 0.18986279, 0.7493188, 0.18229857, 0.07731968, 0.08125962, -0.3810246, 0.6967921, 0.27431104, 0.36408317, 0.06947445, 0.66624695, 0.6395791, 0.2616025, 0.19497731, 0.6184822, -0.85095865, 0.88908845, 0.66500485, 0.33854932, 0.72965646, 0.099999785, 0.24559312, 0.07330083, 0.78916264, 0.32555407, -0.19688624, 0.6883691, 0.9590563, 0.024735536, 0.86383885, 0.8535551, 0.53648174, 0.23104885, 0.32438585, 0.24390268, -0.22208378, 0.32964125, 0.60782045, 0.8067584, 0.4333644, 0.71547633, 0.88111615, 0.13616055, 0.1246885, 0.014324361, -0.6116363, 0.13974965, 0.9578596, 0.34269398, 0.89822793, 0.25947088, 0.16268782, 0.53546876, 0.19461296, 0.6628742, -0.94426966, 0.67601794, 0.3931359, 0.7517656, 0.88437337, 0.6926555, 0.7377358, 0.2495755, 0.50024426, 0.21591938, -0.12976523, 0.40853027, 0.93721664, 0.95107466, 0.39639843, 0.52131736, 0.28126806, 0.85824645, 0.9051849, 0.01418011, -0.21888365, 0.10943257, 0.94861233, 0.77483827, 0.7139178, 0.057136595, 0.73050946, 0.61636233, 0.1265076, 0.60436803, -0.69086725, 0.0010129241, 0.036435887, 0.6615116, 0.299633, 0.54606587, 0.9365053, 0.85605484, 0.922385, 0.7407089, -0.9777405, 0.63154066, 0.63591623, 0.90876913, 0.88455915, 0.20310602, 0.20253302, 0.0067849625, 0.94629556, 0.37691054, -0.9782028, 0.30444136, 0.63028383, 0.18043286, 0.4439906, 0.8348371, 0.7274056, 0.61829764, 0.037847787, 0.8272368, -0.96214604, 0.12137349, 0.123067886, 0.8958763, 0.52505213, 0.1287523, 0.3720944, 0.275705, 0.65144163, 0.85033256, -0.58481205, 0.42521322, 0.93586147, 0.16447607, 0.036439568, 0.58734304, 0.47351632, 0.039843205, 0.8902792, 0.5108118, -0.8546036, 0.72372454, 0.6700668, 0.7495971, 0.6261652, 0.3864259, 0.3707291, 0.85600305, 0.21752104, 0.4647959, -0.81866026, 0.3182077, 0.818207, 0.09514821, 0.77856284, 0.85636705, 0.50847274, 0.74004, 0.38371703, 0.7558068, -0.83101165, 0.926828, 0.35534334, 0.09596299, 0.7920985, 0.5529896, 0.36857986, 0.46580777, 0.14399329, 0.85664755, -0.3613208, 0.6875624, 0.72801846, 0.527036, 0.9726332, 0.23842148, 0.45130673, 0.37347084, 0.26971108, 0.1386262, -0.7580232, 0.51609135, 0.058183976, 0.18664573, 0.031672336, 0.26660433, 0.6070062, 0.84071326, 0.38591322, 0.18007252, -0.07887025, 0.73347634, 0.6561262, 0.13447234, 0.67980015, 0.92777556, 0.3683812, 0.5741038, 0.95749855, 0.07317559, -0.017846042, 0.9049213, 0.7120097, 0.36087346, 0.10347511, 0.13109785, 0.5901893, 0.29117107, 0.12251501, 0.54014134, -0.40506032, 0.13500193, 0.4703289, 0.24509083, 0.9977836, 0.3149203, 0.868644, 0.16869761, 0.06429065, 0.52549416, -0.94598347, 0.5278666, 0.079894565, 0.9639208, 0.7777773, 0.62784445, 0.0314362, 0.5935461, 0.8472358, 0.04485763, -0.8700403, 0.8772029, 0.4159723, 0.1965355, 0.120780155, 0.8531019, 0.80408156, 0.6973105, 0.08317062, 0.9005745, -0.6764151, 0.3158351, 0.71819824, 0.84577185, 0.7750122, 0.94386834, 0.26314744, 0.41103536, 0.13668874, 0.36487988, -0.059131548, 0.19968359, 0.50981313, 0.4320044, 0.12719214, 0.48997945, 0.82502675, 0.74808896, 0.58309615, 0.47563064, -0.09966165, 0.9966431, 0.44393525, 0.07765738, 0.67010105, 0.5278574, 0.71902966, 0.27379337, 0.12431067, 0.14468168, -0.5108387, 0.1713335, 0.08552699, 0.16371617, 0.8490791, 0.63014835, 0.80966836, 0.23412272, 0.18890859, 0.833909, -0.364697, 0.62040085, 0.45685738, 0.48235595, 0.98572606, 0.6703567, 0.3673898, 0.9839679, 0.06934336, 0.6308007, -0.02807519, 0.0559926, 0.11421437, 0.60753995, 0.80091286, 0.67977196, 0.87189984, 0.6405409, 0.17567077, 0.24715477, -0.22483869, 0.9893541, 0.2867247, 0.9920071, 0.85404116, 0.887798, 0.114156604, 0.34609696, 0.5829253, 0.49704382, -0.6803111, 0.590904, 0.5591804, 0.7491872, 0.110933654, 0.4792608, 0.53978574, 0.9615793, 0.091931306, 0.99974436, -0.1604676, 0.73506176, 0.20445003, 0.49350995, 0.11660648, 0.4548461, 0.057119142, 0.47798702, 0.36280334, 0.16930713, -0.7582485, 0.16912746, 0.058451943, 0.9417538, 0.6090703, 0.37534294, 0.33367616, 0.4648503, 0.6283148, 0.09792804, -0.5562001, 0.021292835, 0.40104258, 0.57229954, 0.95048964, 0.4371712, 0.49681222, 0.36502722, 0.49660632, 0.32165202, -0.13998619, 0.9103205, 0.54860955, 0.17592642, 0.086687185, 0.48977694, 0.78490406, 0.79321474, 0.8754006, 0.39919505, -0.8306789, 0.63616955, 0.98329365, 0.41361818, 0.73879534, 0.5111836, 0.53245205, 0.6174266, 0.14011684, 0.7355907, -0.14558467, 0.074935436, 0.33326453, 0.99400324, 0.44354424, 0.13917476, 0.33401918, 0.6321505, 0.5430203, 0.6794353, -0.9580339, 0.69209194, 0.9813807, 0.041151315, 0.029320937, 0.8479279, 0.6205179, 0.8825255, 0.85506666, 0.11929336, -0.5904389, 0.5404614, 0.58944976, 0.22911972, 0.26724914, 0.92003053, 0.037999198, 0.9874244, 0.83350426, 0.439306, -0.9047191, 0.87938565, 0.22491038, 0.7610156, 0.17606735, 0.06505076, 0.577056, 0.5546063, 0.7323822, 0.94751245, -0.15575777, 0.15275358, 0.2501944, 0.19596528, 0.44116116, 0.13858697, 0.65478885, 0.9421423, 0.38429725, 0.89086735, -0.8906657, 0.64992654, 0.7623599, 0.020823486, 0.14515182, 0.6051233, 0.4854857, 0.10414482, 0.7267541, 0.52351373, -0.10117556, 0.34659478, 0.7986462, 0.10371433, 0.7747162, 0.078648254, 0.46718153, 0.22036512, 0.86508393, 0.9642702, -0.27087194, 0.06591158, 0.15014334, 0.9075542, 0.9635356, 0.4376853, 0.290267, 0.39348447, 0.78795856, 0.12866218, -0.26524165, 0.095856875, 0.6031271, 0.94263685, 0.54864025, 0.25479257, 0.11702571, 0.20408688, 0.6158638, 0.5709441, -0.57956505, 0.47291118, 0.8278522, 0.20886846, 0.8463369, 0.809163, 0.35410735, 0.14648008, 0.4212491, 0.36251292, -0.67140543, 0.43442374, 0.07705836, 0.42002708, 0.6199954, 0.8247542, 0.4997832, 0.8548057, 0.057287898, 0.7074665, -0.31485626, 0.09200123, 0.31618625, 0.59809196, 0.25827205, 0.0053186826, 0.7434676, 0.85600936, 0.5550741, 0.5199236, -0.96162254, 0.26309466, 0.60450137, 0.29413986, 0.38470513, 0.79796076, 0.23805939, 0.9412749, 0.061217327, 0.15437259, -0.083577976, 0.14378692, 0.9722354, 0.42544565, 0.45725676, 0.8308179, 0.018798511, 0.18310007, 0.32264143, 0.72388613, -0.75500935, 0.26221997, 0.146799, 0.90839726, 0.25608784, 0.48756382, 0.15672493, 0.22976026, 0.9505964, 0.8410182, -0.06569535, 0.498098, 0.591406, 0.90132546, 0.40089035, 0.40831077, 0.82992244, 0.7829185, 0.03532195, 0.8220347, -0.5866948, 0.55850834, 0.7935884, 0.9029153, 0.62388855, 0.17106935, 0.11976584, 0.8907406, 0.14083518, 0.42745417, -0.9865202, 0.5603676, 0.53336793, 0.83118796, 0.7649143, 0.6994026, 0.116295666, 0.69610405, 0.03805204, 0.8971413, -0.6412358, 0.008299126, 0.9906785, 0.22019914, 0.08867724, 0.58548, 0.5523809, 0.07090994, 0.024555296, 0.048945986, -0.0008954834, 0.23588002, 0.14777812, 0.5006067, 0.13719136, 0.19650105, 0.46863157, 0.24388368, 0.28450873, 0.08501847, -0.367798, 0.26598433, 0.08892508, 0.5231422, 0.854498, 0.50532776, 0.96473, 0.760218, 0.13641119, 0.7014878, -0.2920151, 0.13381833, 0.74486643, 0.13818067, 0.18079887, 0.57839566, 0.56782985, 0.5733893, 0.8142381, 0.038408525, -0.61868846, 0.048855904, 0.8661853, 0.091889195, 0.42655867, 0.75064015, 0.41258946, 0.0327612, 0.6939966, 0.5684132, -0.230771, 0.87241197, 0.41159534, 0.95303357, 0.5293433, 0.37525147, 0.91937405, 0.46753627, 0.3657011, 0.58334947, -0.62074995, 0.79216284, 0.9344987, 0.32306752, 0.7569309, 0.8670772, 0.49101356, 0.0095974505, 0.31980786, 0.5587957, -0.6286712, 0.8952423, 0.42964563, 0.24610022, 0.46633002, 0.31894207, 0.39979902, 0.99703586, 0.09658354, 0.10385787, -0.092738345, 0.9319688, 0.066221446, 0.567998, 0.47071677, 0.41960314, 0.722223, 0.79183286, 0.60883737, 0.8055474, -0.6590216, 0.10029357, 0.20768817, 0.2308886, 0.41765857, 0.82652557, 0.11435715, 0.5431178, 0.3349583, 0.55948156, -0.2596266, 0.402992, 0.7129533, 0.13520089, 0.939742, 0.33552873, 0.44276634, 0.16549513, 0.48670354, 0.2104012, -0.9754525, 0.9223382, 0.37095273, 0.26184326, 0.4906111, 0.68878114, 0.7259414, 0.3665008, 0.8523507, 0.33732775, -0.14485414, 0.69918066, 0.40076008, 0.5142605, 0.89977413, 0.52837765, 0.6875541, 0.19875702, 0.8284416, 0.6398044, -0.20458493, 0.8566812, 0.66207755, 0.537102, 0.84423125, 0.6897463, 0.2190155, 0.93102056, 0.62825596, 0.13518804, -0.9768368, 0.5567279, 0.30512935, 0.39843616, 0.83009493, 0.7366834, 0.72934085, 0.9458449, 0.7402775, 0.7288774, -0.100584194, 0.7478564, 0.69076705, 0.99763054, 0.41462737, 0.5604459, 0.002231921, 0.19869287, 0.23542677, 0.41136438, -0.6479746, 0.24400933, 0.33705348, 0.8468991, 0.0058162767, 0.11877123, 0.26026058, 0.83385074, 0.417612, 0.80086476, -0.46976563, 0.79492086, 0.73824483, 0.71716267, 0.36049098, 0.58812624, 0.3940513, 0.0023239073, 0.68416554, 0.1630907, -0.7990368, 0.74170923, 0.45847952, 0.0995642, 0.5392202, 0.45672858, 0.16591415, 0.664447, 0.12247461, 0.28378534, -0.6875144, 0.020322617, 0.6955938, 0.21689159, 0.48721343, 0.7328274, 0.21967441, 0.45823023, 0.39261988, 0.7113237, -0.47642282, 0.8954901, 0.52823293, 0.9394127, 0.25911182, 0.30566335, 0.009611528, 0.9736044, 0.63713956, 0.82650113, -0.16639459, 0.99990803, 0.5145273, 0.07233607, 0.6123276, 0.9062654, 0.7855298, 0.23748927, 0.30767888, 0.5490877, -0.9528571, 0.5958136, 0.71137613, 0.13382663, 0.11335034, 0.449443, 0.09932706, 0.52135324, 0.22994924, 0.6276635, -0.36845186, 0.93582106, 0.609704, 0.9728418, 0.68666786, 0.9035467, 0.21347627, 0.51906675, 0.8404524, 0.2335569, -0.44711703, 0.19230975, 0.027307436, 0.29597348, 0.11739075, 0.6876064, 0.5057953, 0.6232577, 0.604564, 0.58094805, -0.94729763, 0.9821851, 0.15055138, 0.8435322, 0.7584666, 0.8806093, 0.18411398, 0.3944063, 0.8260624, 0.8096688, -0.20633629, 0.48825827, 0.74365515, 0.009476059, 0.45804924, 0.23057352, 0.39020398, 0.5416855, 0.3856682, 0.7087808, -0.69278914, 0.26646304, 0.39703688, 0.074121974, 0.10197067, 0.76054734, 0.5685061, 0.41540262, 0.016435882, 0.42574394, -0.94364774, 0.47606933, 0.91678923, 0.6490012, 0.68036586, 0.38626674, 0.78526974, 0.7661718, 0.2143752, 0.80605865, -0.7194327, 0.81907, 0.69300437, 0.030783592, 0.027220597, 0.9588587, 0.4486546, 0.017831376, 0.83792424, 0.8868172, -0.2974024, 0.9641097, 0.23758952, 0.8957832, 0.8881589, 0.6808346, 0.5851483, 0.0764294, 0.74156153, 0.9979193, -0.3121031, 0.7687113, 0.37797043, 0.40031847, 0.86602104, 0.730267, 0.57146907, 0.094653964, 0.32911018, 0.07178252, -0.4453038, 0.62403214, 0.32731032, 0.5796096, 0.9893481, 0.87371916, 0.5734587, 0.3662533, 0.046901383, 0.14311191, -0.31189272, 0.5506748, 0.5774784, 0.12961864, 0.12834151, 0.97953796, 0.23847981, 0.021006035, 0.76084226, 0.99953127, -0.8011185, 0.7088403, 0.024610326, 0.21645589, 0.49395552, 0.9507214, 0.44109955, 0.2926859, 0.16476253, 0.29695365, -0.3873897, 0.35400063, 0.6887212, 0.7661417, 0.44151342, 0.67337024, 0.6367994, 0.65797997, 0.906435, 0.014439769, -0.10737592, 0.21889497, 0.029528014, 0.5984496, 0.6860266, 0.76142836, 0.19123298, 0.24835177, 0.27197698, 0.8864831, -0.49178717, 0.550463, 0.3338117, 0.32957888, 0.27066407, 0.7364635, 0.59942186, 0.11085444, 0.08565405, 0.03862678, -0.4326196, 0.28077278, 0.20149076, 0.7499477, 0.7557222, 0.95789206, 0.86195356, 0.8113367, 0.6881052, 0.45497125, -0.34273857, 0.5804998, 0.11457099, 0.7464025, 0.8921554, 0.5822235, 0.6793123, 0.42616072, 0.5304293, 0.7325272, -0.7594884, 0.19274779, 0.02070892, 0.27827948, 0.8051665, 0.83692664, 0.020188946, 0.35914233, 0.49547768, 0.70504993, -0.07394841, 0.525945, 0.5723259, 0.8678083, 0.5818202, 0.8266031, 0.017404223, 0.27958027, 0.84272736, 0.7281345, -0.8994748, 0.3798963, 0.5602465, 0.8170057, 0.5437445, 0.9112873, 0.43589205, 0.5874092, 0.4374235, 0.68844056, -0.057151183, 0.1732611, 0.58042514, 0.35312688, 0.2791384, 0.23987181, 0.26006386, 0.9232113, 0.94478124, 0.9187956, -0.93770313, 0.50281125, 0.31585902, 0.9830553, 0.38102284, 0.8167936, 0.008173941, 0.24676272, 0.16458233, 0.06555225, -0.5648193, 0.39973202, 0.58343333, 0.8022948, 0.8330524, 0.3795921, 0.63250124, 0.20370321, 0.734535, 0.8938792, -0.40103462, 0.43277976, 0.92171884, 0.8070371, 0.64789873, 0.9006873, 0.94551986, 0.21919903, 0.5886699, 0.34194836, -0.5665393, 0.09419294, 0.33479902, 0.92393184, 0.7904314, 0.39666355, 0.0640373, 0.5771913, 0.43598288, 0.7269509, -0.90311337, 0.18912931, 0.42282686, 0.37187123, 0.12362129, 0.65741915, 0.5898278, 0.77813035, 0.5200745, 0.8995463, -0.6073706, 0.056360655, 0.18867631, 0.05090209, 0.51776093, 0.5049234, 0.5810924, 0.5088219, 0.3351565, 0.48033553, -0.87127376, 0.7889749, 0.65809286, 0.822634, 0.49901298, 0.47062632, 0.064933024, 0.65950155, 0.0118634105, 0.43638885, -0.3155548, 0.055309944, 0.76772034, 0.007584079, 0.9907658, 0.2119053, 0.0099529, 0.5498476, 0.68341583, 0.9904796, -0.31085956, 0.16738948, 0.6991246, 0.6891236, 0.7345778, 0.5101786, 0.9055166, 0.28389692, 0.40617087, 0.285508, -0.8155711, 0.5552154, 0.24203478, 0.95564735, 0.8556771, 0.11413846, 0.53103644, 0.6001929, 0.8728583, 0.652995, -0.59248614, 0.9303262, 0.76626694, 0.083685614, 0.5839915, 0.55206066, 0.28864032, 0.18109223, 0.06013629, 0.30585563, -0.49497047, 0.031244803, 0.8254061, 0.34467688, 0.16947599, 0.70388424, 0.089850344, 0.9689693, 0.088056214, 0.9888344, -0.56510967, 0.7810361, 0.25333068, 0.72635543, 0.6208177, 0.7603394, 0.81327516, 0.812073, 0.15190694, 0.8766273, -0.68086886, 0.40976003, 0.6769893, 0.03042084, 0.39799348, 0.38053334, 0.40112254, 0.61543894, 0.10513203, 0.18251711, -0.22153829, 0.7244244, 0.22376063, 0.10031522, 0.79053754, 0.7843263, 0.7298093, 0.8973579, 0.7861713, 0.15179288, -0.024288114, 0.56206715, 0.51213664, 0.8840239, 0.08788527, 0.81145, 0.6769955, 0.039911535, 0.4628679, 0.82365215, -0.7387855, 0.47656733, 0.029185295, 0.18350895, 0.62498677, 0.08521046, 0.35425547, 0.7949853, 0.9466834, 0.78894264, -0.30276173, 0.4744114, 0.86383724, 0.9055391, 0.7672961, 0.8406853, 0.5572755, 0.15301545, 0.9358179, 0.83649135, -0.030530108, 0.9159173, 0.025901658, 0.00011405395, 0.8523392, 0.1188017, 0.89762336, 0.7929654, 0.9425356, 0.58654344, -0.7035378, 0.361211, 0.15257105, 0.2814799, 0.44373164, 0.744971, 0.6952391, 0.040251687, 0.47532842, 0.70532703, -0.43007088, 0.93482405, 0.9506745, 0.9972287, 0.84903115, 0.5498767, 0.6982299, 0.60659754, 0.116727814, 0.24719998, -0.25417453, 0.5239801, 0.10409364, 0.6263765, 0.79312205, 0.82286817, 0.45066565, 0.02907124, 0.33116972, 0.5061851, -0.1875871, 0.56129, 0.8524497, 0.36013994, 0.085404865, 0.94155073, 0.32184035, 0.58235735, 0.46180746, 0.022325099, -0.14544618, 0.5170238, 0.67768705, 0.23049083, 0.4064205, 0.09570609, 0.9652428, 0.028672969, 0.1510829, 0.30246252, -0.4205718, 0.2910258, 0.67623764, 0.69533557, 0.33236894, 0.17955771, 0.25711736, 0.5261945, 0.48835787}; +static int _rnd_count = 9999; +static float _rnd[] = { + 0.39540747, 0.841546, 0.52073574, 0.80399257, 0.95868486, 0.46164507, 0.5644759, 0.50258803, + 0.1953517, 0.40522006, 0.7953865, 0.7795385, 0.6009604, 0.03921096, 0.56872225, 0.93369347, + 0.7019503, 0.5392296, 0.2671585, 0.87286836, 0.28110227, 0.41505373, 0.8609184, 0.65234584, + 0.18079561, 0.1345461, 0.26905555, 0.97823226, 0.9349287, 0.37662244, 0.47883937, 0.1831086, + 0.63446456, 0.2549137, 0.8205819, 0.44705132, 0.7044422, 0.36040744, 0.29616997, 0.60375917, + 0.21973382, 0.094351165, 0.3769042, 0.9975177, 0.6133292, 0.3379986, 0.88620085, 0.83456165, + 0.16677794, 0.2749627, 0.28938183, 0.6274365, 0.058304083, 0.97233975, 0.48520145, 0.9803537, + 0.9806276, 0.8683899, 0.62319696, 0.82413876, 0.19258952, 0.5862436, 0.5676593, 0.8187293, + 0.9263807, 0.6122779, 0.14507395, 0.34604672, 0.21862903, 0.121670924, 0.22925124, 0.34154287, + 0.2430596, 0.66339934, 0.6531345, 0.1867511, 0.038149532, 0.8634007, 0.039016694, 0.84279704, + 0.24834526, 0.4344939, 0.8114543, 0.65996605, 0.08724063, 0.8514029, 0.12480451, 0.6621248, + 0.76971227, 0.8402282, 0.46642372, 0.83605236, 0.73721045, 0.47203118, 0.41116965, 0.6334902, + 0.52669185, 0.55817497, 0.07113702, 0.0010512439, 0.19292463, 0.5401541, 0.61593264, 0.045107026, + 0.04571145, 0.94783896, 0.3843769, 0.39490476, 0.3192052, 0.29845035, 0.9422042, 0.11722695, + 0.8293732, 0.7804, 0.5757935, 0.7580956, 0.7747893, 0.90769327, 0.73148865, 0.074977815, + 0.4874734, 0.48294914, 0.5763345, 0.37840083, 0.6552472, 0.39319888, 0.6043324, 0.77102846, + 0.25222966, 0.019644327, 0.6600592, 0.4799746, 0.7922636, 0.03796545, 0.64987236, 0.70819116, + 0.81856126, 0.7663473, 0.6142546, 0.13940167, 0.46702597, 0.72989976, 0.34291962, 0.47126192, + 0.89802396, 0.34919676, 0.0066791615, 0.95681053, 0.8962376, 0.653074, 0.85870093, 0.6189986, + 0.8266863, 0.9961592, 0.5135778, 0.7099755, 0.9638197, 0.2375318, 0.3898598, 0.65251255, + 0.34350657, 0.6133485, 0.14267509, 0.29956087, 0.6383911, 0.4622296, 0.3249633, 0.79140776, + 0.13052759, 0.8676024, 0.93953437, 0.008441999, 0.2934387, 0.592087, 0.6079518, 0.75757366, + 0.14002953, 0.10507256, 0.48037684, 0.30605045, 0.38651973, 0.64752185, 0.8747908, 0.59915566, + 0.1609434, 0.04106063, 0.65328825, 0.79610443, 0.5243876, 0.9398969, 0.7443715, 0.5810295, + 0.3764875, 0.961742, 0.7958951, 0.8536775, 0.58722466, 0.043358732, 0.8328708, 0.43579438, + 0.024233455, 0.21527143, 0.8262829, 0.028635254, 0.71353966, 0.85025895, 0.3255599, 0.23459937, + 0.38820738, 0.7560042, 0.569946, 0.8587471, 0.75715494, 0.083809346, 0.26599285, 0.6959847, + 0.73855764, 0.54351944, 0.13861747, 0.59733045, 0.80894136, 0.52885884, 0.26702014, 0.1906307, + 0.123230904, 0.35850486, 0.6319545, 0.3316967, 0.7961919, 0.7542743, 0.17034897, 0.0966708, + 0.27220175, 0.04458247, 0.28181702, 0.1712483, 0.82123893, 0.8461555, 0.88561594, 0.3106845, + 0.7155007, 0.4186889, 0.40789708, 0.76838344, 0.36995092, 0.8856244, 0.82387453, 0.29267815, + 0.69574916, 0.099910386, 0.11511985, 0.04370523, 0.9047413, 0.23554033, 0.62685305, 0.4953746, + 0.9482513, 0.63565224, 0.9054043, 0.3550348, 0.21830441, 0.9938632, 0.4384075, 0.633933, + 0.5856552, 0.47327515, 0.58654535, 0.71257246, 0.80199236, 0.09474454, 0.8747458, 0.8924021, + 0.6579035, 0.82793295, 0.88182974, 0.39025244, 0.12096177, 0.4986367, 0.8206798, 0.23760653, + 0.53463036, 0.33927637, 0.6359475, 0.6962815, 0.6391545, 0.12664375, 0.19192953, 0.036661416, + 0.41772944, 0.7864424, 0.222997, 0.18558672, 0.9407512, 0.5305812, 0.092380084, 0.7216375, + 0.9802814, 0.77396405, 0.18272822, 0.89667577, 0.29907903, 0.11130205, 0.4906858, 0.60100466, + 0.22516462, 0.22271773, 0.38580173, 0.07680829, 0.3537106, 0.23660058, 0.37441283, 0.4496146, + 0.81497246, 0.6677978, 0.82040447, 0.879028, 0.35791573, 0.742126, 0.9947786, 0.45901147, + 0.28134564, 0.54988396, 0.29484302, 0.015549939, 0.87174755, 0.68915904, 0.9516509, 0.12732233, + 0.7355529, 0.16019227, 0.40997103, 0.34699774, 0.31590846, 0.924004, 0.93852746, 0.4233283, + 0.84859055, 0.034942873, 0.47111684, 0.41643673, 0.740842, 0.115121245, 0.68295085, 0.18112887, + 0.41202956, 0.77338237, 0.3706143, 0.27295336, 0.7101767, 0.21335205, 0.36372176, 0.2381554, + 0.7791855, 0.72371674, 0.6153301, 0.7491951, 0.816459, 0.47513586, 0.7292571, 0.5360056, + 0.2710668, 0.25847942, 0.3412554, 0.19351831, 0.8266295, 0.0274151, 0.13370614, 0.8909684, + 0.72927034, 0.39707616, 0.030437447, 0.32297286, 0.27100918, 0.57834184, 0.71816945, 0.16622439, + 0.8669331, 0.11371415, 0.6035204, 0.09836516, 0.31854475, 0.6786976, 0.41714564, 0.5222008, + 0.7964705, 0.17181565, 0.56781226, 0.5921917, 0.30867395, 0.1893324, 0.6068693, 0.37345472, + 0.3056858, 0.9351113, 0.14536993, 0.4823626, 0.7738658, 0.4894325, 0.35449934, 0.38461447, + 0.6396763, 0.4796459, 0.54368305, 0.31310055, 0.18291461, 0.040748898, 0.9671462, 0.20084366, + 0.0055472897, 0.4491057, 0.882262, 0.7027449, 0.87161547, 0.6308919, 0.21746083, 0.59236926, + 0.8413338, 0.81905454, 0.3970478, 0.6548139, 0.45960286, 0.5415144, 0.58229446, 0.539938, + 0.7902069, 0.6569827, 0.017287076, 0.33589792, 0.4329719, 0.23580688, 0.39235854, 0.3775006, + 0.7592148, 0.2189059, 0.45868888, 0.83889884, 0.13501453, 0.10404509, 0.3392862, 0.7557216, + 0.20466943, 0.36696857, 0.5866444, 0.85956824, 0.3070704, 0.9041244, 0.5018392, 0.67479384, + 0.7176504, 0.5530007, 0.6410288, 0.9548113, 0.092384726, 0.69968545, 0.92501163, 0.09816185, + 0.89735144, 0.0037450776, 0.52289367, 0.5259319, 0.023461822, 0.6312483, 0.7678718, 0.7697404, + 0.05674718, 0.5047614, 0.9435301, 0.6527096, 0.17220303, 0.37856197, 0.45735472, 0.7372887, + 0.47976837, 0.6413262, 0.45014447, 0.09263428, 0.95487, 0.7227262, 0.23286755, 0.8860825, + 0.15514348, 0.34249324, 0.61824745, 0.8799712, 0.59477806, 0.43754727, 0.28511587, 0.059529364, + 0.2938943, 0.36052704, 0.9415474, 0.13126945, 0.5811514, 0.8133543, 0.7322598, 0.5734211, + 0.5990968, 0.816904, 0.80282104, 0.802309, 0.96059436, 0.8491296, 0.50259084, 0.33908847, + 0.09564596, 0.9037401, 0.4750429, 0.45105854, 0.24954097, 0.8323773, 0.14329186, 0.17462522, + 0.77087754, 0.63681114, 0.3707884, 0.6809686, 0.013000839, 0.8879006, 0.17496233, 0.61919993, + 0.21964556, 0.8840007, 0.3588153, 0.81167597, 0.43701455, 0.32608527, 0.15613726, 0.666414, + 0.9090664, 0.87672335, 0.4935375, 0.13796596, 0.9199052, 0.43055856, 0.9254882, 0.30601385, + 0.8399024, 0.279159, 0.78432524, 0.69103795, 0.9625043, 0.83405733, 0.8099884, 0.46151695, + 0.2172352, 0.7669222, 0.3603919, 0.9443403, 0.44256592, 0.0512912, 0.5604203, 0.7111962, + 0.64194167, 0.18362112, 0.5826634, 0.07659364, 0.49031433, 0.6909148, 0.9020739, 0.7695607, + 0.7476028, 0.80862886, 0.5419922, 0.3728176, 0.33883983, 0.005325912, 0.25472003, 0.34031895, + 0.711323, 0.064774565, 0.8410662, 0.73384184, 0.10357534, 0.48392436, 0.65669554, 0.38558826, + 0.07401231, 0.8972984, 0.5944408, 0.67009234, 0.96569335, 0.21179698, 0.22384812, 0.8577752, + 0.31630307, 0.7823413, 0.49602425, 0.7362841, 0.84789515, 0.84889454, 0.8156995, 0.14898759, + 0.3770851, 0.01476456, 0.94343513, 0.15387547, 0.29206514, 0.43717077, 0.12267711, 0.21190928, + 0.5122022, 0.020072967, 0.23301727, 0.37779135, 0.21022503, 0.82657844, 0.60762084, 0.15801735, + 0.52692556, 0.19707517, 0.0025813282, 0.59301597, 0.09647403, 0.23198159, 0.80386734, 0.5358059, + 0.58478075, 0.684217, 0.056514528, 0.5564985, 0.50930166, 0.51843596, 0.4924238, 0.8624285, + 0.24907504, 0.6920786, 0.35675675, 0.08881078, 0.5404892, 0.5028201, 0.0935231, 0.63684154, + 0.77462125, 0.38253152, 0.15789017, 0.94562036, 0.97877973, 0.84605676, 0.64755017, 0.48972467, + 0.17472044, 0.3380069, 0.2093585, 0.65081996, 0.8463132, 0.22268358, 0.052513562, 0.1451035, + 0.21089722, 0.40762928, 0.5690947, 0.60784817, 0.38065624, 0.56617856, 0.70260763, 0.99376625, + 0.52764916, 0.37058878, 0.1287163, 0.51814646, 0.4698217, 0.5188101, 0.61752814, 0.024105478, + 0.103552066, 0.3657398, 0.81839466, 0.7139425, 0.07409142, 0.858247, 0.55702615, 0.738724, + 0.03666682, 0.56678987, 0.38177812, 0.17129473, 0.30907747, 0.8416038, 0.016115308, 0.02639147, + 0.639565, 0.21165326, 0.87791353, 0.13285992, 0.9337254, 0.48567492, 0.2561853, 0.20844269, + 0.6799239, 0.16412394, 0.41797122, 0.60819095, 0.71734047, 0.12940371, 0.019902974, 0.6559104, + 0.7204788, 0.18525302, 0.5472679, 0.4805734, 0.4042889, 0.33857107, 0.07101207, 0.35265025, + 0.85060316, 0.8303707, 0.57118136, 0.8138664, 0.18440045, 0.5313129, 0.68468875, 0.68604535, + 0.35447347, 0.10232483, 0.8785814, 0.25816843, 0.6408965, 0.48466823, 0.09038009, 0.6178771, + 0.10955451, 0.609952, 0.034018606, 0.9099675, 0.44027576, 0.9488352, 0.021383535, 0.9072631, + 0.5468869, 0.72586775, 0.45081598, 0.12382444, 0.29433593, 0.5355419, 0.62210256, 0.30099395, + 0.14064118, 0.5252633, 0.28225678, 0.10335469, 0.91449356, 0.44231892, 0.024042243, 0.14861101, + 0.47943518, 0.7319259, 0.2537175, 0.6150156, 0.25082228, 0.76173455, 0.01501382, 0.23581055, + 0.09487294, 0.9293908, 0.3710189, 0.7943369, 0.30455244, 0.1610446, 0.9123745, 0.90176797, + 0.80898714, 0.66391826, 0.2669795, 0.4585327, 0.08049692, 0.5608643, 0.3917094, 0.8189315, + 0.48022225, 0.5775875, 0.11752723, 0.11563321, 0.20241146, 0.9870254, 0.70338356, 0.6672356, + 0.5859097, 0.88540757, 0.4305323, 0.7083498, 0.69511765, 0.4063679, 0.6564408, 0.7851523, + 0.71085393, 0.21500541, 0.028951503, 0.36494514, 0.16452302, 0.8277657, 0.9964415, 0.9795966, + 0.6128888, 0.38048878, 0.29436752, 0.25057533, 0.17533945, 0.56550956, 0.06811409, 0.9185709, + 0.3402165, 0.43478596, 0.13479339, 0.6732348, 0.64420736, 0.8993806, 0.033399098, 0.10784754, + 0.22600721, 0.7037833, 0.20842715, 0.41914487, 0.7305123, 0.20402466, 0.2066503, 0.40261927, + 0.007477421, 0.48182714, 0.74767876, 0.8654915, 0.5319128, 0.026764244, 0.6544085, 0.6524566, + 0.58114594, 0.13793063, 0.50274444, 0.82192266, 0.6926579, 0.45280823, 0.49189615, 0.020400187, + 0.8172935, 0.51196146, 0.36813334, 0.26033172, 0.27157453, 0.983206, 0.140945, 0.81147337, + 0.18160632, 0.92110395, 0.13893794, 0.46073973, 0.6193385, 0.5772967, 0.2490843, 0.40886414, + 0.1738385, 0.89174825, 0.24309792, 0.6935123, 0.8178308, 0.20262258, 0.38665804, 0.31345224, + 0.78037745, 0.48233682, 0.09208888, 0.50627667, 0.3966362, 0.21147643, 0.41518968, 0.77319896, + 0.21188715, 0.18802696, 0.60185134, 0.21855086, 0.8358913, 0.94631857, 0.13104475, 0.024271427, + 0.34088212, 0.9362054, 0.6838852, 0.61080885, 0.8878263, 0.1936688, 0.03311803, 0.0038492912, + 0.88884634, 0.09388026, 0.64808416, 0.8009096, 0.2097103, 0.79838383, 0.20256937, 0.61467093, + 0.1253034, 0.054681093, 0.47995427, 0.7892377, 0.8911171, 0.6346683, 0.41483715, 0.9701299, + 0.5059143, 0.36573896, 0.24885257, 0.43131158, 0.97544533, 0.03053343, 0.57297283, 0.2275199, + 0.7607035, 0.21882649, 0.3526302, 0.8816254, 0.5187374, 0.77584916, 0.42562595, 0.58670866, + 0.44921878, 0.08823959, 0.6174303, 0.30275592, 0.5633923, 0.61428005, 0.56348866, 0.41350332, + 0.9854576, 0.9871804, 0.093247466, 0.7812102, 0.4663643, 0.34180707, 0.13315432, 0.70621383, + 0.52136827, 0.7137553, 0.10489457, 0.52208734, 0.94481623, 0.60180646, 0.028403986, 0.8583129, + 0.5209074, 0.42056426, 0.04020609, 0.9908838, 0.44575363, 0.32094392, 0.09593353, 0.34945422, + 0.62905514, 0.89324564, 0.3400189, 0.80287755, 0.017237967, 0.112081215, 0.40673763, 0.8916342, + 0.80225027, 0.83534926, 0.44585398, 0.98826486, 0.93728596, 0.79176265, 0.7611556, 0.41889647, + 0.08567218, 0.64641637, 0.3602572, 0.80498207, 0.6709546, 0.9035386, 0.64189243, 0.84741235, + 0.0598356, 0.7591174, 0.7818485, 0.142828, 0.574074, 0.5726049, 0.96774966, 0.6645137, + 0.8912469, 0.74379325, 0.15215507, 0.5731187, 0.0017881524, 0.3302768, 0.6889758, 0.40928704, + 0.30701768, 0.21326037, 0.71983707, 0.10946698, 0.1559525, 0.040139113, 0.92102695, 0.7291448, + 0.6594087, 0.62130964, 0.9052116, 0.79933727, 0.9606867, 0.29095143, 0.6784996, 0.72551656, + 0.2513532, 0.49260658, 0.74304193, 0.25812054, 0.33023268, 0.2639096, 0.31756023, 0.22964539, + 0.86759955, 0.7813403, 0.097017966, 0.19349271, 0.63960755, 0.18803692, 0.4171083, 0.7553954, + 0.95744056, 0.9509702, 0.4979644, 0.45769426, 0.18370152, 0.53242546, 0.69145983, 0.019696489, + 0.8380905, 0.052703734, 0.48341933, 0.95276433, 0.6673932, 0.16841243, 0.70382696, 0.6002955, + 0.06529366, 0.42663854, 0.32176548, 0.50918156, 0.58723485, 0.4308553, 0.079054326, 0.04310807, + 0.89570016, 0.4901917, 0.24186741, 0.3746122, 0.94312114, 0.72753423, 0.08953723, 0.47137174, + 0.20420133, 0.14981624, 0.8418967, 0.009716521, 0.79298705, 0.22080535, 0.541815, 0.71892774, + 0.80114675, 0.72334546, 0.42003006, 0.27752897, 0.7804903, 0.36479586, 0.56225216, 0.69918716, + 0.07751329, 0.4967225, 0.12819904, 0.212969, 0.86627144, 0.90792674, 0.16816054, 0.5265852, + 0.8719159, 0.45485634, 0.56199414, 0.6935098, 0.29055804, 0.31684762, 0.07657534, 0.11055623, + 0.9631665, 0.012047576, 0.74856305, 0.517577, 0.32651573, 0.69411045, 0.80730844, 0.8444883, + 0.88482356, 0.60283774, 0.7080349, 0.8638894, 0.010825248, 0.80152535, 0.26261777, 0.53090423, + 0.92793953, 0.54268026, 0.29709893, 0.44639865, 0.5993352, 0.8765682, 0.6051003, 0.2962746, + 0.9816557, 0.31531146, 0.13780066, 0.3381307, 0.6588112, 0.84830517, 0.4283697, 0.48429912, + 0.6467701, 0.30947384, 0.31436247, 0.7684427, 0.6162329, 0.044675153, 0.3726714, 0.38340282, + 0.689414, 0.28371072, 0.32814547, 0.26343372, 0.19989188, 0.30427113, 0.51576, 0.07039049, + 0.19223855, 0.031089857, 0.7655703, 0.7478778, 0.019748688, 0.63017666, 0.511221, 0.08659828, + 0.40694728, 0.45228842, 0.53592134, 0.011204251, 0.5563098, 0.46917772, 0.18567711, 0.036518365, + 0.17446801, 0.22373573, 0.21711932, 0.7013514, 0.48716292, 0.49417505, 0.9146714, 0.88326436, + 0.17000887, 0.9136961, 0.7569846, 0.3156245, 0.54842275, 0.34166658, 0.09638273, 0.67738456, + 0.7995515, 0.06741016, 0.14589214, 0.62772137, 0.08273488, 0.680492, 0.46455044, 0.016593413, + 0.7982528, 0.22776419, 0.36149544, 0.16394442, 0.50875384, 0.36146715, 0.827093, 0.22023632, + 0.098033614, 0.2916271, 0.088965714, 0.9761561, 0.08715181, 0.8144086, 0.5832276, 0.6980635, + 0.11641844, 0.8823059, 0.5778689, 0.106052585, 0.8731921, 0.19559653, 0.5381755, 0.06528069, + 0.3559057, 0.8585367, 0.21165277, 0.48889965, 0.32328558, 0.55795574, 0.95378345, 0.49397606, + 0.7591853, 0.20052591, 0.9030986, 0.25939873, 0.13267961, 0.750727, 0.37451053, 0.8085417, + 0.086603075, 0.5367483, 0.21759088, 0.25679567, 0.25270087, 0.120226584, 0.59023273, 0.9851429, + 0.48418257, 0.44782865, 0.51130295, 0.20042898, 0.102623075, 0.35849786, 0.14340132, 0.6026563, + 0.68958867, 0.29621476, 0.8080387, 0.6502171, 0.14981438, 0.3381934, 0.8969507, 0.54007787, + 0.33784363, 0.59498966, 0.21697083, 0.8866259, 0.91130996, 0.32382888, 0.5653839, 0.36569145, + 0.5077954, 0.76932716, 0.01944951, 0.3364438, 0.97800565, 0.28137985, 0.8125798, 0.2356791, + 0.268304, 0.22650987, 0.00471706, 0.8754569, 0.04665282, 0.7533545, 0.39135298, 0.40068746, + 0.05712457, 0.3004423, 0.56981003, 0.8364648, 0.9426883, 0.7242934, 0.65872735, 0.7484097, + 0.63979757, 0.677513, 0.91895205, 0.6577112, 0.90325576, 0.70360684, 0.07383294, 0.1603537, + 0.88244474, 0.14561148, 0.6926336, 0.3332959, 0.33904833, 0.80695754, 0.62465066, 0.40820882, + 0.48363495, 0.5723596, 0.38191313, 0.9233045, 0.33347633, 0.021493766, 0.49342504, 0.5844891, + 0.20363668, 0.81628335, 0.82950133, 0.6108677, 0.75401884, 0.728919, 0.42300317, 0.7835019, + 0.11059984, 0.2710398, 0.6966462, 0.30049264, 0.3624278, 0.1548686, 0.33242336, 0.56469715, + 0.15267694, 0.84436333, 0.9930122, 0.9010413, 0.06072089, 0.058057077, 0.061639126, 0.25016704, + 0.6757917, 0.16160122, 0.3528299, 0.37032866, 0.34238032, 0.7354228, 0.41493335, 0.6183038, + 0.18408795, 0.3344629, 0.45407453, 0.08697238, 0.8741055, 0.46296528, 0.40633488, 0.1535257, + 0.7226083, 0.90913165, 0.22269607, 0.068008505, 0.1103113, 0.32415798, 0.045781024, 0.32876635, + 0.23993625, 0.817216, 0.77062756, 0.48911297, 0.028481547, 0.5923837, 0.52376825, 0.14557959, + 0.7546443, 0.5793343, 0.935076, 0.5924176, 0.37608913, 0.05267449, 0.44112164, 0.37517703, + 0.85610646, 0.078342445, 0.11640469, 0.02796489, 0.70079404, 0.24545097, 0.69059163, 0.68971163, + 0.43802848, 0.83948654, 0.17843302, 0.15158923, 0.835361, 0.99363065, 0.13985574, 0.3516337, + 0.115820184, 0.02406358, 0.13039242, 0.5251643, 0.96479523, 0.92582035, 0.58982223, 0.59170425, + 0.8106947, 0.30849496, 0.33232814, 0.2947712, 0.5278893, 0.8139172, 0.77743655, 0.6699338, + 0.46801004, 0.84751904, 0.21190204, 0.031968854, 0.2077533, 0.017816134, 0.62797225, 0.99448526, + 0.12662433, 0.080915935, 0.05108449, 0.18899502, 0.41395068, 0.372179, 0.3102186, 0.7610136, + 0.43947858, 0.5834423, 0.47659743, 0.35202554, 0.9222821, 0.9159573, 0.4103818, 0.9302861, + 0.4885202, 0.52470046, 0.21727021, 0.39229912, 0.91312283, 0.39582044, 0.16182233, 0.62411124, + 0.062049974, 0.5084992, 0.6835792, 0.98784196, 0.78172857, 0.10788689, 0.1438804, 0.09800406, + 0.3960913, 0.13590716, 0.39854, 0.8838793, 0.8747359, 0.40082723, 0.17775355, 0.43851566, + 0.99827635, 0.5713145, 0.8552926, 0.94444704, 0.33731982, 0.42541102, 0.74765176, 0.55205274, + 0.43713725, 0.28161594, 0.5434486, 0.68305284, 0.80054593, 0.23567316, 0.08136242, 0.7308039, + 0.9190936, 0.42697325, 0.12694505, 0.9054515, 0.6885998, 0.32237664, 0.97928506, 0.33159167, + 0.43956187, 0.3785934, 0.9559342, 0.7863749, 0.5174173, 0.5265025, 0.05555021, 0.08769297, + 0.3469469, 0.77875453, 0.39402276, 0.34180835, 0.5405278, 0.21737531, 0.2867914, 0.636639, + 0.76084745, 0.13152646, 0.5507047, 0.50011265, 0.5644382, 0.46082756, 0.29745814, 0.16041815, + 0.054544732, 0.6677361, 0.9647857, 0.44776264, 0.27388218, 0.27230206, 0.74991584, 0.67589974, + 0.59202945, 0.52370095, 0.50488514, 0.9587264, 0.46947676, 0.9612768, 0.034635436, 0.91063476, + 0.22606573, 0.45575568, 0.33610594, 0.02179139, 0.8416504, 0.7395541, 0.19027609, 0.7017183, + 0.14018182, 0.49030608, 0.14460404, 0.55707335, 0.7716719, 0.47917238, 0.76715344, 0.9787343, + 0.08113525, 0.7955161, 0.7318302, 0.8496812, 0.5617168, 0.60778755, 0.81381077, 0.07464484, + 0.028838681, 0.718123, 0.74977887, 0.016826851, 0.71249014, 0.32806498, 0.16716221, 0.7995706, + 0.096891016, 0.64007, 0.27404693, 0.10868255, 0.12472161, 0.27566674, 0.31876773, 0.31499064, + 0.47746003, 0.2630674, 0.30758083, 0.78357613, 0.12769802, 0.1928425, 0.90422785, 0.112857096, + 0.7565475, 0.5261508, 0.8775912, 0.6739607, 0.22944665, 0.18495426, 0.3489179, 0.61827815, + 0.6419449, 0.2614611, 0.9929527, 0.12352738, 0.98977524, 0.17344923, 0.9892281, 0.81211686, + 0.32314387, 0.34503344, 0.46018234, 0.13160191, 0.20512545, 0.65847087, 0.8540127, 0.8054685, + 0.47674835, 0.41683954, 0.37222117, 0.29864943, 0.30020675, 0.03023468, 0.94694686, 0.8359962, + 0.8138952, 0.63692176, 0.26027933, 0.18633933, 0.45047382, 0.49320155, 0.570124, 0.91193676, + 0.2911521, 0.65576875, 0.46673766, 0.8632605, 0.28271404, 0.19524036, 0.32521543, 0.30401078, + 0.27383924, 0.495464, 0.46043226, 0.7826646, 0.7326602, 0.7726259, 0.90773165, 0.09807661, + 0.6721381, 0.07212267, 0.1972123, 0.8126071, 0.8127331, 0.05026847, 0.3180714, 0.6117102, + 0.31451428, 0.15695652, 0.30963218, 0.35285345, 0.9131699, 0.8028888, 0.36164302, 0.8299423, + 0.7749095, 0.54824555, 0.8404498, 0.5493567, 0.19173324, 0.9907522, 0.5227545, 0.281508, + 0.091624096, 0.06821037, 0.024810186, 0.80474275, 0.5698024, 0.16428226, 0.10333604, 0.04126928, + 0.7291901, 0.16220273, 0.5142012, 0.37835112, 0.29598927, 0.75751686, 0.09920368, 0.24088362, + 0.33769736, 0.85502744, 0.5487462, 0.12575752, 0.8856082, 0.972362, 0.3908409, 0.47095042, + 0.13382097, 0.63048995, 0.007755094, 0.18441458, 0.9321761, 0.35837498, 0.9063434, 0.6813859, + 0.5493682, 0.9157043, 0.720983, 0.7445227, 0.025458287, 0.5133287, 0.041907787, 0.15023202, + 0.053620476, 0.2683629, 0.6236633, 0.75096714, 0.28868756, 0.98329186, 0.5339531, 0.017392641, + 0.4490419, 0.5995662, 0.21165931, 0.3367058, 0.44200596, 0.39699697, 0.39589983, 0.11926211, + 0.6773695, 0.5538598, 0.6709218, 0.93931246, 0.15652716, 0.9189215, 0.10909318, 0.37081516, + 0.25585935, 0.83281535, 0.82898295, 0.38028497, 0.03653382, 0.35468096, 0.21542533, 0.8243687, + 0.81311965, 0.39851424, 0.07213704, 0.61724526, 0.34869868, 0.63987374, 0.18226288, 0.15052907, + 0.096536905, 0.99036247, 0.73537266, 0.3326099, 0.14671567, 0.5696376, 0.2393799, 0.15237123, + 0.5198045, 0.6017209, 0.067153245, 0.47159854, 0.84240687, 0.1025953, 0.99370486, 0.134699, + 0.15926972, 0.25284818, 0.4951078, 0.45587218, 0.15430894, 0.15366808, 0.9808588, 0.094360925, + 0.38414088, 0.3872906, 0.52358615, 0.043491747, 0.32485992, 0.7786546, 0.7705634, 0.037495736, + 0.37159687, 0.5203927, 0.8427756, 0.16616471, 0.18354878, 0.7764833, 0.22409947, 0.6862218, + 0.59343547, 0.6766117, 0.8604805, 0.4348129, 0.2875277, 0.7438268, 0.9819619, 0.7105244, + 0.4048094, 0.937438, 0.45797554, 0.09585048, 0.14476593, 0.7263907, 0.9962201, 0.9428688, + 0.009503636, 0.6410118, 0.94846904, 0.7594251, 0.04605143, 0.19588815, 0.8275113, 0.7411499, + 0.83115745, 0.02965751, 0.10000168, 0.32201412, 0.25981972, 0.82754016, 0.95115024, 0.38278645, + 0.02874871, 0.808886, 0.8624367, 0.47769725, 0.29318756, 0.5460459, 0.8068332, 0.6403141, + 0.4053287, 0.8130618, 0.63868237, 0.3874219, 0.320679, 0.67471296, 0.8927298, 0.64520615, + 0.5241726, 0.89990675, 0.15666108, 0.54253703, 0.82801425, 0.46467438, 0.64017034, 0.39754733, + 0.8491004, 0.11933059, 0.60365546, 0.25787023, 0.6438251, 0.65994775, 0.45070463, 0.57726926, + 0.98628783, 0.075189106, 0.06710178, 0.33587992, 0.863954, 0.51852286, 0.64968127, 0.46345773, + 0.83417857, 0.30815494, 0.35409638, 0.23298964, 0.5572058, 0.4400894, 0.4204709, 0.1564445, + 0.13692771, 0.4547955, 0.7978415, 0.35991296, 0.67087907, 0.4086132, 0.5547722, 0.56407434, + 0.16871567, 0.46488938, 0.62859684, 0.17385697, 0.94239044, 0.548963, 0.996489, 0.74538094, + 0.36235714, 0.061413143, 0.40113407, 0.24548991, 0.6076112, 0.5568499, 0.78125215, 0.005649717, + 0.2502255, 0.69320333, 0.70835847, 0.5198593, 0.110578, 0.4071807, 0.84034157, 0.40901098, + 0.6988597, 0.44721094, 0.12094251, 0.1890296, 0.86210626, 0.09079167, 0.90639013, 0.5776746, + 0.5204169, 0.50302744, 0.16716424, 0.39906463, 0.8899261, 0.47582427, 0.52106726, 0.2852156, + 0.31166598, 0.6087155, 0.87063247, 0.49579263, 0.03895533, 0.174981, 0.5488333, 0.5800778, + 0.67354333, 0.7921918, 0.10968746, 0.97767574, 0.70025474, 0.034912895, 0.45349634, 0.761535, + 0.6245478, 0.21958585, 0.47499728, 0.4951795, 0.42802048, 0.80745935, 0.8832747, 0.27156547, + 0.15502298, 0.8234595, 0.725073, 0.10458374, 0.38968566, 0.38218752, 0.11572367, 0.77440125, + 0.17213607, 0.42314288, 0.2081933, 0.5018625, 0.5365482, 0.3445489, 0.37005565, 0.5238787, + 0.8983776, 0.5408647, 0.51548624, 0.06991447, 0.9811042, 0.9287144, 0.8774199, 0.48550403, + 0.04953112, 0.40562928, 0.7745168, 0.6703402, 0.00082698837, 0.025887761, 0.8571951, 0.5042066, + 0.7254408, 0.59906703, 0.34076965, 0.21549584, 0.449908, 0.44424957, 0.19039217, 0.29135585, + 0.67646813, 0.33528623, 0.80553967, 0.27711186, 0.8267196, 0.95163375, 0.22498675, 0.2799989, + 0.8495302, 0.9511186, 0.5968019, 0.8871558, 0.2919731, 0.8133602, 0.29046127, 0.22630857, + 0.9460396, 0.23956898, 0.05505262, 0.98405635, 0.60767066, 0.4453835, 0.77357423, 0.14624831, + 0.5659478, 0.7039867, 0.7764218, 0.9374812, 0.0037792725, 0.1545598, 0.073970705, 0.45412806, + 0.35047254, 0.2241304, 0.39344636, 0.645818, 0.12317476, 0.600308, 0.65878445, 0.09789734, + 0.18064253, 0.49451795, 0.82080996, 0.049708407, 0.42908588, 0.9700393, 0.2122335, 0.9120806, + 0.30860576, 0.11446109, 0.26945624, 0.21033902, 0.38919696, 0.20633578, 0.6836851, 0.23108464, + 0.56171197, 0.6592914, 0.7111641, 0.122732915, 0.175212, 0.28750554, 0.2762196, 0.69497037, + 0.87714785, 0.14267384, 0.53668326, 0.06784272, 0.41991386, 0.6446433, 0.10313381, 0.34573162, + 0.58078456, 0.9571553, 0.8034138, 0.11315275, 0.62457347, 0.7238658, 0.71716243, 0.59590846, + 0.4917532, 0.8643412, 0.62887543, 0.88931817, 0.8851036, 0.86363167, 0.064931095, 0.14413676, + 0.54044527, 0.16236171, 0.084106006, 0.4638834, 0.8891439, 0.5360515, 0.9226853, 0.893137, + 0.21829833, 0.12583959, 0.17256053, 0.28641203, 0.4333561, 0.14439079, 0.49216673, 0.6639625, + 0.011327274, 0.9237246, 0.62955445, 0.43204167, 0.40292194, 0.5705324, 0.6065112, 0.83784616, + 0.94212896, 0.115255654, 0.6309797, 0.3108708, 0.6586301, 0.38690144, 0.8098668, 0.013516203, + 0.07774274, 0.39254647, 0.52739745, 0.25755215, 0.5605373, 0.6392504, 0.4565877, 0.044733036, + 0.034469932, 0.91027683, 0.8948544, 0.4987339, 0.5513053, 0.4307504, 0.16255233, 0.3473624, + 0.3721745, 0.96491295, 0.8779909, 0.961379, 0.2340772, 0.6328894, 0.7412148, 0.9699129, + 0.55585057, 0.24625985, 0.52175444, 0.77388823, 0.9050718, 0.61181456, 0.23450689, 0.8313969, + 0.31597278, 0.15904433, 0.20866929, 0.04080962, 0.6169933, 0.23461457, 0.1034252, 0.37207687, + 0.4671369, 0.58482146, 0.39757174, 0.4926451, 0.67567796, 0.107777245, 0.28654084, 0.5113785, + 0.9527033, 0.28361735, 0.9386963, 0.6937171, 0.50891054, 0.84848785, 0.779439, 0.44485334, + 0.65133166, 0.55748457, 0.7017016, 0.3142774, 0.11749596, 0.68269944, 0.13966125, 0.42265537, + 0.6757699, 0.06345752, 0.18276113, 0.39226097, 0.2220811, 0.12174272, 0.7303691, 0.13755992, + 0.8614878, 0.50591403, 0.4942421, 0.64925575, 0.23531766, 0.24856968, 0.29423487, 0.44807333, + 0.959719, 0.010375906, 0.82118493, 0.6214544, 0.67311823, 0.5407898, 0.3224864, 0.46748495, + 0.37960532, 0.76381594, 0.38947794, 0.05950873, 0.53291297, 0.7891478, 0.2545809, 0.7844374, + 0.44516018, 0.97491634, 0.81687516, 0.61222047, 0.9250161, 0.89427984, 0.28929746, 0.83096063, + 0.5532483, 0.8011364, 0.8322293, 0.0029964554, 0.35424575, 0.13018323, 0.20953566, 0.402762, + 0.2632497, 0.25362825, 0.3545584, 0.10712006, 0.8615145, 0.51820683, 0.7495371, 0.13498017, + 0.74097115, 0.7152762, 0.0126556605, 0.45826513, 0.73226476, 0.67086035, 0.6046469, 0.07234, + 0.25133318, 0.70980465, 0.20409557, 0.2604013, 0.43169454, 0.6820144, 0.5230572, 0.065439165, + 0.72107846, 0.99022436, 0.06820616, 0.87198186, 0.70856047, 0.31948993, 0.11323921, 0.24942209, + 0.5542803, 0.9867159, 0.79625905, 0.27928472, 0.4345894, 0.14746083, 0.9229229, 0.9269534, + 0.22537923, 0.681895, 0.8712493, 0.20973994, 0.8816242, 0.83103234, 0.098695815, 0.88238794, + 0.19648944, 0.75988936, 0.75166327, 0.64444107, 0.9260877, 0.94913435, 0.9710675, 0.5812353, + 0.7305711, 0.28911924, 0.3860416, 0.87129015, 0.45000067, 0.87755525, 0.42641973, 0.4214812, + 0.60203695, 0.7632336, 0.90398484, 0.74554884, 0.8746013, 0.32536224, 0.6377506, 0.10387234, + 0.7868817, 0.2771422, 0.035022065, 0.74979955, 0.8107651, 0.31331727, 0.18381497, 0.8900461, + 0.89152855, 0.18581823, 0.6754924, 0.9486711, 0.5678266, 0.4687981, 0.32333443, 0.60514593, + 0.015648454, 0.21502374, 0.5487136, 0.14547014, 0.76141924, 0.05163277, 0.4769527, 0.34782398, + 0.25547525, 0.44976813, 0.607703, 0.11839061, 0.9270475, 0.35314697, 0.007786621, 0.8711272, + 0.12213872, 0.64779097, 0.8575594, 0.64894545, 0.9141123, 0.22126794, 0.77047014, 0.4172538, + 0.10530428, 0.4959955, 0.97976166, 0.26418245, 0.20206283, 0.47774863, 0.85365456, 0.13323887, + 0.43989918, 0.29883888, 0.7299004, 0.65957755, 0.7766486, 0.49228048, 0.34245312, 0.7352489, + 0.8001895, 0.6871981, 0.49432427, 0.360997, 0.70561427, 0.06542435, 0.96299857, 0.5383816, + 0.1780316, 0.8043652, 0.82653236, 0.92003566, 0.6112387, 0.67438895, 0.6910336, 0.79438055, + 0.44455358, 0.13145985, 0.04016586, 0.26542372, 0.07187113, 0.21277027, 0.14576113, 0.77772665, + 0.59611356, 0.47446412, 0.6784915, 0.62820864, 0.62324655, 0.34820905, 0.094478644, 0.62985826, + 0.30533785, 0.122310445, 0.84875596, 0.22691421, 0.7269437, 0.40947318, 0.7116395, 0.039879926, + 0.5329969, 0.44138008, 0.08615084, 0.39769763, 0.65121627, 0.93361884, 0.52200013, 0.7655102, + 0.60780525, 0.9355199, 0.21502401, 0.64518875, 0.45211464, 0.0770294, 0.6633778, 0.5874192, + 0.541437, 0.7165977, 0.7648834, 0.2311502, 0.3869329, 0.33478996, 0.915135, 0.82982254, + 0.70988655, 0.19667415, 0.6146979, 0.4889283, 0.825633, 0.46411943, 0.067436874, 0.035080392, + 0.41982034, 0.0002859342, 0.7324268, 0.630491, 0.12661943, 0.7480635, 0.12651038, 0.6624947, + 0.952464, 0.9129812, 0.020403363, 0.6877267, 0.13318504, 0.44928992, 0.1777436, 0.22830844, + 0.45893264, 0.2613367, 0.68547726, 0.010346001, 0.6445898, 0.4804893, 0.652947, 0.19820693, + 0.52624506, 0.25632828, 0.687811, 0.4545421, 0.31892103, 0.033071853, 0.9398772, 0.14368583, + 0.868083, 0.17994362, 0.2253684, 0.4518287, 0.34460258, 0.032886766, 0.4607998, 0.7933734, + 0.59008723, 0.10238874, 0.27868623, 0.47395167, 0.3143866, 0.22740832, 0.6966375, 0.26059666, + 0.018930554, 0.3863894, 0.029995646, 0.5642963, 0.7786422, 0.05709087, 0.39049065, 0.939331, + 0.3473389, 0.53421986, 0.10424597, 0.8702912, 0.060252476, 0.6719683, 0.34357366, 0.9193921, + 0.97310406, 0.8767175, 0.8196437, 0.9532414, 0.22392152, 0.7259149, 0.88370585, 0.42604586, + 0.80053693, 0.8921038, 0.42025873, 0.54220104, 0.2018031, 0.17899537, 0.8838203, 0.29883677, + 0.5596908, 0.42721438, 0.43561155, 0.9325316, 0.0030762074, 0.37558094, 0.36504367, 0.8109921, + 0.78945297, 0.2860374, 0.10448979, 0.8103827, 0.9286408, 0.59050864, 0.733121, 0.91811895, + 0.75881505, 0.35929412, 0.50084764, 0.4376691, 0.40776464, 0.7433961, 0.036675144, 0.29301566, + 0.5026836, 0.6039498, 0.7637594, 0.8865383, 0.6368321, 0.8482896, 0.7375279, 0.16834354, + 0.65039957, 0.8054092, 0.31060037, 0.6330381, 0.23635677, 0.41104206, 0.9163159, 0.5975231, + 0.51167387, 0.008651535, 0.16378845, 0.93788415, 0.62142515, 0.07332315, 0.49740508, 0.21002825, + 0.15898286, 0.5021398, 0.78338593, 0.842509, 0.67814773, 0.44615123, 0.8910721, 0.81629467, + 0.39053923, 0.14259589, 0.42984807, 0.39912644, 0.61182153, 0.47850534, 0.17416, 0.94116336, + 0.5485095, 0.93614626, 0.15998314, 0.12323159, 0.27990827, 0.10008287, 0.6817622, 0.34777302, + 0.4429782, 0.9033245, 0.92599523, 0.39911312, 0.57960767, 0.09879101, 0.6715905, 0.4293604, + 0.1065447, 0.55373114, 0.72755545, 0.13469236, 0.06490368, 0.89501894, 0.4901958, 0.20424834, + 0.9143371, 0.4943057, 0.24249884, 0.093760885, 0.98119396, 0.5171895, 0.98570156, 0.03316852, + 0.83449155, 0.22262509, 0.38937467, 0.6852789, 0.91334003, 0.3741735, 0.93012, 0.05889999, + 0.8203776, 0.43561292, 0.3995308, 0.77482325, 0.52015597, 0.491959, 0.23668702, 0.29174823, + 0.47100535, 0.0004876647, 0.29258174, 0.058090426, 0.75094986, 0.039467655, 0.8762597, 0.65349054, + 0.44595045, 0.9557348, 0.20889449, 0.78560257, 0.857584, 0.5880013, 0.36657903, 0.9257887, + 0.917623, 0.89282674, 0.56462157, 0.35698256, 0.70941633, 0.9863116, 0.51602036, 0.7323712, + 0.62361115, 0.6686555, 0.31431475, 0.62929076, 0.4954881, 0.71537256, 0.68409234, 0.4223781, + 0.2576187, 0.9507506, 0.6227555, 0.98070633, 0.22460775, 0.9276111, 0.28221866, 0.79502386, + 0.34636542, 0.73588413, 0.23932843, 0.95760524, 0.165279, 0.1445174, 0.20131597, 0.23237628, + 0.069033906, 0.47374207, 0.85720026, 0.62732923, 0.9273374, 0.8797045, 0.5823319, 0.48469374, + 0.48446727, 0.5602105, 0.43447927, 0.08229436, 0.7251529, 0.24696892, 0.15800244, 0.7305779, + 0.27164242, 0.78651637, 0.52798384, 0.9068334, 0.9652458, 0.3858727, 0.701181, 0.9900118, + 0.61060804, 0.7695977, 0.010617126, 0.97353226, 0.74698323, 0.5584152, 0.56709224, 0.47909376, + 0.46733952, 0.08193848, 0.56025684, 0.021746036, 0.8581723, 0.056763105, 0.49504068, 0.37791422, + 0.36841872, 0.13806179, 0.49623904, 0.66439724, 0.49313185, 0.19992432, 0.06987098, 0.09939649, + 0.5778817, 0.50875056, 0.6859628, 0.3787626, 0.6165335, 0.29448256, 0.2671305, 0.6831612, + 0.77256113, 0.86718845, 0.016721206, 0.1577397, 0.86908734, 0.60879964, 0.73771054, 0.9260521, + 0.9931183, 0.9553855, 0.6149548, 0.6432144, 0.6867121, 0.1362564, 0.8724056, 0.21487932, + 0.2914757, 0.15006965, 0.53841466, 0.827184, 0.88963366, 0.03678374, 0.49687997, 0.41068372, + 0.69972676, 0.9112206, 0.39565054, 0.23823264, 0.8724524, 0.18832962, 0.8625602, 0.17285694, + 0.814808, 0.87709564, 0.24918492, 0.99098384, 0.0400419, 0.337301, 0.50882685, 0.7596191, + 0.4003513, 0.5701869, 0.67127895, 0.5377463, 0.58496946, 0.42665657, 0.4126844, 0.4416253, + 0.63634497, 0.47108346, 0.08728689, 0.4664639, 0.75606793, 0.4399465, 0.79352754, 0.7357774, + 0.3703085, 0.6060375, 0.45801297, 0.9578667, 0.2131491, 0.49947786, 0.05359975, 0.8047887, + 0.092825316, 0.4420979, 0.82840645, 0.80961645, 0.8870715, 0.88142174, 0.17483743, 0.95417476, + 0.6412428, 0.7787956, 0.4268327, 0.31944674, 0.3655048, 0.9591336, 0.82571423, 0.2730702, + 0.49853623, 0.95402527, 0.6018877, 0.4013689, 0.10104273, 0.39609635, 0.41678905, 0.37486148, + 0.083568096, 0.5134075, 0.6206753, 0.43400443, 0.879288, 0.5509602, 0.54647, 0.9008734, + 0.5165872, 0.86649024, 0.44492102, 0.14287159, 0.59825015, 0.60306793, 0.5545538, 0.7549232, + 0.29624605, 0.13311216, 0.8252211, 0.97727233, 0.013113789, 0.4740808, 0.37027258, 0.41117483, + 0.7803232, 0.18494278, 0.45933047, 0.25912383, 0.89759016, 0.65223086, 0.70374596, 0.696729, + 0.02530885, 0.45354494, 0.72604835, 0.37366393, 0.2607464, 0.740833, 0.07488672, 0.09028263, + 0.23232558, 0.5259593, 0.80285954, 0.49901456, 0.5142126, 0.6828427, 0.67482007, 0.8954683, + 0.39947143, 0.8469645, 0.10512285, 0.96793056, 0.5708752, 0.43951672, 0.3617477, 0.6094873, + 0.14313498, 0.2095005, 0.6536812, 0.69434524, 0.09162968, 0.28734615, 0.0032832306, 0.86435634, + 0.1627443, 0.748192, 0.11756273, 0.14470519, 0.8770196, 0.1808899, 0.49417683, 0.55541307, + 0.05822544, 0.73493844, 0.7449467, 0.48715448, 0.67122126, 0.871258, 0.8969622, 0.097480536, + 0.5101227, 0.5638622, 0.8596524, 0.050625734, 0.547108, 0.7358154, 0.12585375, 0.5857921, + 0.09179724, 0.11656108, 0.23052894, 0.051245883, 0.08715177, 0.38054147, 0.99865294, 0.9449794, + 0.52267605, 0.93850327, 0.33627024, 0.7660206, 0.56527996, 0.5301148, 0.018448701, 0.21858154, + 0.3527876, 0.5497098, 0.90970516, 0.8359368, 0.69457, 0.8745932, 0.93826604, 0.27187696, + 0.3125383, 0.5562007, 0.1842225, 0.5277675, 0.42769375, 0.9526575, 0.3172483, 0.42692894, + 0.6223383, 0.5317706, 0.05290796, 0.7604585, 0.95036095, 0.44293094, 0.46826127, 0.67768395, + 0.7362855, 0.7999673, 0.96447843, 0.732718, 0.53498775, 0.13094164, 0.5322006, 0.9800079, + 0.5454135, 0.64107084, 0.6978381, 0.9973982, 0.82611024, 0.28991696, 0.8912221, 0.21720403, + 0.17829505, 0.95865196, 0.7387076, 0.5309511, 0.19631897, 0.47088546, 0.5172857, 0.5700186, + 0.6212549, 0.90934134, 0.14368229, 0.033509336, 0.4772069, 0.25799018, 0.26822057, 0.9098567, + 0.08144851, 0.23202117, 0.09965124, 0.8946027, 0.91011477, 0.20554802, 0.7368892, 0.18159665, + 0.024000084, 0.20421462, 0.982354, 0.7866229, 0.2548194, 0.31985012, 0.6008187, 0.33242133, + 0.64054847, 0.8357039, 0.58216345, 0.991709, 0.70422333, 0.93731016, 0.481365, 0.26540005, + 0.2826816, 0.39445987, 0.1114631, 0.6256465, 0.9872593, 0.49869126, 0.502801, 0.2874233, + 0.37285027, 0.78798145, 0.9159497, 0.5940891, 0.19026573, 0.99661946, 0.30708927, 0.972747, + 0.22176278, 0.55711097, 0.50695103, 0.99210435, 0.48853147, 0.73066276, 0.31519917, 0.3014048, + 0.30852264, 0.81126094, 0.39296088, 0.641503, 0.6758267, 0.27651158, 0.20563333, 0.14413832, + 0.7506562, 0.83425117, 0.6119211, 0.5156549, 0.094084926, 0.111242734, 0.1943373, 0.52530885, + 0.70141363, 0.6949307, 0.41377264, 0.46683794, 0.4039004, 0.006729609, 0.14215559, 0.643929, + 0.52861464, 0.6094164, 0.7699462, 0.1471124, 0.43035918, 0.4892606, 0.7768686, 0.5520188, + 0.07926069, 0.8100583, 0.31712383, 0.17599839, 0.105730385, 0.861298, 0.6115966, 0.096338674, + 0.5823481, 0.77181137, 0.8434329, 0.35601455, 0.38469836, 0.79143435, 0.8786621, 0.11052005, + 0.36277366, 0.9816422, 0.29069075, 0.7936008, 0.31689015, 0.84836125, 0.8975044, 0.30179304, + 0.66910535, 0.7490319, 0.1128883, 0.06641029, 0.5065654, 0.058520928, 0.71377915, 0.26139554, + 0.057382602, 0.059902266, 0.4363942, 0.28402662, 0.7941189, 0.018338913, 0.41957843, 0.84011555, + 0.083334126, 0.31743395, 0.88448983, 0.632089, 0.16329671, 0.78614104, 0.2592306, 0.7371803, + 0.7307543, 0.65942615, 0.7843387, 0.448717, 0.19856988, 0.9832678, 0.23512867, 0.23089947, + 0.9125539, 0.015330798, 0.50689304, 0.3566985, 0.74840975, 0.5451863, 0.5897733, 0.5238272, + 0.05803223, 0.5820373, 0.29863194, 0.3247961, 0.35504016, 0.5946355, 0.31640115, 0.34443474, + 0.56206375, 0.45057517, 0.71026665, 0.99945617, 0.9638714, 0.26541534, 0.13849631, 0.8829643, + 0.48980126, 0.375708, 0.33565596, 0.84713924, 0.2741822, 0.26506215, 0.06282568, 0.07411481, + 0.8247736, 0.20549475, 0.37147272, 0.7787881, 0.5114459, 0.06287994, 0.09170583, 0.53814787, + 0.72766066, 0.36066267, 0.5740568, 0.58125937, 0.4875091, 0.93443453, 0.38214013, 0.13611887, + 0.343025, 0.439904, 0.88665324, 0.7479947, 0.27300113, 0.23567249, 0.26702806, 0.64713854, + 0.8768345, 0.62392867, 0.8668972, 0.37270173, 0.20953032, 0.74263406, 0.249645, 0.79297006, + 0.51921165, 0.22451714, 0.50002253, 0.14954542, 0.22316273, 0.53761303, 0.83298886, 0.4991838, + 0.35886934, 0.17211881, 0.2717955, 0.6032087, 0.6913585, 0.5572369, 0.3954552, 0.55536675, + 0.9935679, 0.19953707, 0.5041142, 0.83427817, 0.3784089, 0.314831, 0.80111367, 0.58910114, + 0.93846667, 0.7243342, 0.90195364, 0.8875172, 0.19598271, 0.7190041, 0.3286175, 0.9850266, + 0.11101766, 0.78108674, 0.06204771, 0.26299196, 0.434412, 0.23259473, 0.9129562, 0.805412, + 0.6069152, 0.38746944, 0.38912535, 0.10088234, 0.96387696, 0.6638193, 0.95578, 0.31959754, + 0.22847345, 0.3115305, 0.37913388, 0.009993258, 0.23851983, 0.4153668, 0.41456118, 0.20438069, + 0.42340347, 0.9109214, 0.21107873, 0.49882856, 0.6356594, 0.94547164, 0.3032011, 0.6398653, + 0.84350127, 0.28676888, 0.49219108, 0.91027176, 0.49518922, 0.13246326, 0.120954745, 0.76097316, + 0.28658092, 0.6987022, 0.22736304, 0.99093944, 0.9257056, 0.7002313, 0.6252242, 0.27464733, + 0.76855415, 0.5823561, 0.6590438, 0.8844522, 0.3398702, 0.31862426, 0.7465068, 0.6956509, + 0.36652556, 0.857667, 0.8395885, 0.5234906, 0.021515984, 0.4141276, 0.16975257, 0.66144353, + 0.084268354, 0.74926007, 0.25738105, 0.67710805, 0.17162827, 0.045508236, 0.8244083, 0.0960102, + 0.19057575, 0.6181607, 0.72341233, 0.5398176, 0.18800376, 0.4236217, 0.27867505, 0.7231721, + 0.28569725, 0.9364314, 0.73027444, 0.05330333, 0.28642786, 0.4187489, 0.29999506, 0.524877, + 0.5402621, 0.7965402, 0.54374623, 0.6375222, 0.29287475, 0.59746414, 0.73945713, 0.87245333, + 0.5289497, 0.56591946, 0.9066711, 0.17644554, 0.4428503, 0.94811606, 0.10301907, 0.7230459, + 0.75794774, 0.5630336, 0.69387645, 0.7217095, 0.5952119, 0.20668921, 0.5076471, 0.9429038, + 0.57899195, 0.116416365, 0.23779334, 0.08508458, 0.6838532, 0.11644924, 0.3750157, 0.6655195, + 0.44926503, 0.73250407, 0.13684598, 0.37508807, 0.50176203, 0.1868861, 0.80313545, 0.59311163, + 0.8787036, 0.850959, 0.0108679095, 0.62208426, 0.5169506, 0.10222952, 0.28032187, 0.3375812, + 0.83341235, 0.0072284974, 0.2953556, 0.7233943, 0.7248724, 0.5782856, 0.9296651, 0.3335729, + 0.28889313, 0.6008424, 0.05853025, 0.17645839, 0.3596708, 0.6543726, 0.18860014, 0.41250044, + 0.19090378, 0.24115163, 0.7271805, 0.7103462, 0.8112701, 0.727931, 0.22128391, 0.5710617, + 0.7598981, 0.10076484, 0.8430059, 0.7442529, 0.1958213, 0.8855628, 0.4259532, 0.47676244, + 0.8360945, 0.90021217, 0.25167224, 0.67662466, 0.8210937, 0.6516214, 0.940647, 0.8709795, + 0.802839, 0.8032731, 0.08619493, 0.9009196, 0.12835586, 0.62667704, 0.2334408, 0.224331, + 0.6623589, 0.59836745, 0.4311805, 0.27579898, 0.37504902, 0.5699756, 0.5263111, 0.10548131, + 0.7859446, 0.72429395, 0.96349615, 0.6241076, 0.7352797, 0.18541217, 0.13775158, 0.40333033, + 0.17488916, 0.5817678, 0.34036386, 0.45945865, 0.40270033, 0.51197547, 0.59140676, 0.5392824, + 0.3005046, 0.85620105, 0.9075073, 0.007996995, 0.6417361, 0.3203643, 0.44270578, 0.13322107, + 0.86732405, 0.6186749, 0.08189404, 0.59745383, 0.4543823, 0.15015423, 0.10171343, 0.2661189, + 0.37390104, 0.14619094, 0.8906801, 0.096799746, 0.68812525, 0.31653944, 0.13569976, 0.6174268, + 0.6655215, 0.6828646, 0.72603047, 0.54658806, 0.28631318, 0.77398217, 0.8216307, 0.15038341, + 0.0069607063, 0.8918981, 0.97529435, 0.518848, 0.6624684, 0.5183141, 0.46374524, 0.4655803, + 0.28158814, 0.83027506, 0.75678355, 0.11660483, 0.10351813, 0.54029775, 0.948948, 0.024734931, + 0.48005438, 0.074244976, 0.0855576, 0.2565094, 0.62129533, 0.49460703, 0.85115707, 0.98396516, + 0.7205013, 0.2900805, 0.34247547, 0.9588715, 0.5943338, 0.89611775, 0.8469079, 0.09334188, + 0.79704416, 0.9315106, 0.59049314, 0.5624842, 0.17485987, 0.5828654, 0.60365057, 0.85558695, + 0.6824457, 0.4250998, 0.8152116, 0.8578502, 0.55975586, 0.01909494, 0.5139087, 0.12522376, + 0.73391664, 0.7012955, 0.06653367, 0.2120682, 0.6884245, 0.5651213, 0.5290881, 0.51235366, + 0.040741026, 0.9913292, 0.7983467, 0.3723879, 0.17583862, 0.50487375, 0.87124646, 0.3854704, + 0.9833672, 0.66344166, 0.31956065, 0.1720075, 0.94980466, 0.38646382, 0.8498751, 0.89718896, + 0.4705944, 0.22997065, 0.57406366, 0.19619557, 0.67939544, 0.9933069, 0.4242093, 0.70140636, + 0.7761718, 0.21725173, 0.22495484, 0.89303833, 0.82958406, 0.6348397, 0.40491733, 0.23192288, + 0.40242258, 0.07813944, 0.5217432, 0.18353066, 0.7845187, 0.23126268, 0.6797483, 0.17757194, + 0.55385333, 0.42974123, 0.874483, 0.8963142, 0.6995343, 0.34190118, 0.17541912, 0.34745282, + 0.85142046, 0.16934472, 0.7414738, 0.4584539, 0.99105763, 0.33289248, 0.8329583, 0.04743413, + 0.5671199, 0.09694037, 0.5962161, 0.9585869, 0.2799189, 0.9782081, 0.5558863, 0.3485275, + 0.25852436, 0.08763776, 0.76958495, 0.8716652, 0.86472064, 0.6663444, 0.1126702, 0.23933174, + 0.55022234, 0.39649174, 0.64234227, 0.24965419, 0.118823886, 0.5278951, 0.0018720366, 0.43427062, + 0.04183261, 0.877502, 0.04161787, 0.66023934, 0.8933659, 0.9464634, 0.24086526, 0.069530085, + 0.24518117, 0.47430903, 0.61641073, 0.6875784, 0.6350466, 0.7211614, 0.89765304, 0.5756452, + 0.87385494, 0.5259555, 0.63778985, 0.6118965, 0.5723162, 0.3037539, 0.48273215, 0.18507604, + 0.05667453, 0.5021421, 0.90823156, 0.59456587, 0.69055027, 0.5833041, 0.92861027, 0.039224792, + 0.095068336, 0.16194543, 0.9167543, 0.40241688, 0.93659025, 0.895647, 0.4551616, 0.31206095, + 0.8467725, 0.7000548, 0.62648404, 0.39041162, 0.049933646, 0.42509183, 0.6042851, 0.8290609, + 0.49883872, 0.06669706, 0.37579927, 0.5928684, 0.89010525, 0.3899755, 0.8619544, 0.7380787, + 0.39476988, 0.8565418, 0.6035648, 0.39122385, 0.038231853, 0.64629936, 0.37897983, 0.6618771, + 0.54569876, 0.577186, 0.59251004, 0.47310117, 0.8044071, 0.49523613, 0.6390549, 0.97820795, + 0.07079393, 0.3257289, 0.765124, 0.8722614, 0.6772699, 0.092320524, 0.1351424, 0.6315827, + 0.89785695, 0.07917066, 0.09572715, 0.6238532, 0.20750481, 0.33574188, 0.14911953, 0.70509285, + 0.29999104, 0.1786756, 0.0076469877, 0.08004845, 0.29208216, 0.063937746, 0.27382907, 0.20047311, + 0.32107502, 0.96460694, 0.84471285, 0.47274768, 0.8325818, 0.13118395, 0.024653764, 0.0036025788, + 0.42764217, 0.39759132, 0.52207446, 0.56437635, 0.62485147, 0.989693, 0.060808785, 0.30244938, + 0.7213994, 0.9719821, 0.49336693, 0.9590612, 0.5505722, 0.75512666, 0.4543723, 0.2099569, + 0.42806646, 0.8874172, 0.17311013, 0.6257315, 0.48758915, 0.55900645, 0.68612576, 0.0068561803, + 0.051899806, 0.56465095, 0.5511864, 0.71266294, 0.2476077, 0.6623947, 0.7990009, 0.76667297, + 0.054516893, 0.092124574, 0.19621104, 0.80991346, 0.8136675, 0.58474314, 0.08024137, 0.31029803, + 0.117866814, 0.70519763, 0.35864902, 0.32010004, 0.5705708, 0.3147679, 0.64990085, 0.56594837, + 0.51023465, 0.6347559, 0.044681232, 0.94516456, 0.9580738, 0.39892223, 0.51601344, 0.8686357, + 0.71146554, 0.51521826, 0.51247656, 0.06020054, 0.43850663, 0.3481458, 0.054841675, 0.059004717, + 0.1729812, 0.7266939, 0.9045443, 0.45844766, 0.5589156, 0.6444588, 0.39628944, 0.8433233, + 0.8071758, 0.8628121, 0.5078647, 0.78239155, 0.20035744, 0.36602575, 0.43628535, 0.7371319, + 0.91475004, 0.985238, 0.20242831, 0.61285174, 0.6177135, 0.8538363, 0.8085992, 0.65559465, + 0.57611114, 0.32757533, 0.09844793, 0.2984492, 0.07226656, 0.020040827, 0.87179136, 0.769721, + 0.65035594, 0.2996443, 0.14711884, 0.8438769, 0.4102236, 0.1914532, 0.007032739, 0.8657759, + 0.23846649, 0.20135792, 0.13798875, 0.09526171, 0.8910575, 0.7336219, 0.6682783, 0.34543982, + 0.078932896, 0.77534467, 0.14545049, 0.45326862, 0.14571752, 0.44198993, 0.44129124, 0.31914487, + 0.9180948, 0.24894963, 0.8823365, 0.23134027, 0.54601085, 0.09784024, 0.7710568, 0.787135, + 0.99102074, 0.73814374, 0.13203558, 0.90071315, 0.2189069, 0.5924085, 0.32690832, 0.7232968, + 0.97820526, 0.33665246, 0.37438527, 0.41635555, 0.71584755, 0.7133375, 0.76453716, 0.84248924, + 0.6592971, 0.7530081, 0.2195163, 0.29692188, 0.87459034, 0.41852275, 0.62400347, 0.20836602, + 0.8583531, 0.82797396, 0.9257821, 0.16127396, 0.3091167, 0.77569246, 0.31976497, 0.14062625, + 0.43030116, 0.35085374, 0.104240976, 0.15291376, 0.6015863, 0.76756513, 0.12653293, 0.48652443, + 0.44843635, 0.42215365, 0.47506335, 0.80906504, 0.06760467, 0.02493567, 0.6032973, 0.20475733, + 0.48441246, 0.039847255, 0.5720432, 0.7930028, 0.8783239, 0.47413486, 0.91254467, 0.57249796, + 0.11414025, 0.9236696, 0.042360075, 0.39093295, 0.6666264, 0.16563436, 0.41418016, 0.20251282, + 0.016887465, 0.23375902, 0.9860544, 0.36499384, 0.60909647, 0.6116234, 0.24090295, 0.891732, + 0.6264752, 0.7329919, 0.8484855, 0.45243672, 0.9434594, 0.8149384, 0.14076136, 0.8334174, + 0.22467664, 0.72102475, 0.6768615, 0.26926944, 0.20364925, 0.52676225, 0.2623023, 0.95616627, + 0.43830907, 0.531743, 0.03877351, 0.67791677, 0.72520506, 0.7356, 0.81989807, 0.282802, + 0.007973485, 0.27255052, 0.7921776, 0.8338457, 0.038881265, 0.23830348, 0.59566087, 0.872789, + 0.7989443, 0.68031126, 0.16652757, 0.14533207, 0.62564933, 0.46010798, 0.6290386, 0.29920182, + 0.7829082, 0.20894268, 0.16625631, 0.94560164, 0.48877287, 0.14491072, 0.9988636, 0.49012524, + 0.9714567, 0.029888112, 0.92668474, 0.07735347, 0.5728499, 0.5629862, 0.16652691, 0.8908752, + 0.91309386, 0.56568354, 0.44446322, 0.67090887, 0.022760825, 0.3069157, 0.7945361, 0.9863731, + 0.12536389, 0.80407244, 0.47032514, 0.523338, 0.36023465, 0.11697024, 0.33051696, 0.9782011, + 0.9027044, 0.7395717, 0.89500856, 0.51626235, 0.5693437, 0.8742964, 0.7940291, 0.86306274, + 0.27368698, 0.30205235, 0.86238897, 0.008993154, 0.31161872, 0.5183074, 0.29993913, 0.2359581, + 0.51378435, 0.27565238, 0.23223823, 0.059965752, 0.01564475, 0.9581297, 0.276441, 0.4759925, + 0.41440654, 0.17988315, 0.82023776, 0.68470037, 0.6745856, 0.47552556, 0.12989059, 0.85448647, + 0.69937116, 0.94848365, 0.17464903, 0.83327824, 0.6679777, 0.65026456, 0.32153153, 0.038797423, + 0.7716544, 0.58140045, 0.3972219, 0.7207085, 0.44452676, 0.78554296, 0.67475444, 0.6070565, + 0.50413334, 0.23436703, 0.009553685, 0.08458229, 0.884732, 0.27055123, 0.96255636, 0.9445748, + 0.46313068, 0.41901603, 0.10185582, 0.38946053, 0.05405868, 0.10932874, 0.18847717, 0.79816145, + 0.17216177, 0.007902476, 0.30962202, 0.36313507, 0.34365836, 0.46666092, 0.5679804, 0.8635198, + 0.9541208, 0.19344081, 0.2883113, 0.4342443, 0.5609078, 0.55573255, 0.03146575, 0.6288636, + 0.50512874, 0.21318124, 0.18056706, 0.44021857, 0.46597186, 0.045308296, 0.96975446, 0.42881992, + 0.9859273, 0.23007429, 0.37014756, 0.24896163, 0.54840875, 0.932071, 0.98473877, 0.6623257, + 0.39292327, 0.5990605, 0.5485467, 0.4366243, 0.47592095, 0.31161934, 0.26339814, 0.037472416, + 0.6663866, 0.1460339, 0.13046144, 0.6912912, 0.9822399, 0.528312, 0.38366696, 0.90739816, + 0.3875503, 0.47299224, 0.88433176, 0.8408774, 0.92876166, 0.7482586, 0.33218956, 0.12685347, + 0.038148023, 0.8808021, 0.37720776, 0.11358407, 0.09651337, 0.3190188, 0.31511107, 0.022049852, + 0.20870206, 0.6259856, 0.041321024, 0.9618473, 0.007185834, 0.5948415, 0.15294261, 0.19350938, + 0.9497831, 0.14309464, 0.77383196, 0.31993797, 0.91484684, 0.27846324, 0.44658, 0.45761526, + 0.8464073, 0.46274942, 0.86141133, 0.075416476, 0.0477392, 0.14386131, 0.733564, 0.64466465, + 0.26687092, 0.42169324, 0.39847627, 0.5951189, 0.9344116, 0.14981407, 0.94095904, 0.3473678, + 0.83092284, 0.108411595, 0.48258916, 0.3562543, 0.48699102, 0.42181966, 0.9002123, 0.7927088, + 0.32004964, 0.6908224, 0.8910943, 0.78566706, 0.9744266, 0.012251603, 0.21200661, 0.7596848, + 0.4342221, 0.9195925, 0.26717675, 0.63376397, 0.45760745, 0.2396946, 0.97431064, 0.06484076, + 0.8924216, 0.39665636, 0.6949764, 0.5854926, 0.1963652, 0.5578238, 0.2590978, 0.799969, + 0.2021356, 0.42646417, 0.48901513, 0.8064353, 0.7958741, 0.0903257, 0.9706242, 0.42458767, + 0.56253713, 0.068702534, 0.75536686, 0.3569168, 0.25276697, 0.94789696, 0.670238, 0.2546193, + 0.2096866, 0.6387915, 0.16089676, 0.01481907, 0.8826373, 0.3071951, 0.8897603, 0.59122825, + 0.13410094, 0.4177484, 0.4638327, 0.09033466, 0.72684324, 0.3147197, 0.5963436, 0.76222587, + 0.43172458, 0.091125324, 0.58353144, 0.5479625, 0.52323645, 0.40557137, 0.9638107, 0.3438964, + 0.9489683, 0.8425891, 0.07122685, 0.38890493, 0.48432773, 0.61739385, 0.8120738, 0.9445246, + 0.7264184, 0.4403571, 0.375806, 0.55757374, 0.396927, 0.24427874, 0.9173317, 0.8949405, + 0.5367038, 0.8977869, 0.6723343, 0.3781257, 0.626493, 0.88028955, 0.6977444, 0.24781741, + 0.4723589, 0.993141, 0.9251922, 0.16164163, 0.36436552, 0.12227554, 0.73138285, 0.80411524, + 0.6749808, 0.8170004, 0.06585078, 0.040048227, 0.23596825, 0.5008554, 0.10690048, 0.51670706, + 0.6056746, 0.5193081, 0.3639163, 0.28648618, 0.9389137, 0.03876988, 0.36529887, 0.18744585, + 0.17379361, 0.68859094, 0.011258623, 0.62544954, 0.733237, 0.585685, 0.7174034, 0.06867873, + 0.14484468, 0.82340944, 0.916546, 0.49118677, 0.6922017, 0.65043217, 0.58015907, 0.60414284, + 0.70897424, 0.57169074, 0.8825929, 0.5799266, 0.17842796, 0.8772835, 0.65897226, 0.03584844, + 0.7908864, 0.15562724, 0.7724511, 0.10718488, 0.5163733, 0.41125825, 0.3089037, 0.43358904, + 0.62784207, 0.73774636, 0.98784804, 0.6757746, 0.111016914, 0.10593328, 0.07087821, 0.08929581, + 0.09959695, 0.99717206, 0.89520353, 0.4125588, 0.5843094, 0.6157137, 0.82450545, 0.95524246, + 0.939149, 0.7597735, 0.5775119, 0.36722296, 0.15617695, 0.78537226, 0.009017896, 0.29651013, + 0.029618707, 0.97541016, 0.83456314, 0.5776098, 0.8132339, 0.6102185, 0.55230546, 0.73358643, + 0.51450574, 0.48295695, 0.86334467, 0.9544553, 0.6625841, 0.90438455, 0.49312592, 0.603041, + 0.50081253, 0.7932971, 0.4803297, 0.1812559, 0.9820799, 0.24641345, 0.45153904, 0.1751727, + 0.3311218, 0.81720865, 0.16803588, 0.7565998, 0.8337463, 0.9416807, 0.2774121, 0.8424698, + 0.7287285, 0.6913379, 0.64615583, 0.13560674, 0.27137014, 0.4932684, 0.27606192, 0.48937842, + 0.4448666, 0.16161712, 0.89805305, 0.10135246, 0.75236905, 0.87005013, 0.29265827, 0.034764472, + 0.26664755, 0.9744709, 0.86641043, 0.3628798, 0.30504256, 0.827762, 0.31443018, 0.7832053, + 0.5238711, 0.65939045, 0.246488, 0.9960252, 0.44218266, 0.7957057, 0.8998401, 0.572825, + 0.20554484, 0.020874852, 0.22572684, 0.97124624, 0.2582287, 0.35751918, 0.33167085, 0.007544129, + 0.5172352, 0.99095124, 0.73638934, 0.8204628, 0.34836042, 0.3501866, 0.4228037, 0.46107167, + 0.5245504, 0.1332714, 0.48995224, 0.8592754, 0.07527029, 0.91453224, 0.53742725, 0.90096647, + 0.3769077, 0.8629506, 0.6117356, 0.61197966, 0.2467804, 0.2800367, 0.047195755, 0.6491609, + 0.261777, 0.32522804, 0.8958076, 0.7314942, 0.6443233, 0.32141203, 0.7765358, 0.90912837, + 0.6428001, 0.85886633, 0.8456446, 0.31409132, 0.09137268, 0.49396735, 0.43484485, 0.17368458, + 0.23658675, 0.78541636, 0.47147486, 0.30891126, 0.30575344, 0.040564716, 0.49755472, 0.2910126, + 0.48344758, 0.32476038, 0.59433854, 0.39527807, 0.7457836, 0.71969116, 0.76076376, 0.23719852, + 0.9437555, 0.087228395, 0.55868584, 0.023132376, 0.45437896, 0.6913095, 0.8167484, 0.20313835, + 0.35673562, 0.58082384, 0.2164753, 0.21640398, 0.06888765, 0.22333595, 0.8095938, 0.88294035, + 0.42810574, 0.43805102, 0.37539294, 0.46136406, 0.80856186, 0.7382845, 0.34340748, 0.2212123, + 0.8276733, 0.60479504, 0.24804658, 0.3195629, 0.7270735, 0.3812577, 0.16334477, 0.92310894, + 0.09810257, 0.6084461, 0.37033582, 0.004144284, 0.9352815, 0.41171247, 0.71930563, 0.54527724, + 0.968668, 0.2683365, 0.9521756, 0.7249296, 0.8240894, 0.28115076, 0.22212493, 0.26011166, + 0.5151666, 0.71139824, 0.9671723, 0.3077326, 0.3442982, 0.29939967, 0.42863667, 0.20547101, + 0.7438209, 0.33747354, 0.19545908, 0.8495839, 0.44326293, 0.49718547, 0.4760649, 0.97547793, + 0.4174791, 0.29336637, 0.11830141, 0.46044156, 0.85300016, 0.8054495, 0.9476588, 0.016393282, + 0.7187454, 0.8301157, 0.49269608, 0.5402253, 0.78610885, 0.6184779, 0.39712286, 0.54652256, + 0.3826701, 0.98793495, 0.80439633, 0.015675247, 0.4140854, 0.85561216, 0.5788107, 0.7987029, + 0.17980942, 0.16486481, 0.26032335, 0.597808, 0.2162534, 0.86972165, 0.102014296, 0.47148252, + 0.7922716, 0.97669774, 0.3074505, 0.53072304, 0.16284934, 0.7616834, 0.40711153, 0.7097171, + 0.7637394, 0.950779, 0.58898723, 0.5141825, 0.8067036, 0.88841134, 0.41936216, 0.12534304, + 0.94035065, 0.6489365, 0.46691382, 0.45532802, 0.69278914, 0.46038964, 0.56139255, 0.56186694, + 0.7145557, 0.31959853, 0.28063214, 0.6881353, 0.54512614, 0.3498508, 0.8001399, 0.8490237, + 0.7281014, 0.021213572, 0.7479538, 0.8094111, 0.31102738, 0.8663998, 0.38367322, 0.6209867, + 0.5808234, 0.09467922, 0.25193584, 0.46330634, 0.26662496, 0.06462818, 0.99199927, 0.29139808, + 0.74550265, 0.13498032, 0.65745735, 0.5673169, 0.40280786, 0.64668626, 0.7786934, 0.33188194, + 0.4153052, 0.7455836, 0.8161674, 0.8432508, 0.48105124, 0.7189762, 0.16459095, 0.41388863, + 0.15063916, 0.73996353, 0.78608114, 0.78549004, 0.14045759, 0.609951, 0.8143157, 0.07395084, + 0.26526332, 0.8459271, 0.8745046, 0.5981099, 0.20845382, 0.098086186, 0.29524195, 0.6499275, + 0.32759923, 0.98923403, 0.9426327, 0.41014582, 0.6923934, 0.23282301, 0.44621587, 0.08141512, + 0.24252021, 0.4160718, 0.3941059, 0.5654438, 0.050232418, 0.5404224, 0.13993548, 0.8618472, + 0.9300883, 0.8380472, 0.31266716, 0.52666146, 0.27854705, 0.20650926, 0.1509405, 0.13555165, + 0.32066464, 0.5835065, 0.30205357, 0.5568808, 0.7721817, 0.18058343, 0.123428136, 0.31721902, + 0.45034164, 0.16623993, 0.5156516, 0.4918172, 0.7763435, 0.75444514, 0.7214952, 0.91781616, + 0.29374766, 0.704666, 0.5429698, 0.7243858, 0.21584511, 0.24887188, 0.02371842, 0.7248409, + 0.7059916, 0.012657363, 0.6680217, 0.37040663, 0.785419, 0.7685805, 0.37138042, 0.12108998, + 0.83829355, 0.80708104, 0.08948117, 0.108886935, 0.93076944, 0.8893351, 0.30923343, 0.061936773, + 0.29264367, 0.07688689, 0.11510216, 0.8839925, 0.02477082, 0.64811826, 0.08550372, 0.17564313, + 0.11655201, 0.39485103, 0.23291379, 0.57388103, 0.6635394, 0.42655468, 0.9197065, 0.071792774, + 0.5597881, 0.57721263, 0.8508891, 0.75952435, 0.5125618, 0.75302154, 0.53180003, 0.6817611, + 0.79485947, 0.3945616, 0.6535236, 0.9692625, 0.66496396, 0.61260825, 0.98704666, 0.40441254, + 0.3954326, 0.48103306, 0.43174213, 0.13895822, 0.13376972, 0.13972592, 0.7000701, 0.05787335, + 0.92715365, 0.49237853, 0.2538546, 0.390568, 0.5356667, 0.7974994, 0.45755056, 0.41173887, + 0.8873745, 0.017688395, 0.54909885, 0.3535568, 0.038445998, 0.54970914, 0.549375, 0.5396221, + 0.54508686, 0.43334106, 0.089132994, 0.6302092, 0.99459463, 0.11624123, 0.5106792, 0.50394374, + 0.40780434, 0.8285013, 0.17844845, 0.18250638, 0.99481255, 0.7807483, 0.93802303, 0.42006215, + 0.87714255, 0.7930158, 0.8323707, 0.020183232, 0.4991669, 0.14123203, 0.1460944, 0.9973601, + 0.93701106, 0.24178477, 0.081888, 0.64727557, 0.06350941, 0.6334899, 0.36596653, 0.84572345, + 0.931658, 0.89212, 0.59387136, 0.70042866, 0.050592937, 0.06986087, 0.063278705, 0.81091243, + 0.98169935, 0.74991083, 0.98276365, 0.7071655, 0.6190509, 0.27504414, 0.41692632, 0.106626175, + 0.07966534, 0.12903668, 0.47641423, 0.24543023, 0.71733844, 0.5291918, 0.040455237, 0.40385485, + 0.28724664, 0.091772884, 0.69319814, 0.7528099, 0.034353238, 0.8634036, 0.44043434, 0.77431446, + 0.46253473, 0.332725, 0.25084835, 0.10269255, 0.18687698, 0.23759438, 0.36946923, 0.8072817, + 0.72973704, 0.021458272, 0.038483858, 0.7492561, 0.1584684, 0.43892893, 0.37830916, 0.6619669, + 0.8248584, 0.9752618, 0.5676102, 0.93447274, 0.15707563, 0.120536305, 0.12838502, 0.40246627, + 0.8516648, 0.19001648, 0.41318202, 0.95882004, 0.3766627, 0.31046882, 0.7765592, 0.11829578, + 0.3094765, 0.20844917, 0.24463072, 0.28632593, 0.024195805, 0.31423378, 0.9197492, 0.84207094, + 0.75956744, 0.66913253, 0.5156932, 0.6958802, 0.4907079, 0.29119918, 0.24538647, 0.8483177, + 0.7134637, 0.031231258, 0.92795146, 0.059091415, 0.29579335, 0.5059616, 0.6172388, 0.34199843, + 0.20433997, 0.84838206, 0.2510278, 0.9968605, 0.82441235, 0.41064918, 0.43061897, 0.41926822, + 0.2448991, 0.92018807, 0.43977955, 0.95001924, 0.19429821, 0.09198324, 0.63777107, 0.51062465, + 0.055512622, 0.72553927, 0.17490527, 0.48794308, 0.60484314, 0.43250486, 0.91175836, 0.5604656, + 0.94463, 0.56486434, 0.24535634, 0.34543145, 0.38251737, 0.7174677, 0.82250243, 0.8035149, + 0.59121037, 0.9026323, 0.081985965, 0.17581372, 0.06320599, 0.9228887, 0.017658591, 0.3489183, + 0.23851357, 0.096424945, 0.45098105, 0.57051986, 0.8514196, 0.29536724, 0.6540195, 0.62148046, + 0.39346015, 0.41732678, 0.0035787956, 0.5702541, 0.33105636, 0.12929575, 0.7371553, 0.7718351, + 0.93662375, 0.6905622, 0.052230474, 0.25954804, 0.16529284, 0.08518753, 0.03675085, 0.52743137, + 0.097685665, 0.6362647, 0.35880888, 0.2916659, 0.009997273, 0.46195737, 0.4474187, 0.13262391, + 0.7078807, 0.825987, 0.24942951, 0.5084182, 0.9815238, 0.3412385, 0.70904595, 0.6492628, + 0.9108448, 0.62387586, 0.9519713, 0.9651906, 0.71388894, 0.25224832, 0.4724585, 0.4619146, + 0.16547702, 0.31015086, 0.23919, 0.37264377, 0.8706582, 0.7581105, 0.18362544, 0.15332605, + 0.05967409, 0.9235497, 0.47283417, 0.21515496, 0.93655837, 0.3623536, 0.6114832, 0.93150276, + 0.9699081, 0.8709549, 0.8623734, 0.5050694, 0.87986624, 0.2287371, 0.7903113, 0.5953852, + 0.98151624, 0.40296772, 0.34870324, 0.541417, 0.13321623, 0.07156025, 0.81354237, 0.84543735, + 0.16380614, 0.8968943, 0.12618889, 0.6998464, 0.22276738, 0.07477489, 0.2619657, 0.94977015, + 0.6423615, 0.09610346, 0.4487441, 0.05797409, 0.8684043, 0.49389097, 0.7127044, 0.54849124, + 0.012392659, 0.020468513, 0.99528253, 0.8429341, 0.3898749, 0.96738917, 0.58204836, 0.9367399, + 0.5198395, 0.6438048, 0.39112753, 0.46769053, 0.40940732, 0.64220846, 0.02010981, 0.9881138, + 0.11000732, 0.6273968, 0.051348828, 0.039664086, 0.2361647, 0.91163677, 0.7087354, 0.8951332, + 0.6089892, 0.91260326, 0.86270785, 0.7837628, 0.779993, 0.73233724, 0.72698087, 0.48762527, + 0.69026333, 0.800212, 0.5290243, 0.11274772, 0.07627774, 0.9706083, 0.45556244, 0.19641699, + 0.31484595, 0.18944897, 0.18000686, 0.5789626, 0.6836474, 0.79427516, 0.54036283, 0.00015307916, + 0.07599365, 0.46063024, 0.94796675, 0.24100749, 0.44254217, 0.67304033, 0.31232652, 0.10075587, + 0.31173313, 0.100149296, 0.23394488, 0.47727165, 0.10468131, 0.79828554, 0.1567469, 0.78750235, + 0.9168239, 0.9035022, 0.7774272, 0.6091953, 0.11318414, 0.9073621, 0.9118361, 0.139399, + 0.17183441, 0.85493183, 0.7248181, 0.04671574, 0.7316299, 0.1297728, 0.21148583, 0.814714, + 0.37224042, 0.8625547, 0.70776916, 0.31936276, 0.7843705, 0.4859734, 0.04508312, 0.017223012, + 0.4878855, 0.42826846, 0.8010146, 0.97612846, 0.73666346, 0.9782908, 0.09173568, 0.51656044, + 0.032702066, 0.3925045, 0.6621387, 0.7801451, 0.01684795, 0.93116754, 0.886969, 0.16863157, + 0.54879415, 0.80856776, 0.06917309, 0.5876103, 0.94822216, 0.26561078, 0.36912593, 0.18196031, + 0.8886635, 0.41923082, 0.1050312, 0.24212655, 0.09051639, 0.8373841, 0.0031318855, 0.4308505, + 0.8584191, 0.7602042, 0.121309794, 0.68491566, 0.10634747, 0.9357077, 0.4027356, 0.19354361, + 0.7631962, 0.2082577, 0.014013676, 0.3391254, 0.46763408, 0.43134072, 0.7978661, 0.44107288, + 0.9755858, 0.5391376, 0.7705686, 0.9758027, 0.4168003, 0.4574728, 0.06900084, 0.22227472, + 0.059142508, 0.6190543, 0.08746498, 0.3174326, 0.8732596, 0.84960914, 0.42604402, 0.19531794, + 0.38937265, 0.2312882, 0.921726, 0.25664374, 0.8098577, 0.20205325, 0.06228409, 0.61308646, + 0.40583217, 0.8756295, 0.8244142, 0.7399645, 0.2515971, 0.030000538, 0.7143262, 0.45732272, + 0.6213647, 0.6639583, 0.26654074, 0.5513788, 0.0668155, 0.02732918, 0.014050223, 0.40094635, + 0.69120336, 0.8990351, 0.6257732, 0.48729318, 0.8482427, 0.08530297, 0.320284, 0.91358703, + 0.7822137, 0.8186957, 0.94975275, 0.2363459, 0.50961477, 0.54122233, 0.63121516, 0.77353257, + 0.4768535, 0.15748215, 0.56997055, 0.54117084, 0.6330586, 0.32903638, 0.9706776, 0.02914197, + 0.90472806, 0.6301423, 0.69606787, 0.20930128, 0.5830684, 0.8746652, 0.12850243, 0.36204344, + 0.21723796, 0.5207796, 0.5654404, 0.9108227, 0.57628006, 0.5749909, 0.7648438, 0.3205292, + 0.5553455, 0.91082716, 0.9577508, 0.43290135, 0.08024777, 0.47798032, 0.94770795, 0.0801424, + 0.03274318, 0.49300817, 0.07452531, 0.90933335, 0.45735866, 0.4728794, 0.7678877, 0.362167, + 0.9283575, 0.5966312, 0.5825651, 0.21810043, 0.3892351, 0.11098274, 0.33051863, 0.9075484, + 0.6901933, 0.5877093, 0.019107932, 0.9888351, 0.9757819, 0.72039247, 0.19725248, 0.90186256, + 0.39263836, 0.24944134, 0.98582536, 0.72223145, 0.3712856, 0.5377763, 0.9488942, 0.42674774, + 0.68243426, 0.6159255, 0.1765581, 0.09006023, 0.8001399, 0.21916907, 0.9046848, 0.74435854, + 0.7528919, 0.20327342, 0.9824652, 0.9796489, 0.9924258, 0.5467434, 0.9312941, 0.44436273, + 0.58030856, 0.05020233, 0.742708, 0.49253845, 0.4588724, 0.95887285, 0.10436046, 0.31235072, + 0.29575568, 0.17266272, 0.516695, 0.20791732, 0.48705408, 0.045656245, 0.9908814, 0.3905812, + 0.647737, 0.15581739, 0.5356661, 0.77330965, 0.93442464, 0.2404584, 0.10740854, 0.47102425, + 0.6830245, 0.27474937, 0.2359432, 0.7725085, 0.73792726, 0.21760361, 0.9094368, 0.845895, + 0.31814724, 0.5414626, 0.14192294, 0.32108325, 0.7950682, 0.45635575, 0.96787536, 0.72356147, + 0.511565, 0.8642074, 0.79430455, 0.62747717, 0.70247406, 0.6967675, 0.2573045, 0.7072357, + 0.212392, 0.591884, 0.33191186, 0.8366084, 0.01107724, 0.15798447, 0.5099381, 0.33985013, + 0.9427938, 0.27168378, 0.8095139, 0.18412302, 0.72292966, 0.33185193, 0.5744235, 0.078152075, + 0.2632259, 0.67080003, 0.8897701, 0.94559145, 0.9037333, 0.66979814, 0.595513, 0.19138126, + 0.18794204, 0.8121047, 0.26174462, 0.07021725, 0.44615385, 0.47993135, 0.76855016, 0.986257, + 0.017444894, 0.5287075, 0.5601165, 0.1460432, 0.88569176, 0.07282839, 0.8348177, 0.16016278, + 0.031524524, 0.80207276, 0.37828946, 0.52338445, 0.6468418, 0.7837523, 0.00063179433, 0.17971309, + 0.2897839, 0.7161524, 0.3642513, 0.031674027, 0.8069974, 0.31171304, 0.8035024, 0.54259384, + 0.9963711, 0.14053062, 0.6486664, 0.19897254, 0.8962398, 0.43972084, 0.8936963, 0.46286246, + 0.5031336, 0.8232569, 0.16667813, 0.19422211, 0.7717354, 0.42838028, 0.19246033, 0.19039753, + 0.8359823, 0.7296073, 0.9140669, 0.10166052, 0.29150867, 0.07212853, 0.54453945, 0.40418974, + 0.8114729, 0.08203155, 0.78043336, 0.7300014, 0.11568007, 0.73687613, 0.1792596, 0.70573187, + 0.7252052, 0.017522655, 0.14967212, 0.7451611, 0.42416203, 0.6358452, 0.26392296, 0.59180367, + 0.9083765, 0.915427, 0.020250821, 0.8235849, 0.6170742, 0.80640966, 0.40797767, 0.86140364, + 0.52369213, 0.17385374, 0.19569172, 0.07739012, 0.3976461, 0.70184183, 0.2510852, 0.92424256, + 0.59599113, 0.24447663, 0.38749963, 0.81420827, 0.6592875, 0.16369487, 0.34718236, 0.76625746, + 0.6439973, 0.46094626, 0.46901694, 0.75421274, 0.27870816, 0.44729918, 0.76623553, 0.20013711, + 0.46568435, 0.32226324, 0.193284, 0.37608168, 0.051877704, 0.72095454, 0.7871155, 0.0050632227, + 0.6740539, 0.9190297, 0.20630927, 0.94182634, 0.5411844, 0.10186948, 0.30808574, 0.023363324, + 0.7664375, 0.22542956, 0.14916998, 0.17968538, 0.24834555, 0.44971466, 0.93251616, 0.74468166, + 0.56824464, 0.25399336, 0.17958756, 0.15612793, 0.33739275, 0.6537649, 0.5826955, 0.07639295, + 0.40761822, 0.9955546, 0.6117058, 0.07538286, 0.50855786, 0.8750035, 0.8723649, 0.8750366, + 0.4573611, 0.38243642, 0.1401544, 0.7402578, 0.9573856, 0.40535605, 0.22507304, 0.54212785, + 0.1528605, 0.44565362, 0.98777527, 0.05327858, 0.2981292, 0.5865501, 0.9517916, 0.015969688, + 0.38974705, 0.44860238, 0.807837, 0.79788435, 0.541367, 0.6309876, 0.6676705, 0.02028897, + 0.33633423, 0.12991633, 0.5342081, 0.5456298, 0.4901637, 0.2327029, 0.5148055, 0.89143395, + 0.35306472, 0.27413338, 0.7223243, 0.86590916, 0.30956024, 0.1922584, 0.787296, 0.1628886, + 0.02892033, 0.6374597, 0.0032674163, 0.89173913, 0.66598964, 0.5294169, 0.77826375, 0.8210681, + 0.043763056, 0.5957361, 0.6856358, 0.05995547, 0.06716649, 0.07448051, 0.3336696, 0.8263735, + 0.7147659, 0.11986544, 0.40392354, 0.8274693, 0.87114793, 0.67944324, 0.051964145, 0.9201576, + 0.9308481, 0.096341334, 0.70021385, 0.02399584, 0.8642258, 0.08588241, 0.70640945, 0.19748867, + 0.6613063, 0.6449484, 0.768964, 0.9039073, 0.6277202, 0.77593136, 0.35429934, 0.8069173, + 0.3516526, 0.71314, 0.50186676, 0.8944276, 0.5470671, 0.45485002, 0.82426745, 0.2785842, + 0.9404638, 0.8959508, 0.15114321, 0.18969482, 0.78833485, 0.9598267, 0.29174066, 0.3494771, + 0.5854956, 0.0831098, 0.960891, 0.56964827, 0.829203, 0.7542679, 0.9568423, 0.9578806, + 0.88932663, 0.48814714, 0.39864913, 0.42221805, 0.3055165, 0.42976233, 0.19865331, 0.93883455, + 0.7655661, 0.5970062, 0.4758167, 0.15800795, 0.17757647, 0.15753652, 0.3730905, 0.47599813, + 0.27207386, 0.42162967, 0.08353208, 0.96827507, 0.9347392, 0.51671463, 0.40915382, 0.7014796, + 0.35320777, 0.4194869, 0.3184117, 0.5446104, 0.81504035, 0.78465104, 0.9777143, 0.5973847, + 0.7562977, 0.54398614, 0.0051009622, 0.05891997, 0.05620089, 0.4020494, 0.9730677, 0.5107014, + 0.69729745, 0.21230865, 0.4241287, 0.19132863, 0.48401004, 0.1337327, 0.17190064, 0.42795905, + 0.7100193, 0.48489287, 0.29757443, 0.40757337, 0.67073584, 0.98856723, 0.023141444, 0.37261203, + 0.07899332, 0.6971695, 0.06901029, 0.8860296, 0.11135061, 0.65404296, 0.12379419, 0.98091507, + 0.6192919, 0.878432, 0.40171024, 0.63359034, 0.15243557, 0.31417054, 0.41979724, 0.87002444, + 0.44856197, 0.5728306, 0.2709776, 0.7224305, 0.09258589, 0.21782517, 0.21746957, 0.21947508, + 0.24758625, 0.8904527, 0.8345911, 0.3301475, 0.48707664, 0.57014096, 0.92664886, 0.7677305, + 0.5208447, 0.6324889, 0.97992665, 0.35903138, 0.3330391, 0.0870381, 0.39935082, 0.043254532, + 0.08851445, 0.44321367, 0.57203674, 0.60557806, 0.73202246, 0.5383103, 0.27552348, 0.39584875, + 0.06509563, 0.42754996, 0.95901144, 0.09790518, 0.7175897, 0.3007109, 0.28002614, 0.86116815, + 0.47969994, 0.8495352, 0.63844335, 0.22089794, 0.8194518, 0.7936467, 0.4938384, 0.049150985, + 0.9517831, 0.6339798, 0.11274567, 0.51994663, 0.3342439, 0.060765848, 0.53698534, 0.36152387, + 0.17347981, 0.22772305, 0.6339161, 0.6493722, 0.64578843, 0.6118915, 0.48745263, 0.70927596, + 0.6149292, 0.43874234, 0.26505187, 0.05952667, 0.6111295, 0.8287437, 0.050140806, 0.22013378, + 0.35246277, 0.1187585, 0.87933147, 0.4835039, 0.44859475, 0.1784529, 0.2238027, 0.29486778, + 0.9493753, 0.52288574, 0.65379494, 0.09804267, 0.42556462, 0.75557685, 0.061604857, 0.0043297815, + 0.8905646, 0.59748757, 0.92442536, 0.4898666, 0.6667948, 0.6306539, 0.21537969, 0.8678084, + 0.3620826, 0.9291674, 0.6059688, 0.3807095, 0.5285948, 0.43431175, 0.43802148, 0.123039424, + 0.583839, 0.8926119, 0.16748385, 0.2154854, 0.18143441, 0.05348144, 0.9129291, 0.99502695, + 0.003920352, 0.33904833, 0.69999695, 0.12290272, 0.9580966, 0.38940993, 0.2837113, 0.85935235, + 0.37713748, 0.2607221, 0.16896206, 0.013641968, 0.90431833, 0.5602742, 0.553339, 0.72180885, + 0.9033788, 0.011523027, 0.1214213, 0.51942736, 0.57248414, 0.8430932, 0.76627296, 0.5150635, + 0.084864266, 0.5307555, 0.51420367, 0.5329527, 0.588093, 0.84611946, 0.82289535, 0.83708316, + 0.68455845, 0.9293985, 0.48594627, 0.32774645, 0.930657, 0.092476964, 0.9097118, 0.97267264, + 0.6454561, 0.74661636, 0.003572011, 0.2678727, 0.2653497, 0.4243795, 0.2187211, 0.023564778, + 0.3392729, 0.44567502, 0.31210658, 0.16991138, 0.9320601, 0.39350176, 0.42254278, 0.16082714, + 0.57277536, 0.18493341, 0.03803846, 0.4273411, 0.87520623, 0.7507586, 0.27125937, 0.531018, + 0.43782672, 0.33187887, 0.32908353, 0.97491986, 0.07432794, 0.22559255, 0.7911518, 0.8109018, + 0.10181122, 0.14874865, 0.8739713, 0.8258678, 0.83952117, 0.49840027, 0.24971384, 0.6604848, + 0.3120344, 0.4906389, 0.19367984, 0.14241797, 0.5340129, 0.65298396, 0.90502304, 0.2910567, + 0.50685567, 0.3251191, 0.7549711, 0.7457236, 0.054438505, 0.4823707, 0.09746641, 0.8946975, + 0.47535703, 0.472554, 0.83004594, 0.9334708, 0.09529597, 0.24380124, 0.9492368, 0.11368034, + 0.6545232, 0.5012047, 0.06810016, 0.7833115, 0.5195305, 0.59667504, 0.32130596, 0.07437508, + 0.9352196, 0.3775537, 0.11530671, 0.38456735, 0.5570788, 0.12884142, 0.9970051, 0.7848427, + 0.42685586, 0.03802683, 0.4680642, 0.7492088, 0.47062147, 0.045428254, 0.75646335, 0.6194405, + 0.05128224, 0.9792738, 0.35051075, 0.3669672, 0.66835433, 0.31624305, 0.56518877, 0.06823316, + 0.5414021, 0.0799995, 0.4878948, 0.032808155, 0.5848838, 0.12171154, 0.7715262, 0.9101807, + 0.0038131434, 0.680596, 0.810504, 0.67688483, 0.36706397, 0.7128991, 0.3376187, 0.3465156, + 0.47554886, 0.04520323, 0.5066149, 0.05726915, 0.77573705, 0.200028, 0.6430589, 0.6090949, + 0.7447414, 0.44865963, 0.73202926, 0.5402566, 0.24616429, 0.9543388, 0.40602076, 0.61897653, + 0.8123649, 0.047073558, 0.8431653, 0.47707924, 0.6409466, 0.964197, 0.1999589, 0.3051443, + 0.2665006, 0.5578835, 0.7453957, 0.7900255, 0.23492423, 0.07957853, 0.25237653, 0.33838317, + 0.6416551, 0.0039951354, 0.89141834, 0.62315106, 0.80962807, 0.50791967, 0.29249611, 0.34137407, + 0.4369406, 0.8787999, 0.28806677, 0.1362242, 0.3896823, 0.23126958, 0.66401637, 0.049474377, + 0.27457523, 0.19152752, 0.8645199, 0.31999043, 0.8697338, 0.8605395, 0.70556897, 0.5113519, + 0.84524435, 0.20147063, 0.79076856, 0.21785353, 0.4546323, 0.8530334, 0.3741707, 0.66516286, + 0.1962831, 0.3936461, 0.89860153, 0.24216916, 0.062920436, 0.7828697, 0.8093484, 0.30444527, + 0.75457746, 0.5017912, 0.040138636, 0.7621467, 0.6761302, 0.06373471, 0.915462, 0.035231, + 0.89386714, 0.6959213, 0.51545024, 0.04339671, 0.21505861, 0.9323861, 0.46864936, 0.7811156, + 0.29842615, 0.38006642, 0.7779068, 0.60815746, 0.7171511, 0.07464257, 0.88674176, 0.5839072, + 0.5046292, 0.6229039, 0.9399411, 0.9960362, 0.33266804, 0.42184722, 0.9865539, 0.49170554, + 0.38217908, 0.5600747, 0.565413, 0.36794263, 0.82040083, 0.94342226, 0.8352217, 0.78150964, + 0.2860086, 0.75553757, 0.32398638, 0.758711, 0.3375832, 0.33077398, 0.45010427, 0.26389697, + 0.92499673, 0.11748593, 0.943743, 0.682854, 0.004962936, 0.20119096, 0.58729416, 0.67993486, + 0.6150494, 0.45623145, 0.25751752, 0.053226303, 0.12379362, 0.91942585, 0.702563, 0.47201994, + 0.7093674, 0.023744669, 0.66121763, 0.65498394, 0.36697313, 0.10070673, 0.96071476, 0.3550039, + 0.54484475, 0.99639714, 0.32214886, 0.96161354, 0.7506562, 0.12803078, 0.24632397, 0.17385522, + 0.17279965, 0.6760441, 0.071039446, 0.2151821, 0.4781042, 0.30369994, 0.48674262, 0.18098812, + 0.97278047, 0.8854781, 0.7528932, 0.3641694, 0.68590474, 0.7819954, 0.657716, 0.36658275, + 0.05297459, 0.85196644, 0.049343612, 0.31383854, 0.6695563, 0.7951203, 0.89692384, 0.82429004, + 0.15677115, 0.5887391, 0.13800927, 0.0085657975, 0.8790421, 0.6256806, 0.9292787, 0.48701864, + 0.20990747, 0.083662316, 0.88042665, 0.4477495, 0.8483864, 0.48738086, 0.99391574, 0.40566745, + 0.537002, 0.4802295, 0.6822035, 0.48149505, 0.34781352, 0.5965454, 0.66909915, 0.76284933, + 0.33868113, 0.9555661, 0.90863895, 0.89868975, 0.07868716, 0.93248546, 0.50429887, 0.37767935, + 0.77912027, 0.24674945, 0.05841095, 0.8893651, 0.16569066, 0.4781768, 0.301946, 0.34709984, + 0.9561994, 0.26587456, 0.15426192, 0.6022424, 0.9015687, 0.20996648, 0.51819634, 0.5655937, + 0.8580507, 0.64367616, 0.7768365, 0.18932684, 0.11291685, 0.4154288, 0.4764765, 0.5602257, + 0.91964, 0.37515992, 0.6698847, 0.923476, 0.7170417, 0.030588947, 0.40833148, 0.27742204, + 0.57936347, 0.5027473, 0.6686292, 0.60163695, 0.42896992, 0.10455062, 0.2399768, 0.058825243, + 0.17828348, 0.3351036, 0.5252956, 0.08193896, 0.44228348, 0.06685673, 0.8612806, 0.12871465, + 0.43736976, 0.34304523, 0.040639006, 0.435011, 0.15564895, 0.314972, 0.2647625, 0.36369145, + 0.770273, 0.4981852, 0.96972513, 0.79053074, 0.80829215, 0.37847006, 0.63005817, 0.9256105, + 0.85754305, 0.8768399, 0.022878975, 0.3988214, 0.54133725, 0.9165594, 0.1366238, 0.7535001, + 0.40369937, 0.71801126, 0.011043364, 0.77781326, 0.89013314, 0.39453754, 0.11794228, 0.85278326, + 0.5138793, 0.54117, 0.4861062, 0.37399647, 0.98994994, 0.9733205, 0.12177309, 0.26439142, + 0.23798482, 0.30493778, 0.83136404, 0.9307847, 0.13482551, 0.44944605, 0.25053307, 0.7998134, + 0.70504546, 0.5996852, 0.22439589, 0.5654436, 0.043977752, 0.4624592, 0.5873774, 0.52081037, + 0.20642142, 0.2871389, 0.031311635, 0.43763772, 0.30392867, 0.48694924, 0.4735583, 0.37573543, + 0.3802429, 0.11694187, 0.27665144, 0.26712215, 0.89236385, 0.25606167, 0.93566054, 0.8842226, + 0.7550668, 0.7584876, 0.16083659, 0.23639946, 0.08519537, 0.20583908, 0.6186746, 0.9542533, + 0.46747816, 0.21122995, 0.07276781, 0.29044798, 0.17014165, 0.5524987, 0.8088055, 0.0514201, + 0.9537926, 0.9652958, 0.16757506, 0.70281106, 0.94200885, 0.6841354, 0.96046275, 0.7510356, + 0.8313795, 0.45562857, 0.5505418, 0.017883644, 0.17279461, 0.9834109, 0.90744954, 0.44898376, + 0.66402465, 0.34017327, 0.81037676, 0.28549019, 0.3016226, 0.35097796, 0.43561503, 0.00058234343, + 0.6684643, 0.07705832, 0.97015953, 0.092698716, 0.41418144, 0.18311031, 0.20559378, 0.82774425, + 0.30813637, 0.22523133, 0.31332958, 0.92706805, 0.08848662, 0.23284948, 0.9422138, 0.07093142, + 0.7980248, 0.409801, 0.40501997, 0.6295668, 0.6552973, 0.600791, 0.7814587, 0.48406723, + 0.3037804, 0.62378407, 0.62642336, 0.82996833, 0.7421219, 0.5233153, 0.74979746, 0.6028146, + 0.5296808, 0.16699271, 0.03434674, 0.86495054, 0.71397585, 0.86776406, 0.33685416, 0.6482692, + 0.2500348, 0.7227976, 0.70974725, 0.9475633, 0.6700813, 0.9803815, 0.36049715, 0.43117517, + 0.39795953, 0.7394454, 0.4874654, 0.8918216, 0.94595796, 0.8060482, 0.3452851, 0.06767335, + 0.29559964, 0.4860923, 0.7889183, 0.7903974, 0.556687, 0.3756254, 0.08562232, 0.7848211, + 0.47543386, 0.71051496, 0.3973873, 0.9214939, 0.19850273, 0.07726323, 0.3569556, 0.9302608, + 0.072946854, 0.7567508, 0.37953198, 0.9324997, 0.89104366, 0.8338954, 0.8139859, 0.32339892, + 0.2632869, 0.19524816, 0.43200883, 0.002676534, 0.035849903, 0.8579759, 0.65685666, 0.7236325, + 0.82170767, 0.9666734, 0.5693509, 0.22788355, 0.07884572, 0.54645675, 0.09158218, 0.8744094, + 0.63717526, 0.9249262, 0.47212943, 0.9595664, 0.58299416, 0.43900326, 0.23267244, 0.3206963, + 0.3824898, 0.55720466, 0.8188748, 0.18920717, 0.42651626, 0.41278538, 0.17662966, 0.46170422, + 0.6721064, 0.4655194, 0.5271105, 0.3614388, 0.94361657, 0.08294579, 0.74897116, 0.617458, + 0.053658314, 0.67375475, 0.09978627, 0.23182935, 0.50791234, 0.12907204, 0.85141504, 0.5264901, + 0.66516864, 0.50512254, 0.29532441, 0.9661175, 0.36176598, 0.8544195, 0.7404047, 0.82428366, + 0.96257573, 0.11131253, 0.62018675, 0.47864527, 0.039101128, 0.46764946, 0.29711628, 0.40892226, + 0.7900437, 0.10764668, 0.55577713, 0.6133263, 0.019346252, 0.73014337, 0.9307928, 0.5542295, + 0.17595504, 0.8546715, 0.90590805, 0.9092394, 0.33921698, 0.0008430821, 0.81278396, 0.25341776, + 0.7057896, 0.29238465, 0.52403855, 0.9213937, 0.11746097, 0.21051219, 0.09993823, 0.8176869, + 0.72511464, 0.70282686, 0.3988631, 0.83230406, 0.46275905, 0.2703259, 0.57835686, 0.58600885, + 0.3766385, 0.690864, 0.44178563, 0.40026566, 0.5732949, 0.23808873, 0.50714386, 0.9350253, + 0.57432973, 0.74109495, 0.79016244, 0.5070945, 0.9485114, 0.8311653, 0.48506665, 0.9617326, + 0.29852858, 0.366769, 0.77285564, 0.74671644, 0.94361097, 0.3757226, 0.29146126, 0.57953155, + 0.007708449, 0.7380902, 0.88821167, 0.31651938, 0.33128026, 0.09848877, 0.09147043, 0.90562916, + 0.27631462, 0.31989923, 0.53260094, 0.648353, 0.5590575, 0.4125183, 0.68012285, 0.4677009, + 0.7852408, 0.5890133, 0.34706393, 0.37636602, 0.42034975, 0.5928437, 0.86917543, 0.89394933, + 0.21776019, 0.43713045, 0.5337755, 0.09599007, 0.49747026, 0.83164036, 0.6423979, 0.00091591524, + 0.39940274, 0.8622541, 0.3925572, 0.83520466, 0.3498771, 0.19062445, 0.603745, 0.475841, + 0.6496245, 0.8845333, 0.2307799, 0.6286122, 0.29856437, 0.83671373, 0.40267518, 0.8860103, + 0.6866461, 0.30515477, 0.9614757, 0.3545977, 0.028658632, 0.9150952, 0.15918177, 0.41486475, + 0.8689148, 0.9942623, 0.0987592, 0.8941498, 0.5647133, 0.99548036, 0.40815887, 0.44467425, + 0.6775013, 0.531685, 0.24895021, 0.69680333, 0.019961093, 0.8449182, 0.1178238, 0.59461635, + 0.98526824, 0.871223, 0.7267415, 0.53581643, 0.3620638, 0.24056326, 0.59538496, 0.38104647, + 0.034455262, 0.6477652, 0.40934396, 0.19231549, 0.8701647, 0.28780022, 0.97225726, 0.48430753, + 0.7030723, 0.9776925, 0.9662899, 0.3556148, 0.09186526, 0.7095952, 0.9111277, 0.65414417, + 0.47637445, 0.78610563, 0.9511109, 0.7668794, 0.5877635, 0.7058718, 0.8660492, 0.8417279, + 0.18733096, 0.3668593, 0.36932942, 0.15743567, 0.18835372, 0.62336534, 0.05280094, 0.6283515, + 0.3988773, 0.7177127, 0.85969454, 0.9169481, 0.5861364, 0.21584338, 0.5745095, 0.3897011, + 0.55942774, 0.7646427, 0.993731, 0.042268623, 0.8786283, 0.762209, 0.5027511, 0.27567303, + 0.9600953, 0.072597355, 0.059442017, 0.57595813, 0.2894524, 0.82850564, 0.793283, 0.32858342, + 0.78171605, 0.56761605, 0.0049845274, 0.50330544, 0.9184708, 0.8148216, 0.29595378, 0.07970701, + 0.92489153, 0.33793837, 0.9567375, 0.37415254, 0.84990066, 0.9941796, 0.06800775, 0.26053104, + 0.21159613, 0.5614098, 0.20745164, 0.8231208, 0.7121408, 0.82378054, 0.9630996, 0.42512196, + 0.8641082, 0.09365638, 0.19734041, 0.11575636, 0.5639233, 0.4768428, 0.33889914, 0.5703717, + 0.9244297, 0.5311111, 0.13523202, 0.01852037, 0.21085885, 0.071204096, 0.4712303, 0.74460614, + 0.4686889, 0.914024, 0.117377095, 0.54068995, 0.80547154, 0.12859856, 0.4257724, 0.9659156, + 0.0045896024, 0.798911, 0.36436203, 0.7280426, 0.621054, 0.9701622, 0.6164426, 0.9579355, + 0.6045164, 0.5798626, 0.63919723, 0.82481444, 0.61748123, 0.18019743, 0.5157837, 0.44804874, + 0.99903923, 0.3863658, 0.44972283, 0.31878954, 0.85894763, 0.049487386, 0.04967219, 0.14039204, + 0.09017946, 0.4628455, 0.3544319, 0.7981168, 0.70640343, 0.42240968, 0.6196504, 0.73550963, + 0.667884, 0.23142478, 0.11116676, 0.7650123, 0.112480775, 0.6108565, 0.9493177, 0.9542675, + 0.9146685, 0.17729652, 0.41400397, 0.6309963, 0.43200687, 0.6464159, 0.12712492, 0.2884915, + 0.3982403, 0.66932833, 0.54165065, 0.4191057, 0.67887574, 0.10698286, 0.10696802, 0.9551022, + 0.7492388, 0.22396998, 0.63786316, 0.15820846, 0.6157303, 0.8183258, 0.25153205, 0.18210672, + 0.9602121, 0.9036876, 0.15693043, 0.38605642, 0.06903067, 0.7507714, 0.33556795, 0.38818276, + 0.43704808, 0.4954553, 0.40412104, 0.6816511, 0.63548344, 0.4186759, 0.70838517, 0.44376358, + 0.3357206, 0.06594042, 0.39987648, 0.037075095, 0.88075906, 0.20054473, 0.05663389, 0.5609011, + 0.124456756, 0.15606454, 0.015773552, 0.88851076, 0.9729933, 0.79110926, 0.33853722, 0.09634267, + 0.9257645, 0.23189723, 0.6707842, 0.52831924, 0.48948547, 0.7410685, 0.2194608, 0.6474689, + 0.3337604, 0.15346791, 0.98205763, 0.18342042, 0.70286185, 0.42531693, 0.3196188, 0.3305629, + 0.5155848, 0.19409959, 0.82248783, 0.5497899, 0.41844934, 0.21445695, 0.3013477, 0.7596674, + 0.8470537, 0.5960293, 0.26159966, 0.91296613, 0.7349978, 0.44705716, 0.41518942, 0.6459388, + 0.1569181, 0.30777836, 0.7558866, 0.4035862, 0.7478917, 0.18006596, 0.9542781, 0.5946521, + 0.8464796, 0.75240755, 0.7033147, 0.7272911, 0.2184871, 0.87321347, 0.8580393, 0.69913983, + 0.83644575, 0.68521065, 0.372926, 0.77889377, 0.96862143, 0.7887473, 0.67789334, 0.7113075, + 0.93054956, 0.9111168, 0.6812655, 0.89345616, 0.47946882, 0.30649468, 0.9124711, 0.88670325, + 0.7382785, 0.33611885, 0.026502334, 0.39508346, 0.6694303, 0.9160326, 0.5826711, 0.33551884, + 0.23982148, 0.22783574, 0.70331025, 0.6660418, 0.51114225, 0.57405657, 0.5411803, 0.9738403, + 0.73799, 0.5624598, 0.07652036, 0.04978715, 0.07413118, 0.6362957, 0.6773174, 0.36817077, + 0.629885, 0.044579085, 0.47303665, 0.836775, 0.49880046, 0.06082195, 0.115183294, 0.53998494, + 0.83993644, 0.81661147, 0.98901266, 0.88236827, 0.84671116, 0.46295583, 0.029709496, 0.9204132, + 0.10253954, 0.03740714, 0.5390723, 0.74078566, 0.08543706, 0.011851499, 0.20016527, 0.356493, + 0.36993647, 0.70742524, 0.15546617, 0.917009, 0.22997431, 0.86268395, 0.81257206, 0.1019828, + 0.65880144, 0.6583316, 0.7651984, 0.6248512, 0.44299594, 0.74589616, 0.8367184, 0.17899951, + 0.11265245, 0.16332534, 0.8261054, 0.6945308, 0.5850439, 0.65881205, 0.12712914, 0.27503416, + 0.53275037, 0.15610719, 0.9472476, 0.036724042, 0.0972234, 0.9365317, 0.2827337, 0.6180335, + 0.8444138, 0.116543666, 0.46683854, 0.7913752, 0.9053558, 0.19817433, 0.3100106, 0.9772525, + 0.0040394296, 0.8870298, 0.22356682, 0.18837956, 0.6977574, 0.40485826, 0.47741726, 0.35664338, + 0.20068875, 0.36007276, 0.62813324, 0.92211175, 0.1857461, 0.5056345, 0.7714491, 0.7111244, + 0.5802961, 0.880432, 0.3842586, 0.07386713, 0.9154364, 0.775848, 0.0047594067, 0.7222697, + 0.37559786, 0.14716488, 0.7804374, 0.32645226, 0.27905762, 0.04534316, 0.27364373, 0.9144781, + 0.8533147, 0.84885293, 0.6904914, 0.6980141, 0.43524522, 0.93874955, 0.57727677, 0.1278921, + 0.67868996, 0.5906042, 0.8360353, 0.73715067, 0.30839851, 0.360622, 0.43228745, 0.33877933, + 0.3450946, 0.7557141, 0.21107915, 0.024923787, 0.8139157, 0.23614348, 0.061816096, 0.22819144, + 0.88227046, 0.5012971, 0.8127817, 0.55059254, 0.6244208, 0.15096499, 0.07758577, 0.15534559, + 0.08642902, 0.7136551, 0.068797, 0.33689317, 0.8151431, 0.073435, 0.27587917, 0.6415465, + 0.30315524, 0.25636652, 0.3951772, 0.32483214, 0.9398127, 0.26760876, 0.41387123, 0.014975904, + 0.7148774, 0.4416581, 0.9813577, 0.5233435, 0.83426404, 0.24871995, 0.100562416, 0.6171712, + 0.78703684, 0.4622999, 0.8157436, 0.93394816, 0.1259679, 0.026684225, 0.50347126, 0.527725, + 0.5130184, 0.6806897, 0.6507216, 0.59474343, 0.29182497, 0.09539426, 0.52363616, 0.27165958, + 0.47983494, 0.56953263, 0.72176856, 0.5575492, 0.8409663, 0.73698395, 0.28837872, 0.6146617, + 0.08742587, 0.7978058, 0.8357151, 0.18276273, 0.16960731, 0.55424225, 0.32108158, 0.83770907, + 0.61309266, 0.45162576, 0.54985636, 0.35284323, 0.25769138, 0.34193105, 0.5155786, 0.27647102, + 0.75289524, 0.86745226, 0.8118137, 0.259123, 0.61688715, 0.8191278, 0.7231509, 0.6194832, + 0.9180219, 0.7096981, 0.043508567, 0.26473138, 0.5269514, 0.5430132, 0.77620494, 0.05005288, + 0.1739212, 0.20108196, 0.8465223, 0.32816213, 0.19096912, 0.32070854, 0.35811764, 0.9587762, + 0.3596081, 0.81301254, 0.9816507, 0.84019923, 0.54553795, 0.17079297, 0.013968218, 0.13790388, + 0.053954035, 0.44529754, 0.80465394, 0.9735141, 0.92517024, 0.029255724, 0.99777454, 0.26829806, + 0.07465485, 0.21623193, 0.2647408, 0.45990923, 0.5107337, 0.056350194, 0.31075767, 0.07007945, + 0.6754208, 0.49980345, 0.17892201, 0.056609415, 0.4954088, 0.18741646, 0.08550189, 0.4321867, + 0.5093346, 0.85303754, 0.89951485, 0.8038746, 0.8374771, 0.88295174, 0.073945254, 0.7472289, + 0.69572985, 0.90560466, 0.21077734, 0.08165387, 0.7383593, 0.80269086, 0.12488264, 0.14466548, + 0.20330743, 0.5782242, 0.2535073, 0.9747372, 0.055967752, 0.8982084, 0.44804245, 0.30325794, + 0.50225484, 0.91157126, 0.16477837, 0.045734458, 0.99187094, 0.9573588, 0.6424951, 0.8665376, + 0.35979563, 0.37246728, 0.46417946, 0.0721327, 0.12974085, 0.19389993, 0.430821, 0.19170313, + 0.14228667, 0.51751184, 0.76417935, 0.605129, 0.8455728, 0.2291038, 0.3317202, 0.87272996, + 0.37492082, 0.034256544, 0.853302, 0.9171846, 0.9339092, 0.11076469, 0.37621894, 0.6111262, + 0.40499508, 0.5962569, 0.30161974, 0.92590576, 0.7181733, 0.028210793, 0.755358, 0.7383711, + 0.2631096, 0.34423977, 0.7218582, 0.365892, 0.3385114, 0.05274994, 0.014924624, 0.0094075035, + 0.1474032, 0.061804168, 0.8324505, 0.5384559, 0.13402902, 0.84291345, 0.45768508, 0.27315107, + 0.5798511, 0.29204842, 0.6708136, 0.9576144, 0.10405682, 0.7253105, 0.9326284, 0.24903095, + 0.99624836, 0.8530533, 0.6671376, 0.5334839, 0.8922802, 0.50491524, 0.47352976, 0.114075884, + 0.76215386, 0.025808325, 0.34201944, 0.50133306, 0.5072456, 0.9658282, 0.53421855, 0.32217088, + 0.019331919, 0.8438945, 0.7697814, 0.872105, 0.27831417, 0.837763, 0.47709718, 0.56208163, + 0.13857186, 0.028468672, 0.34605467, 0.42612493, 0.35739717, 0.79774356, 0.63431424, 0.5377991, + 0.4116114, 0.4728273, 0.36964366, 0.48545814, 0.3856123, 0.48144072, 0.11712731, 0.64248794, + 0.5882744, 0.71837467, 0.77630204, 0.1082207, 0.500894, 0.956352, 0.7659055, 0.6140229, + 0.75782984, 0.34864277, 0.9382825, 0.26016235, 0.9555291, 0.06052337, 0.9707168, 0.15848531, + 0.3759561, 0.10505597, 0.39491206, 0.86381155, 0.15886053, 0.047404833, 0.7566787, 0.96441025, + 0.3914941, 0.8042203, 0.08972167, 0.0344183, 0.59618455, 0.0487604, 0.93655854, 0.5378912, + 0.7267672, 0.12729345, 0.2838306, 0.5599395, 0.06146098, 0.3688765, 0.061187647, 0.18221985, + 0.2625632, 0.7320318, 0.6682951, 0.008754399, 0.85946107, 0.3741519, 0.58227, 0.35108802, + 0.5021105, 0.21115834, 0.10950206, 0.28055635, 0.08652866, 0.25331578, 0.48362744, 0.5408696, + 0.9616959, 0.8118918, 0.7167266, 0.6966737, 0.8666303, 0.73148715, 0.017838325, 0.7090695, + 0.4120842, 0.40039128, 0.5333952, 0.8282356, 0.77669275, 0.41077727, 0.09702433, 0.007079605, + 0.043868326, 0.21269222, 0.6012483, 0.42682874, 0.37910977, 0.7479243, 0.10494917, 0.01734221, + 0.22195028, 0.73863363, 0.5323078, 0.38502622, 0.93925834, 0.6560022, 0.45136255, 0.47345138, + 0.643666, 0.74296105, 0.5982436, 0.24956919, 0.65214986, 0.36451396, 0.31558952, 0.531076, + 0.71419346, 0.9592256, 0.5966702, 0.45906982, 0.8407567, 0.7540344, 0.5743953, 0.09133322, + 0.114134, 0.10242245, 0.23668802, 0.87383646, 0.6520674, 0.056798704, 0.16175981, 0.2137716, + 0.7069426, 0.6993844, 0.4747234, 0.1279967, 0.19917937, 0.6328121, 0.76981115, 0.756082, + 0.94902873, 0.059943788, 0.1845696, 0.03373171, 0.8125337, 0.84745514, 0.35492972, 0.67935437, + 0.8971027, 0.07017233, 0.7126353, 0.41988418, 0.15125412, 0.6458793, 0.1765855, 0.46791586, + 0.16423836, 0.4409746, 0.27089223, 0.83683586, 0.4193142, 0.5775261, 0.82138395, 0.58686733, + 0.58120126, 0.384472, 0.54262656, 0.95276546, 0.8897906, 0.1875928, 0.33189663, 0.08138137, + 0.18941447, 0.8405882, 0.51004106, 0.7808129, 0.5694648, 0.54066354, 0.27879953, 0.26667887, + 0.74749273, 0.55733365, 0.97673374, 0.5818951, 0.34416345, 0.74187565, 0.06251747, 0.061063267, + 0.5227989, 0.0068075284, 0.96375835, 0.75820476, 0.36191988, 0.93297523, 0.3367678, 0.37150264, + 0.23855984, 0.5977023, 0.45253047, 0.42806166, 0.30482855, 0.40216422, 0.7895638, 0.7095099, + 0.7382757, 0.6312539, 0.23046969, 0.3106659, 0.13583827, 0.39577258, 0.89845103, 0.6235748, + 0.16217506, 0.004213362, 0.08934315, 0.86198056, 0.60079235, 0.23948883, 0.24270387, 0.8393256, + 0.32195452, 0.4815633, 0.4299666, 0.8829831, 0.22383447, 0.57369184, 0.7194615, 0.2564392, + 0.5038204, 0.13853844, 0.5422531, 0.97176254, 0.0881331, 0.85073787, 0.9618503, 0.3453285, + 0.76776993, 0.26722383, 0.8436194, 0.7129096, 0.51140594, 0.75185156, 0.925225, 0.1270263, + 0.10835649, 0.34018353, 0.5960297, 0.35770652, 0.8436321, 0.47478724, 0.7707103, 0.999071, + 0.35499844, 0.6132049, 0.106107146, 0.82326525, 0.97219765, 0.9065807, 0.48567542, 0.16458383, + 0.9117924, 0.9740305, 0.8068454, 0.99729985, 0.8535195, 0.9266885, 0.5354417, 0.3114372, + 0.04236306, 0.7440147, 0.09421062, 0.3335685, 0.3958694, 0.52979434, 0.32791966, 0.57010293, + 0.5563383, 0.30294028, 0.77462655, 0.88365096, 0.97766215, 0.36175498, 0.41280714, 0.029033197, + 0.36782816, 0.5431821, 0.61676407, 0.47492823, 0.7446307, 0.13858505, 0.37313086, 0.86118925, + 0.7815484, 0.6790356, 0.8011172, 0.53737545, 0.94500613, 0.92792517, 0.27350682, 0.18166798, + 0.8047418, 0.2845925, 0.31534344, 0.09961744, 0.38057664, 0.43714178, 0.6032016, 0.82520413, + 0.28528523, 0.5360042, 0.26692694, 0.66925734, 0.13195412, 0.6020245, 0.18692169, 0.5500374, + 0.5612233, 0.77781224, 0.62947166, 0.31033742, 0.30992442, 0.060513485, 0.5668065, 0.903778, + 0.3708838, 0.2330214, 0.55202013, 0.71683383, 0.72867715, 0.79054415, 0.6250968, 0.62841314, + 0.029433481, 0.59295857, 0.07890911, 0.69306964, 0.046411548, 0.3131897, 0.6484566, 0.9306864, + 0.93998045, 0.79156, 0.189643, 0.20862652, 0.8716581, 0.7038735, 0.7292351, 0.1795239, + 0.49211392, 0.25107977, 0.9761521, 0.16719387, 0.29845348, 0.9631694, 0.87174356, 0.74422836, + 0.7177861, 0.41156542, 0.72873366, 0.14755523, 0.88512164, 0.8863678, 0.096526965, 0.49474105, + 0.9109074, 0.6385138, 0.63982385, 0.53899556, 0.5231154, 0.49385205, 0.5036258, 0.24803366, + 0.12935568, 0.6987853, 0.37035698, 0.5183644, 0.8708705, 0.35817996, 0.032119915, 0.66701025, + 0.5037863, 0.37249622, 0.22471993, 0.47759736, 0.81439203, 0.45790294, 0.32995966, 0.06626411, + 0.721215, 0.33468077, 0.97528356, 0.6348461, 0.584456, 0.50090134, 0.04556473, 0.053612676, + 0.695033, 0.69490194, 0.29771915, 0.23314431, 0.064049676, 0.19023955, 0.6564085, 0.99826187, + 0.7474539, 0.7281185, 0.037838195, 0.5996682, 0.5928124, 0.35337916, 0.87335783, 0.3596061, + 0.37944552, 0.06172341, 0.6437689, 0.51262546, 0.66164786, 0.6189296, 0.680349, 0.45300442, + 0.3085541, 0.57355976, 0.81778055, 0.18843463, 0.51856846, 0.8687797, 0.6635776, 0.6284543, + 0.6532206, 0.3167443, 0.8233314, 0.17596854, 0.06046078, 0.7989756, 0.6029606, 0.31354675, + 0.7160877, 0.22645807, 0.7301434, 0.086273566, 0.42006475, 0.7302915, 0.4734517, 0.36783585, + 0.4613229, 0.6156775, 0.2554006, 0.5227326, 0.8571324, 0.53293926, 0.39196482, 0.07610343, + 0.014552955, 0.84471476, 0.9245902, 0.49048993, 0.37245902, 0.4679739, 0.47969338, 0.8786742, + 0.06454086, 0.40938383, 0.9464476, 0.2760681, 0.5300478, 0.6973893, 0.2991453, 0.5804699, + 0.45876285, 0.33022216, 0.79653776, 0.43518978, 0.8887862, 0.59407544, 0.032939672, 0.5782626, + 0.10010804, 0.44994467, 0.7271117, 0.902891, 0.6133791, 0.140845, 0.77132195, 0.12028129, + 0.9247795, 0.74722797, 0.16141559, 0.21574605, 0.8743854, 0.11247064, 0.9410877, 0.24811381, + 0.74676466, 0.8514692, 0.021732707, 0.010680916, 0.7838439, 0.19738361, 0.8377881, 0.7639336, + 0.31653216, 0.6749307, 0.06396978, 0.52691025, 0.7364015, 0.956775, 0.18731725, 0.42047754, + 0.8117751, 0.34632754, 0.39038187, 0.9225143, 0.7408622, 0.57680243, 0.2652951, 0.92369586, + 0.6380619, 0.82616633, 0.35128862, 0.7828198, 0.5359737, 0.08339928, 0.7060845, 0.3462922, + 0.38913444, 0.54842395, 0.6884251, 0.037316978, 0.5723427, 0.022258755, 0.79441875, 0.90272444, + 0.61215657, 0.9631781, 0.5863588, 0.9384484, 0.07687521, 0.24441172, 0.38387978, 0.96800447, + 0.5599107, 0.74093807, 0.403971, 0.5280579, 0.72208875, 0.018573398, 0.5072516, 0.16996226, + 0.58617413, 0.09803684, 0.37261903, 0.95767754, 0.84609497, 0.05496832, 0.22795987, 0.23313288, + 0.9688462, 0.7176776, 0.1377758, 0.18797757, 0.26834992, 0.15000027, 0.8481348, 0.7895163, + 0.5519088, 0.48765746, 0.31035778, 0.77768403, 0.9904436, 0.32684666, 0.84682065, 0.39365014, + 0.44228655, 0.38328415, 0.22290905, 0.79503566, 0.6794283, 0.17802662, 0.62420344, 0.37056103, + 0.041172326, 0.51846284, 0.45114288, 0.47430587, 0.6496397, 0.8367412, 0.05662944, 0.5571883, + 0.7352182, 0.35322595, 0.9696022, 0.35919765, 0.10663593, 0.19590221, 0.6996546, 0.40991047, + 0.89280325, 0.6144547, 0.9761491, 0.23443131, 0.70821565, 0.7295676, 0.17951865, 0.25932744, + 0.25121617, 0.97896886, 0.515391, 0.46281084, 0.83205926, 0.4329242, 0.55370456, 0.7908196, + 0.093474135, 0.7672148, 0.14680524, 0.74988705, 0.69885737, 0.37382892, 0.13987659, 0.7151676, + 0.431028, 0.75316954, 0.04246583, 0.63721764, 0.35724443, 0.48762304, 0.28701422, 0.24638435, + 0.6836296, 0.8129986, 0.9022324, 0.064973645, 0.20187753, 0.38977212, 0.6623454, 0.31160477, + 0.3389442, 0.19181544, 0.2230897, 0.6706708, 0.32135025, 0.5938186, 0.725129, 0.30229402, + 0.7995213, 0.17878264, 0.2657235, 0.33942115, 0.04909697, 0.94976753, 0.7110531, 0.5189743, + 0.47457805, 0.2609815, 0.8034033, 0.9550461, 0.6871017, 0.542301, 0.90208304, 0.76359314, + 0.6919547, 0.2690066, 0.77918124, 0.019060668, 0.5306918, 0.48873094, 0.58894205, 0.703702, + 0.104869366, 0.8352005, 0.41094282, 0.507042, 0.15073924, 0.46920577, 0.3938173, 0.8372094, + 0.028040525, 0.7401718, 0.8376963, 0.17846179, 0.22189952, 0.9475931, 0.19728738, 0.7338621, + 0.101945534, 0.3832581, 0.59039557, 0.94089603, 0.5863688, 0.7072993, 0.624503, 0.7966432, + 0.28973243, 0.45949653, 0.9787162, 0.052343633, 0.81463736, 0.70606834, 0.7716022, 0.31079042, + 0.5898406, 0.5620215, 0.23455179, 0.21389648, 0.5388247, 0.2040111, 0.36823508, 0.0053723096, + 0.8671642, 0.9661939, 0.9270056, 0.94692993, 0.7046047, 0.72362125, 0.5416936, 0.7443616, + 0.07171923, 0.04531915, 0.91711515, 0.1474337, 0.89833534, 0.648046, 0.11733318, 0.39757007, + 0.21069747, 0.6142996, 0.21730955, 0.6912427, 0.49048957, 0.34147367, 0.022572042, 0.3219722, + 0.9685696, 0.5269059, 0.5886212, 0.659878, 0.7130413, 0.98339087, 0.19503741, 0.89793444, + 0.015023004, 0.5850233, 0.07373183, 0.62017494, 0.7802937, 0.6775731, 0.09203854, 0.5661112, + 0.9178029, 0.2343546, 0.9806244, 0.7693182, 0.7889532, 0.6241685, 0.41245508, 0.9417946, + 0.44468832, 0.8369817, 0.0031990237, 0.9245251, 0.98670155, 0.6769924, 0.51488274, 0.5256905, + 0.9436219, 0.6050334, 0.97836035, 0.17769879, 0.13500004, 0.8818156, 0.0313203, 0.08832834, + 0.8502817, 0.019180698, 0.13241069, 0.31331208, 0.5743142, 0.49715826, 0.6172764, 0.5331244, + 0.5222611, 0.6511984, 0.7734398, 0.256135, 0.3608493, 0.25325385, 0.533019, 0.34440103, + 0.114450805, 0.6468266, 0.2151897, 0.8760596, 0.9801919, 0.27051234, 0.9112329, 0.3380306, + 0.07014053, 0.54804134, 0.6765531, 0.1752603, 0.69921273, 0.9143398, 0.43111116, 0.035987273, + 0.2030343, 0.8922961, 0.91903645, 0.76977247, 0.49175784, 0.099143006, 0.3674804, 0.94753003, + 0.21970531, 0.47007462, 0.40226397, 0.3355032, 0.9035526, 0.25874776, 0.16484123, 0.69036806, + 0.07201438, 0.63395935, 0.063247986, 0.48817343, 0.6666259, 0.15526073, 0.10813647, 0.5797694, + 0.10794782, 0.79438007, 0.24317154, 0.026272861, 0.8206052, 0.4420161, 0.8339117, 0.6079213, + 0.22008722, 0.73745257, 0.053100668, 0.46855322, 0.33421737, 0.76324654, 0.8526432, 0.015307797, + 0.27934623, 0.26765963, 0.65635425, 0.51011723, 0.86824834, 0.57572967, 0.43447804, 0.8113928, + 0.38320008, 0.986185, 0.10324592, 0.06525337, 0.85109174, 0.94293773, 0.36936134, 0.047773577, + 0.7841596, 0.33926708, 0.66182464, 0.69737774, 0.85597146, 0.34120753, 0.12692484, 0.7776892, + 0.63616294, 0.79434264, 0.11541597, 0.16610004, 0.2056471, 0.696288, 0.35615066, 0.30876786, + 0.78131616, 0.04794019, 0.2088272, 0.39896628, 0.49890646, 0.59801924, 0.711521, 0.5322181, + 0.35990205, 0.43177876, 0.6430728, 0.8344202, 0.33877015, 0.76865834, 0.75682956, 0.2771495, + 0.3680912, 0.005327093, 0.68439364, 0.9949503, 0.10142185, 0.15526544, 0.15933633, 0.9381387, + 0.14073479, 0.87866503, 0.8739543, 0.07390571, 0.46031374, 0.268378, 0.6057457, 0.68691206, + 0.6300343, 0.79447806, 0.28393722, 0.80315155, 0.73411053, 0.9703951, 0.5488671, 0.18614037, + 0.6277461, 0.12960654, 0.33747572, 0.4241927, 0.6981348, 0.29250467, 0.43891907, 0.8675046, + 0.037513115, 0.8382665, 0.79800886, 0.20032, 0.011894401, 0.3612004, 0.207346, 0.6260507, + 0.88860387, 0.27068847, 0.25823146, 0.62024146, 0.72406495, 0.6376153, 0.0719044, 0.09152406, + 0.82603306, 0.9561607, 0.20438583, 0.5442921, 0.4847211, 0.95367795, 0.54303896, 0.3976961, + 0.45646, 0.49825326, 0.3672042, 0.9718153, 0.81778973, 0.73514366, 0.24000394, 0.8482301, + 0.43974596, 0.006449677, 0.036392592, 0.62204725, 0.47036913, 0.4054257, 0.67501765, 0.26883397, + 0.58713204, 0.6578865, 0.91454774, 0.46342203, 0.7121636, 0.92862564, 0.46207544, 0.9901308, + 0.057702154, 0.24595165, 0.5981596, 0.74197406, 0.08811883, 0.894627, 0.38278353, 0.08383514, + 0.2952275, 0.40031275, 0.74386, 0.5136412, 0.9939962, 0.2355307, 0.808261, 0.15346022, + 0.030684536, 0.41000134, 0.1804955, 0.71761525, 0.6012227, 0.44985715, 0.6211549, 0.4206074, + 0.28114304, 0.9355519, 0.95716006, 0.82683456, 0.03913026, 0.07961693, 0.6855325, 0.52783436, + 0.036177807, 0.3770734, 0.91411316, 0.5718381, 0.13698402, 0.4980299, 0.76011133, 0.545119, + 0.62366617, 0.95255744, 0.32681978, 0.07005637, 0.66156566, 0.16137652, 0.27483776, 0.35160136, + 0.8496255, 0.7610875, 0.4327375, 0.30216226, 0.74813014, 0.74446017, 0.38890806, 0.607845, + 0.62479675, 0.17755221, 0.46083102, 0.15256695, 0.9374669, 0.5559489, 0.04470488, 0.21561056, + 0.7147803, 0.21602567, 0.47746333, 0.6169228, 0.32141757, 0.23642296, 0.016476203, 0.53265464, + 0.64989, 0.6353765, 0.0939491, 0.64866525, 0.12303737, 0.5510985, 0.7590417, 0.11976651, + 0.6607141, 0.6055587, 0.9772091, 0.27804276, 0.64687943, 0.38337022, 0.7797042, 0.29171762, + 0.9881654, 0.30626813, 0.94704133, 0.9594318, 0.037198868, 0.60754436, 0.60765207, 0.06771721, + 0.9078526, 0.1112092, 0.3552761, 0.44554, 0.6839132, 0.657915, 0.030183792, 0.6132026, + 0.74461126, 0.9000829, 0.6522722, 0.112753615, 0.6505111, 0.74024284, 0.48480767, 0.073698185, + 0.4185105, 0.3410645, 0.49185285, 0.33190826, 0.5787399, 0.7666621, 0.5687311, 0.33141005, + 0.43632144, 0.18574573, 0.6287574, 0.01514944, 0.28938162, 0.057044394, 0.49545577, 0.042345677, + 0.027724478, 0.026231889, 0.74081266, 0.011828165, 0.19582245, 0.31350172, 0.43585333, 0.0027991086, + 0.5753749, 0.36400652, 0.5334315, 0.74679655, 0.731098, 0.6669506, 0.6412065, 0.24792254, + 0.8214605, 0.8733431, 0.54092133, 0.6961343, 0.115691505, 0.27574378, 0.48897734, 0.14119047, + 0.5424781, 0.02386607, 0.009218562, 0.49816743, 0.029157575, 0.015034353, 0.32382092, 0.6875669, + 0.40462708, 0.6099266, 0.08502913, 0.6242792, 0.9994301, 0.4729795, 0.87787575, 0.10500878, + 0.90521115, 0.48905376, 0.7565334, 0.21473333, 0.23323065, 0.8219346, 0.60031205, 0.76937085, + 0.5445392, 0.38083488, 0.19368897, 0.41603848, 0.51612306, 0.7993214, 0.92665416, 0.75198066, + 0.5372545, 0.5996222, 0.4693501, 0.17195638, 0.30428314, 0.9376859, 0.9736415, 0.5603405, + 0.040185597, 0.8458646, 0.34216946, 0.12117143, 0.58192146, 0.016927328, 0.24849239, 0.34848097, + 0.99546736, 0.43591255, 0.7909232, 0.62663776, 0.51921046, 0.274244, 0.9079598, 0.72054344, + 0.42355403, 0.2398477, 0.95362824, 0.6483227, 0.8213454, 0.90778244, 0.17144382, 0.6053057, + 0.68327236, 0.33304846, 0.08702466, 0.39980793, 0.0036293846, 0.7059194, 0.80072564, 0.96752524, + 0.5154122, 0.19619283, 0.17454775, 0.38736606, 0.47976512, 0.4791406, 0.1874494, 0.52761185, + 0.13234249, 0.845208, 0.4205711, 0.08021053, 0.00839825, 0.3000164, 0.23277025, 0.26301053, + 0.6916624, 0.74880666, 0.74840236, 0.064435445, 0.98405766, 0.32531884, 0.73899513, 0.13240317, + 0.6744208, 0.7368638, 0.43789902, 0.24887301, 0.9299027, 0.8486845, 0.34485158, 0.289548, + 0.6351869, 0.82339793, 0.11122555, 0.3230176, 0.09969627, 0.52059376, 0.24077836, 0.9444134, + 0.05239831, 0.42601636, 0.5159802, 0.9761374, 0.48721132, 0.09123329, 0.59690744, 0.383256, + 0.1002782, 0.8240141, 0.70814556, 0.25482276, 0.957517, 0.7362902, 0.9834676, 0.19009337, + 0.45719767, 0.042144574, 0.71294534, 0.7429013, 0.041241586, 0.9385764, 0.59770924, 0.28365803, + 0.50035644, 0.13102308, 0.44502363, 0.18500035, 0.18879086, 0.90975267, 0.16331425, 0.17106864, + 0.50802827, 0.80398893, 0.012037134, 0.55804133, 0.8093386, 0.7628578, 0.64519185, 0.58318746, + 0.1399564, 0.05464305, 0.14859481, 0.10588853, 0.14053893, 0.09002884, 0.332031, 0.89889675, + 0.8399303, 0.9211322, 0.86581993, 0.057551697, 0.8076484, 0.49787706, 0.90317184, 0.113821924, + 0.82830715, 0.23232217, 0.47578096, 0.35618824, 0.64620966, 0.41190708, 0.19446513, 0.19052555, + 0.6606999, 0.5370769, 0.74679446, 0.15352806, 0.72425306, 0.42542627, 0.3807547, 0.6943399, + 0.39695272, 0.12975785, 0.6029449, 0.98659855, 0.78998154, 0.4918207, 0.1431191, 0.41032755, + 0.7989921, 0.5461269, 0.34507003, 0.26765865, 0.043932725, 0.105762556, 0.36342022, 0.010151213, + 0.90081716, 0.89821523, 0.7297342, 0.5770165, 0.2870768, 0.28900358, 0.9369778, 0.72804934, + 0.86017793, 0.95806926, 0.44518864, 0.60346204, 0.34323436, 0.17850293, 0.17464367, 0.41450405, + 0.5403775, 0.17148003, 0.660599, 0.6778906, 0.89493215, 0.9165733, 0.32384035, 0.33648646, + 0.08920308, 0.06545341, 0.5571962, 0.10008278, 0.06683705, 0.92680645, 0.14659283, 0.5549373, + 0.17365667, 0.73664325, 0.25271094, 0.8260378, 0.69569206, 0.80373824, 0.4072631, 0.10794914, + 0.19278006, 0.8748956, 0.12642062, 0.8319123, 0.04663203, 0.53965706, 0.06709321, 0.6204891, + 0.37148324, 0.93056595, 0.7272812, 0.8724527, 0.44516358, 0.68552965, 0.11521906, 0.98424387, + 0.57437485, 0.39324772, 0.48781338, 0.22162339, 0.7318074, 0.836895, 0.66121227, 0.9333714, + 0.81147647, 0.89025134, 0.42980537, 0.6065911, 0.925792, 0.3486058, 0.718812, 0.7366392, + 0.7642169, 0.55264986, 0.4851105, 0.02003657, 0.79015267, 0.49192804, 0.28985444, 0.54954606, + 0.9983602, 0.936707, 0.72859955, 0.13627109, 0.1995253, 0.27414012, 0.10977373, 0.48812705, + 0.6214242, 0.26846707, 0.251663, 0.30244434, 0.31592485, 0.18563971, 0.3761417, 0.35588506, + 0.2136833, 0.19304918, 0.020435851, 0.1563807, 0.10985168, 0.46050212, 0.69469714, 0.022877397, + 0.211754, 0.99064195, 0.10823577, 0.89251375, 0.20041913, 0.09518249, 0.19409119, 0.082446806, + 0.1033933, 0.93826735, 0.22326319, 0.7951004, 0.108295456, 0.5249412, 0.7338461, 0.53733635, + 0.7804776, 0.94167835, 0.9851669, 0.6573249, 0.09694284, 0.41636762, 0.42071435, 0.5785772, + 0.17650813, 0.12922545, 0.8063533, 0.5971035, 0.4714922, 0.13347372, 0.43969434, 0.53785807, + 0.2420099, 0.70572215, 0.9245171, 0.20888333, 0.16590436, 0.21725997, 0.2877079, 0.5262417, + 0.07437589, 0.16921617, 0.19905105, 0.3776575, 0.96237653, 0.58104134, 0.2475896, 0.6887421, + 0.459203, 0.48309952, 0.3759031, 0.16817336, 0.47533524, 0.037372224, 0.92593455, 0.7953864, + 0.5699276, 0.52965856, 0.7160056, 0.07119369, 0.28882924, 0.5969877, 0.6109546, 0.96991956, + 0.498573, 0.68540514, 0.5530905, 0.40257332, 0.6004241, 0.52496284, 0.37143198, 0.56321764, + 0.6539704, 0.45892516, 0.58294904, 0.9277267, 0.21731657, 0.043056846, 0.6162007, 0.5954668, + 0.88163584, 0.11761114, 0.13790047, 0.98839265, 0.7575706, 0.271521, 0.06252285, 0.20463766, + 0.7797876, 0.1291307, 0.6389557, 0.6362458, 0.5012543, 0.21651421, 0.23741248, 0.4773882, + 0.5582616, 0.22913149, 0.8790845, 0.27697143, 0.02795082, 0.8450163, 0.08831802, 0.9342402, + 0.11166756, 0.8126855, 0.51420295, 0.016410068, 0.4544232, 0.99820787, 0.5780698, 0.5268707, + 0.9134579, 0.12053883, 0.18955784, 0.1712181, 0.45908722, 0.62256193, 0.21234894, 0.227052, + 0.62288225, 0.34845284, 0.6227857, 0.4712934, 0.8860071, 0.73518616, 0.06196327, 0.4374562, + 0.22151268, 0.10556084, 0.3694651, 0.9881851, 0.16397232, 0.3392293, 0.56751597, 0.036619555, + 0.029293122, 0.20366028, 0.87672514, 0.94488513, 0.757318, 0.04611278, 0.75021446, 0.78157973, + 0.5510609, 0.112084985, 0.7227879, 0.38071552, 0.026956385, 0.0661944, 0.01830097, 0.93569964, + 0.016782548, 0.6520325, 0.65408915, 0.67949796, 0.22223058, 0.6170246, 0.048233118, 0.37648138, + 0.7507222, 0.07674675, 0.7948974, 0.34886235, 0.6287428, 0.5898847, 0.36289844, 0.5742286, + 0.55302286, 0.15293828, 0.14192496, 0.25542694, 0.74583685, 0.26746377, 0.46973395, 0.5767695, + 0.59823835, 0.841206, 0.9202325, 0.7739221, 0.012398226, 0.6812478, 0.4104998, 0.15531828, + 0.087259874, 0.43376547, 0.9714025, 0.5119398, 0.68514013, 0.888018, 0.814389, 0.4122685, + 0.15542716, 0.5002437, 0.19416295, 0.6805713, 0.2512154, 0.4013521, 0.15283692, 0.96117616, + 0.7491866, 0.14855935, 0.8276927, 0.8740181, 0.92426944, 0.762874, 0.18986279, 0.7493188, + 0.18229857, 0.07731968, 0.08125962, 0.3810246, 0.6967921, 0.27431104, 0.36408317, 0.06947445, + 0.66624695, 0.6395791, 0.2616025, 0.19497731, 0.6184822, 0.85095865, 0.88908845, 0.66500485, + 0.33854932, 0.72965646, 0.099999785, 0.24559312, 0.07330083, 0.78916264, 0.32555407, 0.19688624, + 0.6883691, 0.9590563, 0.024735536, 0.86383885, 0.8535551, 0.53648174, 0.23104885, 0.32438585, + 0.24390268, 0.22208378, 0.32964125, 0.60782045, 0.8067584, 0.4333644, 0.71547633, 0.88111615, + 0.13616055, 0.1246885, 0.014324361, 0.6116363, 0.13974965, 0.9578596, 0.34269398, 0.89822793, + 0.25947088, 0.16268782, 0.53546876, 0.19461296, 0.6628742, 0.94426966, 0.67601794, 0.3931359, + 0.7517656, 0.88437337, 0.6926555, 0.7377358, 0.2495755, 0.50024426, 0.21591938, 0.12976523, + 0.40853027, 0.93721664, 0.95107466, 0.39639843, 0.52131736, 0.28126806, 0.85824645, 0.9051849, + 0.01418011, 0.21888365, 0.10943257, 0.94861233, 0.77483827, 0.7139178, 0.057136595, 0.73050946, + 0.61636233, 0.1265076, 0.60436803, 0.69086725, 0.0010129241, 0.036435887, 0.6615116, 0.299633, + 0.54606587, 0.9365053, 0.85605484, 0.922385, 0.7407089, 0.9777405, 0.63154066, 0.63591623, + 0.90876913, 0.88455915, 0.20310602, 0.20253302, 0.0067849625, 0.94629556, 0.37691054, 0.9782028, + 0.30444136, 0.63028383, 0.18043286, 0.4439906, 0.8348371, 0.7274056, 0.61829764, 0.037847787, + 0.8272368, 0.96214604, 0.12137349, 0.123067886, 0.8958763, 0.52505213, 0.1287523, 0.3720944, + 0.275705, 0.65144163, 0.85033256, 0.58481205, 0.42521322, 0.93586147, 0.16447607, 0.036439568, + 0.58734304, 0.47351632, 0.039843205, 0.8902792, 0.5108118, 0.8546036, 0.72372454, 0.6700668, + 0.7495971, 0.6261652, 0.3864259, 0.3707291, 0.85600305, 0.21752104, 0.4647959, 0.81866026, + 0.3182077, 0.818207, 0.09514821, 0.77856284, 0.85636705, 0.50847274, 0.74004, 0.38371703, + 0.7558068, 0.83101165, 0.926828, 0.35534334, 0.09596299, 0.7920985, 0.5529896, 0.36857986, + 0.46580777, 0.14399329, 0.85664755, 0.3613208, 0.6875624, 0.72801846, 0.527036, 0.9726332, + 0.23842148, 0.45130673, 0.37347084, 0.26971108, 0.1386262, 0.7580232, 0.51609135, 0.058183976, + 0.18664573, 0.031672336, 0.26660433, 0.6070062, 0.84071326, 0.38591322, 0.18007252, 0.07887025, + 0.73347634, 0.6561262, 0.13447234, 0.67980015, 0.92777556, 0.3683812, 0.5741038, 0.95749855, + 0.07317559, 0.017846042, 0.9049213, 0.7120097, 0.36087346, 0.10347511, 0.13109785, 0.5901893, + 0.29117107, 0.12251501, 0.54014134, 0.40506032, 0.13500193, 0.4703289, 0.24509083, 0.9977836, + 0.3149203, 0.868644, 0.16869761, 0.06429065, 0.52549416, 0.94598347, 0.5278666, 0.079894565, + 0.9639208, 0.7777773, 0.62784445, 0.0314362, 0.5935461, 0.8472358, 0.04485763, 0.8700403, + 0.8772029, 0.4159723, 0.1965355, 0.120780155, 0.8531019, 0.80408156, 0.6973105, 0.08317062, + 0.9005745, 0.6764151, 0.3158351, 0.71819824, 0.84577185, 0.7750122, 0.94386834, 0.26314744, + 0.41103536, 0.13668874, 0.36487988, 0.059131548, 0.19968359, 0.50981313, 0.4320044, 0.12719214, + 0.48997945, 0.82502675, 0.74808896, 0.58309615, 0.47563064, 0.09966165, 0.9966431, 0.44393525, + 0.07765738, 0.67010105, 0.5278574, 0.71902966, 0.27379337, 0.12431067, 0.14468168, 0.5108387, + 0.1713335, 0.08552699, 0.16371617, 0.8490791, 0.63014835, 0.80966836, 0.23412272, 0.18890859, + 0.833909, 0.364697, 0.62040085, 0.45685738, 0.48235595, 0.98572606, 0.6703567, 0.3673898, + 0.9839679, 0.06934336, 0.6308007, 0.02807519, 0.0559926, 0.11421437, 0.60753995, 0.80091286, + 0.67977196, 0.87189984, 0.6405409, 0.17567077, 0.24715477, 0.22483869, 0.9893541, 0.2867247, + 0.9920071, 0.85404116, 0.887798, 0.114156604, 0.34609696, 0.5829253, 0.49704382, 0.6803111, + 0.590904, 0.5591804, 0.7491872, 0.110933654, 0.4792608, 0.53978574, 0.9615793, 0.091931306, + 0.99974436, 0.1604676, 0.73506176, 0.20445003, 0.49350995, 0.11660648, 0.4548461, 0.057119142, + 0.47798702, 0.36280334, 0.16930713, 0.7582485, 0.16912746, 0.058451943, 0.9417538, 0.6090703, + 0.37534294, 0.33367616, 0.4648503, 0.6283148, 0.09792804, 0.5562001, 0.021292835, 0.40104258, + 0.57229954, 0.95048964, 0.4371712, 0.49681222, 0.36502722, 0.49660632, 0.32165202, 0.13998619, + 0.9103205, 0.54860955, 0.17592642, 0.086687185, 0.48977694, 0.78490406, 0.79321474, 0.8754006, + 0.39919505, 0.8306789, 0.63616955, 0.98329365, 0.41361818, 0.73879534, 0.5111836, 0.53245205, + 0.6174266, 0.14011684, 0.7355907, 0.14558467, 0.074935436, 0.33326453, 0.99400324, 0.44354424, + 0.13917476, 0.33401918, 0.6321505, 0.5430203, 0.6794353, 0.9580339, 0.69209194, 0.9813807, + 0.041151315, 0.029320937, 0.8479279, 0.6205179, 0.8825255, 0.85506666, 0.11929336, 0.5904389, + 0.5404614, 0.58944976, 0.22911972, 0.26724914, 0.92003053, 0.037999198, 0.9874244, 0.83350426, + 0.439306, 0.9047191, 0.87938565, 0.22491038, 0.7610156, 0.17606735, 0.06505076, 0.577056, + 0.5546063, 0.7323822, 0.94751245, 0.15575777, 0.15275358, 0.2501944, 0.19596528, 0.44116116, + 0.13858697, 0.65478885, 0.9421423, 0.38429725, 0.89086735, 0.8906657, 0.64992654, 0.7623599, + 0.020823486, 0.14515182, 0.6051233, 0.4854857, 0.10414482, 0.7267541, 0.52351373, 0.10117556, + 0.34659478, 0.7986462, 0.10371433, 0.7747162, 0.078648254, 0.46718153, 0.22036512, 0.86508393, + 0.9642702, 0.27087194, 0.06591158, 0.15014334, 0.9075542, 0.9635356, 0.4376853, 0.290267, + 0.39348447, 0.78795856, 0.12866218, 0.26524165, 0.095856875, 0.6031271, 0.94263685, 0.54864025, + 0.25479257, 0.11702571, 0.20408688, 0.6158638, 0.5709441, 0.57956505, 0.47291118, 0.8278522, + 0.20886846, 0.8463369, 0.809163, 0.35410735, 0.14648008, 0.4212491, 0.36251292, 0.67140543, + 0.43442374, 0.07705836, 0.42002708, 0.6199954, 0.8247542, 0.4997832, 0.8548057, 0.057287898, + 0.7074665, 0.31485626, 0.09200123, 0.31618625, 0.59809196, 0.25827205, 0.0053186826, 0.7434676, + 0.85600936, 0.5550741, 0.5199236, 0.96162254, 0.26309466, 0.60450137, 0.29413986, 0.38470513, + 0.79796076, 0.23805939, 0.9412749, 0.061217327, 0.15437259, 0.083577976, 0.14378692, 0.9722354, + 0.42544565, 0.45725676, 0.8308179, 0.018798511, 0.18310007, 0.32264143, 0.72388613, 0.75500935, + 0.26221997, 0.146799, 0.90839726, 0.25608784, 0.48756382, 0.15672493, 0.22976026, 0.9505964, + 0.8410182, 0.06569535, 0.498098, 0.591406, 0.90132546, 0.40089035, 0.40831077, 0.82992244, + 0.7829185, 0.03532195, 0.8220347, 0.5866948, 0.55850834, 0.7935884, 0.9029153, 0.62388855, + 0.17106935, 0.11976584, 0.8907406, 0.14083518, 0.42745417, 0.9865202, 0.5603676, 0.53336793, + 0.83118796, 0.7649143, 0.6994026, 0.116295666, 0.69610405, 0.03805204, 0.8971413, 0.6412358, + 0.008299126, 0.9906785, 0.22019914, 0.08867724, 0.58548, 0.5523809, 0.07090994, 0.024555296, + 0.048945986, 0.0008954834, 0.23588002, 0.14777812, 0.5006067, 0.13719136, 0.19650105, 0.46863157, + 0.24388368, 0.28450873, 0.08501847, 0.367798, 0.26598433, 0.08892508, 0.5231422, 0.854498, + 0.50532776, 0.96473, 0.760218, 0.13641119, 0.7014878, 0.2920151, 0.13381833, 0.74486643, + 0.13818067, 0.18079887, 0.57839566, 0.56782985, 0.5733893, 0.8142381, 0.038408525, 0.61868846, + 0.048855904, 0.8661853, 0.091889195, 0.42655867, 0.75064015, 0.41258946, 0.0327612, 0.6939966, + 0.5684132, 0.230771, 0.87241197, 0.41159534, 0.95303357, 0.5293433, 0.37525147, 0.91937405, + 0.46753627, 0.3657011, 0.58334947, 0.62074995, 0.79216284, 0.9344987, 0.32306752, 0.7569309, + 0.8670772, 0.49101356, 0.0095974505, 0.31980786, 0.5587957, 0.6286712, 0.8952423, 0.42964563, + 0.24610022, 0.46633002, 0.31894207, 0.39979902, 0.99703586, 0.09658354, 0.10385787, 0.092738345, + 0.9319688, 0.066221446, 0.567998, 0.47071677, 0.41960314, 0.722223, 0.79183286, 0.60883737, + 0.8055474, 0.6590216, 0.10029357, 0.20768817, 0.2308886, 0.41765857, 0.82652557, 0.11435715, + 0.5431178, 0.3349583, 0.55948156, 0.2596266, 0.402992, 0.7129533, 0.13520089, 0.939742, + 0.33552873, 0.44276634, 0.16549513, 0.48670354, 0.2104012, 0.9754525, 0.9223382, 0.37095273, + 0.26184326, 0.4906111, 0.68878114, 0.7259414, 0.3665008, 0.8523507, 0.33732775, 0.14485414, + 0.69918066, 0.40076008, 0.5142605, 0.89977413, 0.52837765, 0.6875541, 0.19875702, 0.8284416, + 0.6398044, 0.20458493, 0.8566812, 0.66207755, 0.537102, 0.84423125, 0.6897463, 0.2190155, + 0.93102056, 0.62825596, 0.13518804, 0.9768368, 0.5567279, 0.30512935, 0.39843616, 0.83009493, + 0.7366834, 0.72934085, 0.9458449, 0.7402775, 0.7288774, 0.100584194, 0.7478564, 0.69076705, + 0.99763054, 0.41462737, 0.5604459, 0.002231921, 0.19869287, 0.23542677, 0.41136438, 0.6479746, + 0.24400933, 0.33705348, 0.8468991, 0.0058162767, 0.11877123, 0.26026058, 0.83385074, 0.417612, + 0.80086476, 0.46976563, 0.79492086, 0.73824483, 0.71716267, 0.36049098, 0.58812624, 0.3940513, + 0.0023239073, 0.68416554, 0.1630907, 0.7990368, 0.74170923, 0.45847952, 0.0995642, 0.5392202, + 0.45672858, 0.16591415, 0.664447, 0.12247461, 0.28378534, 0.6875144, 0.020322617, 0.6955938, + 0.21689159, 0.48721343, 0.7328274, 0.21967441, 0.45823023, 0.39261988, 0.7113237, 0.47642282, + 0.8954901, 0.52823293, 0.9394127, 0.25911182, 0.30566335, 0.009611528, 0.9736044, 0.63713956, + 0.82650113, 0.16639459, 0.99990803, 0.5145273, 0.07233607, 0.6123276, 0.9062654, 0.7855298, + 0.23748927, 0.30767888, 0.5490877, 0.9528571, 0.5958136, 0.71137613, 0.13382663, 0.11335034, + 0.449443, 0.09932706, 0.52135324, 0.22994924, 0.6276635, 0.36845186, 0.93582106, 0.609704, + 0.9728418, 0.68666786, 0.9035467, 0.21347627, 0.51906675, 0.8404524, 0.2335569, 0.44711703, + 0.19230975, 0.027307436, 0.29597348, 0.11739075, 0.6876064, 0.5057953, 0.6232577, 0.604564, + 0.58094805, 0.94729763, 0.9821851, 0.15055138, 0.8435322, 0.7584666, 0.8806093, 0.18411398, + 0.3944063, 0.8260624, 0.8096688, 0.20633629, 0.48825827, 0.74365515, 0.009476059, 0.45804924, + 0.23057352, 0.39020398, 0.5416855, 0.3856682, 0.7087808, 0.69278914, 0.26646304, 0.39703688, + 0.074121974, 0.10197067, 0.76054734, 0.5685061, 0.41540262, 0.016435882, 0.42574394, 0.94364774, + 0.47606933, 0.91678923, 0.6490012, 0.68036586, 0.38626674, 0.78526974, 0.7661718, 0.2143752, + 0.80605865, 0.7194327, 0.81907, 0.69300437, 0.030783592, 0.027220597, 0.9588587, 0.4486546, + 0.017831376, 0.83792424, 0.8868172, 0.2974024, 0.9641097, 0.23758952, 0.8957832, 0.8881589, + 0.6808346, 0.5851483, 0.0764294, 0.74156153, 0.9979193, 0.3121031, 0.7687113, 0.37797043, + 0.40031847, 0.86602104, 0.730267, 0.57146907, 0.094653964, 0.32911018, 0.07178252, 0.4453038, + 0.62403214, 0.32731032, 0.5796096, 0.9893481, 0.87371916, 0.5734587, 0.3662533, 0.046901383, + 0.14311191, 0.31189272, 0.5506748, 0.5774784, 0.12961864, 0.12834151, 0.97953796, 0.23847981, + 0.021006035, 0.76084226, 0.99953127, 0.8011185, 0.7088403, 0.024610326, 0.21645589, 0.49395552, + 0.9507214, 0.44109955, 0.2926859, 0.16476253, 0.29695365, 0.3873897, 0.35400063, 0.6887212, + 0.7661417, 0.44151342, 0.67337024, 0.6367994, 0.65797997, 0.906435, 0.014439769, 0.10737592, + 0.21889497, 0.029528014, 0.5984496, 0.6860266, 0.76142836, 0.19123298, 0.24835177, 0.27197698, + 0.8864831, 0.49178717, 0.550463, 0.3338117, 0.32957888, 0.27066407, 0.7364635, 0.59942186, + 0.11085444, 0.08565405, 0.03862678, 0.4326196, 0.28077278, 0.20149076, 0.7499477, 0.7557222, + 0.95789206, 0.86195356, 0.8113367, 0.6881052, 0.45497125, 0.34273857, 0.5804998, 0.11457099, + 0.7464025, 0.8921554, 0.5822235, 0.6793123, 0.42616072, 0.5304293, 0.7325272, 0.7594884, + 0.19274779, 0.02070892, 0.27827948, 0.8051665, 0.83692664, 0.020188946, 0.35914233, 0.49547768, + 0.70504993, 0.07394841, 0.525945, 0.5723259, 0.8678083, 0.5818202, 0.8266031, 0.017404223, + 0.27958027, 0.84272736, 0.7281345, 0.8994748, 0.3798963, 0.5602465, 0.8170057, 0.5437445, + 0.9112873, 0.43589205, 0.5874092, 0.4374235, 0.68844056, 0.057151183, 0.1732611, 0.58042514, + 0.35312688, 0.2791384, 0.23987181, 0.26006386, 0.9232113, 0.94478124, 0.9187956, 0.93770313, + 0.50281125, 0.31585902, 0.9830553, 0.38102284, 0.8167936, 0.008173941, 0.24676272, 0.16458233, + 0.06555225, 0.5648193, 0.39973202, 0.58343333, 0.8022948, 0.8330524, 0.3795921, 0.63250124, + 0.20370321, 0.734535, 0.8938792, 0.40103462, 0.43277976, 0.92171884, 0.8070371, 0.64789873, + 0.9006873, 0.94551986, 0.21919903, 0.5886699, 0.34194836, 0.5665393, 0.09419294, 0.33479902, + 0.92393184, 0.7904314, 0.39666355, 0.0640373, 0.5771913, 0.43598288, 0.7269509, 0.90311337, + 0.18912931, 0.42282686, 0.37187123, 0.12362129, 0.65741915, 0.5898278, 0.77813035, 0.5200745, + 0.8995463, 0.6073706, 0.056360655, 0.18867631, 0.05090209, 0.51776093, 0.5049234, 0.5810924, + 0.5088219, 0.3351565, 0.48033553, 0.87127376, 0.7889749, 0.65809286, 0.822634, 0.49901298, + 0.47062632, 0.064933024, 0.65950155, 0.0118634105, 0.43638885, 0.3155548, 0.055309944, 0.76772034, + 0.007584079, 0.9907658, 0.2119053, 0.0099529, 0.5498476, 0.68341583, 0.9904796, 0.31085956, + 0.16738948, 0.6991246, 0.6891236, 0.7345778, 0.5101786, 0.9055166, 0.28389692, 0.40617087, + 0.285508, 0.8155711, 0.5552154, 0.24203478, 0.95564735, 0.8556771, 0.11413846, 0.53103644, + 0.6001929, 0.8728583, 0.652995, 0.59248614, 0.9303262, 0.76626694, 0.083685614, 0.5839915, + 0.55206066, 0.28864032, 0.18109223, 0.06013629, 0.30585563, 0.49497047, 0.031244803, 0.8254061, + 0.34467688, 0.16947599, 0.70388424, 0.089850344, 0.9689693, 0.088056214, 0.9888344, 0.56510967, + 0.7810361, 0.25333068, 0.72635543, 0.6208177, 0.7603394, 0.81327516, 0.812073, 0.15190694, + 0.8766273, 0.68086886, 0.40976003, 0.6769893, 0.03042084, 0.39799348, 0.38053334, 0.40112254, + 0.61543894, 0.10513203, 0.18251711, 0.22153829, 0.7244244, 0.22376063, 0.10031522, 0.79053754, + 0.7843263, 0.7298093, 0.8973579, 0.7861713, 0.15179288, 0.024288114, 0.56206715, 0.51213664, + 0.8840239, 0.08788527, 0.81145, 0.6769955, 0.039911535, 0.4628679, 0.82365215, 0.7387855, + 0.47656733, 0.029185295, 0.18350895, 0.62498677, 0.08521046, 0.35425547, 0.7949853, 0.9466834, + 0.78894264, 0.30276173, 0.4744114, 0.86383724, 0.9055391, 0.7672961, 0.8406853, 0.5572755, + 0.15301545, 0.9358179, 0.83649135, 0.030530108, 0.9159173, 0.025901658, 0.00011405395, 0.8523392, + 0.1188017, 0.89762336, 0.7929654, 0.9425356, 0.58654344, 0.7035378, 0.361211, 0.15257105, + 0.2814799, 0.44373164, 0.744971, 0.6952391, 0.040251687, 0.47532842, 0.70532703, 0.43007088, + 0.93482405, 0.9506745, 0.9972287, 0.84903115, 0.5498767, 0.6982299, 0.60659754, 0.116727814, + 0.24719998, 0.25417453, 0.5239801, 0.10409364, 0.6263765, 0.79312205, 0.82286817, 0.45066565, + 0.02907124, 0.33116972, 0.5061851, 0.1875871, 0.56129, 0.8524497, 0.36013994, 0.085404865, + 0.94155073, 0.32184035, 0.58235735, 0.46180746, 0.022325099, 0.14544618, 0.5170238, 0.67768705, + 0.23049083, 0.4064205, 0.09570609, 0.9652428, 0.028672969, 0.1510829, 0.30246252, 0.4205718, + 0.2910258, 0.67623764, 0.69533557, 0.33236894, 0.17955771, 0.25711736, 0.5261945, 0.48835787}; float rndf() { - static int _cur_rnd = 0; - if (_cur_rnd > _rnd_count) - _cur_rnd = 0; - return _rnd[_cur_rnd++]; + static int _cur_rnd = 0; + if (_cur_rnd > _rnd_count) + _cur_rnd = 0; + return _rnd[_cur_rnd++]; } diff --git a/tests/common/test.c b/tests/common/test.c index c583f8f..0295993 100644 --- a/tests/common/test.c +++ b/tests/common/test.c @@ -3,842 +3,795 @@ #include #if defined(_WIN32) || defined(_WIN64) -int gettimeofday(struct timeval * tp, void * tzp) -{ - // FILETIME Jan 1 1970 00:00:00 - // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's - static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); - - SYSTEMTIME nSystemTime; - FILETIME nFileTime; - uint64_t nTime; - - GetSystemTime( &nSystemTime ); - SystemTimeToFileTime( &nSystemTime, &nFileTime ); - nTime = ((uint64_t)nFileTime.dwLowDateTime ) ; - nTime += ((uint64_t)nFileTime.dwHighDateTime) << 32; - - tp->tv_sec = (long) ((nTime - EPOCH) / 10000000L); - tp->tv_usec = (long) (nSystemTime.wMilliseconds * 1000); - return 0; +int gettimeofday(struct timeval *tp, void *tzp) { + // FILETIME Jan 1 1970 00:00:00 + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); + + SYSTEMTIME nSystemTime; + FILETIME nFileTime; + uint64_t nTime; + + GetSystemTime(&nSystemTime); + SystemTimeToFileTime(&nSystemTime, &nFileTime); + nTime = ((uint64_t)nFileTime.dwLowDateTime); + nTime += ((uint64_t)nFileTime.dwHighDateTime) << 32; + + tp->tv_sec = (long)((nTime - EPOCH) / 10000000L); + tp->tv_usec = (long)(nSystemTime.wMilliseconds * 1000); + return 0; } #endif -float panX = 0.f; -float panY = 0.f; -float lastX = 0.f; -float lastY = 0.f; -float zoom = 1.0f; -bool mouseDown = false; - -VkvgDevice device = NULL; -VkvgSurface surf = NULL; - -uint32_t test_size = 500; // items drawn in one run, or complexity -uint32_t iterations = 500; // repeat test n times -uint32_t test_width = 512; -uint32_t test_height= 512; -bool test_vsync = false; -bool quiet = false;//if true, don't print details and head row -bool first_test = true; //if multiple tests, dont print header row. -bool no_test_size= false;//several test consist of a single draw sequence without looping 'size' times - //those test must be preceded by setting no_test_size to 'true' -int test_index = 0; -int single_test = -1; //if not < 0, contains the index of the single test to run - - -static bool paused = false; -static bool offscreen = false; -static bool threadAware = false; -static VkSampleCountFlags samples = VK_SAMPLE_COUNT_1_BIT; +float panX = 0.f; +float panY = 0.f; +float lastX = 0.f; +float lastY = 0.f; +float zoom = 1.0f; +bool mouseDown = false; + +VkvgDevice device = NULL; +VkvgSurface surf = NULL; + +uint32_t test_size = 500; // items drawn in one run, or complexity +uint32_t iterations = 500; // repeat test n times +uint32_t test_width = 512; +uint32_t test_height = 512; +bool test_vsync = false; +bool quiet = false; // if true, don't print details and head row +bool first_test = true; // if multiple tests, dont print header row. +bool no_test_size = false; // several test consist of a single draw sequence without looping 'size' times + // those test must be preceded by setting no_test_size to 'true' +int test_index = 0; +int single_test = -1; // if not < 0, contains the index of the single test to run + +static bool paused = false; +static bool offscreen = false; +static bool threadAware = false; +static VkSampleCountFlags samples = VK_SAMPLE_COUNT_1_BIT; static VkPhysicalDeviceType preferedPhysicalDeviceType = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; -static vk_engine_t* e; -static char* saveToPng = NULL; - -static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { - if (action != GLFW_PRESS) - return; - switch (key) { - case GLFW_KEY_SPACE: - paused = !paused; - break; - case GLFW_KEY_ESCAPE : - glfwSetWindowShouldClose(window, GLFW_TRUE); - break; +static vk_engine_t *e; +static char *saveToPng = NULL; + +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { + if (action != GLFW_PRESS) + return; + switch (key) { + case GLFW_KEY_SPACE: + paused = !paused; + break; + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GLFW_TRUE); + break; #ifdef VKVG_WIRED_DEBUG - case GLFW_KEY_F1: - vkvg_wired_debug ^= (1U << 0); - break; - case GLFW_KEY_F2: - vkvg_wired_debug ^= (1U << 1); - break; - case GLFW_KEY_F3: - vkvg_wired_debug ^= (1U << 2); - break; + case GLFW_KEY_F1: + vkvg_wired_debug ^= (1U << 0); + break; + case GLFW_KEY_F2: + vkvg_wired_debug ^= (1U << 1); + break; + case GLFW_KEY_F3: + vkvg_wired_debug ^= (1U << 2); + break; #endif - } + } } -static void char_callback (GLFWwindow* window, uint32_t c){} -static void mouse_move_callback(GLFWwindow* window, double x, double y){ - if (mouseDown) { - panX += ((float)x-lastX); - panY += ((float)y-lastY); - } - lastX = (float)x; - lastY = (float)y; +static void char_callback(GLFWwindow *window, uint32_t c) {} +static void mouse_move_callback(GLFWwindow *window, double x, double y) { + if (mouseDown) { + panX += ((float)x - lastX); + panY += ((float)y - lastY); + } + lastX = (float)x; + lastY = (float)y; } -static void scroll_callback(GLFWwindow* window, double x, double y){ - if (y<0.f) - zoom *= 0.5f; - else - zoom *= 2.0f; +static void scroll_callback(GLFWwindow *window, double x, double y) { + if (y < 0.f) + zoom *= 0.5f; + else + zoom *= 2.0f; } -static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif){ - if (but != GLFW_MOUSE_BUTTON_1) - return; - if (state == GLFW_TRUE) - mouseDown = true; - else - mouseDown = false; +static void mouse_button_callback(GLFWwindow *window, int but, int state, int modif) { + if (but != GLFW_MOUSE_BUTTON_1) + return; + if (state == GLFW_TRUE) + mouseDown = true; + else + mouseDown = false; } -double time_diff(struct timeval x , struct timeval y) -{ - double x_ms , y_ms , diff; +double time_diff(struct timeval x, struct timeval y) { + double x_ms, y_ms, diff; - x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; - y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; + x_ms = (double)x.tv_sec * 1000000 + (double)x.tv_usec; + y_ms = (double)y.tv_sec * 1000000 + (double)y.tv_usec; - diff = (double)y_ms - (double)x_ms; + diff = (double)y_ms - (double)x_ms; - return diff; + return diff; } /* from caskbench */ -double get_tick (void) -{ - struct timeval now; - gettimeofday (&now, NULL); - return (double)now.tv_sec + (double)now.tv_usec / 1000000.0; +double get_tick(void) { + struct timeval now; + gettimeofday(&now, NULL); + return (double)now.tv_sec + (double)now.tv_usec / 1000000.0; } -double median_run_time (double data[], int n) -{ - double temp; - int i, j; - for (i = 0; i < n; i++) - for (j = i+1; j < n; j++) - { - if (data[i] > data[j]) - { - temp = data[j]; - data[j] = data[i]; - data[i] = temp; - } - } - if (n % 2 == 0) - return (data[n/2] + data[n/2-1])/2; - return data[n/2]; +double median_run_time(double data[], int n) { + double temp; + int i, j; + for (i = 0; i < n; i++) + for (j = i + 1; j < n; j++) { + if (data[i] > data[j]) { + temp = data[j]; + data[j] = data[i]; + data[i] = temp; + } + } + if (n % 2 == 0) + return (data[n / 2] + data[n / 2 - 1]) / 2; + return data[n / 2]; } -double standard_deviation (const double data[], int n, double mean) -{ - double sum_deviation = 0.0; - int i; - for (i = 0; i < n; ++i) - sum_deviation += (data[i]-mean) * (data[i]-mean); - return sqrt (sum_deviation / n); +double standard_deviation(const double data[], int n, double mean) { + double sum_deviation = 0.0; + int i; + for (i = 0; i < n; ++i) + sum_deviation += (data[i] - mean) * (data[i] - mean); + return sqrt(sum_deviation / n); } /***************/ -void init_test (uint32_t width, uint32_t height){ - if (test_vsync) - e = vkengine_create (preferedPhysicalDeviceType, VK_PRESENT_MODE_FIFO_KHR, width, height); - else - e = vkengine_create (preferedPhysicalDeviceType, VK_PRESENT_MODE_MAILBOX_KHR, width, height); +void init_test(uint32_t width, uint32_t height) { + if (test_vsync) + e = vkengine_create(preferedPhysicalDeviceType, VK_PRESENT_MODE_FIFO_KHR, width, height); + else + e = vkengine_create(preferedPhysicalDeviceType, VK_PRESENT_MODE_MAILBOX_KHR, width, height); - VkhPresenter r = e->renderer; - vkengine_set_key_callback (e, key_callback); - vkengine_set_mouse_but_callback(e, mouse_button_callback); - vkengine_set_cursor_pos_callback(e, mouse_move_callback); - vkengine_set_scroll_callback(e, scroll_callback); + VkhPresenter r = e->renderer; + vkengine_set_key_callback(e, key_callback); + vkengine_set_mouse_but_callback(e, mouse_button_callback); + vkengine_set_cursor_pos_callback(e, mouse_move_callback); + vkengine_set_scroll_callback(e, scroll_callback); - vkvg_device_create_info_t info = { - samples, - false, - vkh_app_get_inst(e->app), - r->dev->phy, - r->dev->dev, - r->qFam, - 0 - }; + vkvg_device_create_info_t info = {samples, false, vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0}; device = vkvg_device_create(&info); - surf = vkvg_surface_create(device, width, height); + surf = vkvg_surface_create(device, width, height); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), width, height); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), width, height); } -void clear_test () { - vkDeviceWaitIdle(e->dev->dev); +void clear_test() { + vkDeviceWaitIdle(e->dev->dev); - vkvg_surface_destroy (surf); - vkvg_device_destroy (device); + vkvg_surface_destroy(surf); + vkvg_device_destroy(device); - vkengine_destroy (e); + vkengine_destroy(e); } #ifdef VKVG_TEST_DIRECT_DRAW -VkvgSurface* surfaces; +VkvgSurface *surfaces; #endif -void _print_usage_and_exit () { - printf("\nUsage: test [options]\n\n"); - printf("\t-i iterations:\tSpecify the repeat count for the test.\n"); - printf("\t-s size:\tWhen applicable, specify the size of the test.\n"); - printf("\t-x width:\tOutput surface width.\n"); - printf("\t-y height:\tOutput surface height.\n"); - printf("\t-S num samples:\tOutput surface filter, default is 1.\n"); +void _print_usage_and_exit() { + printf("\nUsage: test [options]\n\n"); + printf("\t-i iterations:\tSpecify the repeat count for the test.\n"); + printf("\t-s size:\tWhen applicable, specify the size of the test.\n"); + printf("\t-x width:\tOutput surface width.\n"); + printf("\t-y height:\tOutput surface height.\n"); + printf("\t-S num samples:\tOutput surface filter, default is 1.\n"); printf("\t-g gpu_type:\tSet prefered GPU type:\n"); - printf("\t\t\t - 0: Other\n"); - printf("\t\t\t - 1: Integrated (second choice)\n"); - printf("\t\t\t - 2: Discrete (first choice)\n"); - printf("\t\t\t - 3: Virtual\n"); - printf("\t\t\t - 4: Cpu\n"); - printf("\t-l line_width:\tset lines width for stokes.\n"); - printf("\t-j line_join:\tset line joins for strokes:\n"); - printf("\t\t\t - m: Mitter(default)\n"); - printf("\t\t\t - r: Rount\n"); - printf("\t\t\t - b: Bevel\n"); - printf("\t-c line_cap:\tset line caps for strokes:\n"); - printf("\t\t\t - b: Butt (default)\n"); - printf("\t\t\t - r: Rount\n"); - printf("\t\t\t - s: Square\n"); - printf("\t-f fill_rule:\tset current fill rule:\n"); - printf("\t\t\t - 0: Even Odd\n"); - printf("\t\t\t - 1: Non Zero\n"); - printf("\t-d:\t\tenable dashes.\n"); - printf("\t-n index:\tRun only a single test, zero based index.\n"); - printf("\t-q:\t\tQuiet, don't print measures table head row, usefull for batch tests.\n"); - printf("\t-t:\t\tThread aware, set device in multithreading aware mode.\n"); - printf("\t-p:\t\tPrint test details and exit without performing test, usefull to print details in logs.\n"); - printf("\t-vsync:\t\tEnable VSync, disabled by default.\n"); - printf("\t-o:\t\tPerform test offscreen.\n"); - printf("\t-w filepath:\twrite last image to png.\n"); + printf("\t\t\t - 0: Other\n"); + printf("\t\t\t - 1: Integrated (second choice)\n"); + printf("\t\t\t - 2: Discrete (first choice)\n"); + printf("\t\t\t - 3: Virtual\n"); + printf("\t\t\t - 4: Cpu\n"); + printf("\t-l line_width:\tset lines width for stokes.\n"); + printf("\t-j line_join:\tset line joins for strokes:\n"); + printf("\t\t\t - m: Mitter(default)\n"); + printf("\t\t\t - r: Rount\n"); + printf("\t\t\t - b: Bevel\n"); + printf("\t-c line_cap:\tset line caps for strokes:\n"); + printf("\t\t\t - b: Butt (default)\n"); + printf("\t\t\t - r: Rount\n"); + printf("\t\t\t - s: Square\n"); + printf("\t-f fill_rule:\tset current fill rule:\n"); + printf("\t\t\t - 0: Even Odd\n"); + printf("\t\t\t - 1: Non Zero\n"); + printf("\t-d:\t\tenable dashes.\n"); + printf("\t-n index:\tRun only a single test, zero based index.\n"); + printf("\t-q:\t\tQuiet, don't print measures table head row, usefull for batch tests.\n"); + printf("\t-t:\t\tThread aware, set device in multithreading aware mode.\n"); + printf("\t-p:\t\tPrint test details and exit without performing test, usefull to print details in logs.\n"); + printf("\t-vsync:\t\tEnable VSync, disabled by default.\n"); + printf("\t-o:\t\tPerform test offscreen.\n"); + printf("\t-w filepath:\twrite last image to png.\n"); #ifdef DEBUG - printf("\t-L level:\tLog level in hexadecimal format (0xFF), 0 to disable.\n"); - printf("\t\t\tsee vkvg.h for possible values.\n"); + printf("\t-L level:\tLog level in hexadecimal format (0xFF), 0 to disable.\n"); + printf("\t\t\tsee vkvg.h for possible values.\n"); #endif - printf("\t-h:\t\tThis help message.\n"); - printf("\n"); - exit(-1); + printf("\t-h:\t\tThis help message.\n"); + printf("\n"); + exit(-1); } -void _parse_args (int argc, char* argv[]) { - bool printTestDetailsAndExit = false; - for (int i = 1; i < argc; i++) { - if (strcmp (argv[i], "-h\0") == 0) - _print_usage_and_exit (); - if (strcmp (argv[i], "-p\0") == 0) - printTestDetailsAndExit = true; - else if (strcmp (argv[i], "-vsync\0") == 0) - test_vsync = true; - else if (strcmp(argv[i], "-q\0") == 0) - quiet = true; - else if (strcmp(argv[i], "-t\0") == 0) - threadAware = true; - else if (strcmp (argv[i], "-i\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - iterations = atoi (argv[i]); - }else if (strcmp (argv[i], "-x\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - test_width = atoi (argv[i]); - }else if (strcmp (argv[i], "-y\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - test_height = atoi (argv[i]); - }else if (strcmp (argv[i], "-n\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - single_test = atoi (argv[i]); - }else if (strcmp (argv[i], "-s\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - test_size = atoi (argv[i]); - }else if (strcmp (argv[i], "-S\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - samples = (VkSampleCountFlags)atoi (argv[i]); - }else if (strcmp (argv[i], "-g\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - preferedPhysicalDeviceType = (VkPhysicalDeviceType)atoi (argv[i]); - }else if (strcmp (argv[i], "-l\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - line_width = atoi (argv[i]); - }else if (strcmp (argv[i], "-d\0") == 0) { - dashes_count = 2; - }else if (strcmp (argv[i], "-f\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - fill_rule = atoi (argv[i]); - } else if (strcmp (argv[i], "-o\0") == 0) { - offscreen = true; - }else if (strcmp (argv[i], "-j\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - switch (argv[i][0]) { - case 'm': - line_join = VKVG_LINE_JOIN_MITER; - break; - case 'r': - line_join = VKVG_LINE_JOIN_ROUND; - break; - case 'b': - line_join = VKVG_LINE_JOIN_BEVEL; - break; - default: - _print_usage_and_exit(); - } - }else if (strcmp (argv[i], "-c\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - switch (argv[i][0]) { - case 'b': - line_cap = VKVG_LINE_CAP_BUTT; - break; - case 'r': - line_cap = VKVG_LINE_CAP_ROUND; - break; - case 's': - line_cap = VKVG_LINE_CAP_SQUARE; - break; - default: - _print_usage_and_exit(); - } - }else if (strcmp (argv[i], "-w\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - saveToPng = argv[i]; +void _parse_args(int argc, char *argv[]) { + bool printTestDetailsAndExit = false; + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-h\0") == 0) + _print_usage_and_exit(); + if (strcmp(argv[i], "-p\0") == 0) + printTestDetailsAndExit = true; + else if (strcmp(argv[i], "-vsync\0") == 0) + test_vsync = true; + else if (strcmp(argv[i], "-q\0") == 0) + quiet = true; + else if (strcmp(argv[i], "-t\0") == 0) + threadAware = true; + else if (strcmp(argv[i], "-i\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + iterations = atoi(argv[i]); + } else if (strcmp(argv[i], "-x\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + test_width = atoi(argv[i]); + } else if (strcmp(argv[i], "-y\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + test_height = atoi(argv[i]); + } else if (strcmp(argv[i], "-n\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + single_test = atoi(argv[i]); + } else if (strcmp(argv[i], "-s\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + test_size = atoi(argv[i]); + } else if (strcmp(argv[i], "-S\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + samples = (VkSampleCountFlags)atoi(argv[i]); + } else if (strcmp(argv[i], "-g\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + preferedPhysicalDeviceType = (VkPhysicalDeviceType)atoi(argv[i]); + } else if (strcmp(argv[i], "-l\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + line_width = atoi(argv[i]); + } else if (strcmp(argv[i], "-d\0") == 0) { + dashes_count = 2; + } else if (strcmp(argv[i], "-f\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + fill_rule = atoi(argv[i]); + } else if (strcmp(argv[i], "-o\0") == 0) { + offscreen = true; + } else if (strcmp(argv[i], "-j\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + switch (argv[i][0]) { + case 'm': + line_join = VKVG_LINE_JOIN_MITER; + break; + case 'r': + line_join = VKVG_LINE_JOIN_ROUND; + break; + case 'b': + line_join = VKVG_LINE_JOIN_BEVEL; + break; + default: + _print_usage_and_exit(); + } + } else if (strcmp(argv[i], "-c\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + switch (argv[i][0]) { + case 'b': + line_cap = VKVG_LINE_CAP_BUTT; + break; + case 'r': + line_cap = VKVG_LINE_CAP_ROUND; + break; + case 's': + line_cap = VKVG_LINE_CAP_SQUARE; + break; + default: + _print_usage_and_exit(); + } + } else if (strcmp(argv[i], "-w\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + saveToPng = argv[i]; #ifdef DEBUG - }else if (strcmp (argv[i], "-L\0") == 0) { - if (argc -1 < ++i) - _print_usage_and_exit(); - sscanf(argv[i], "%x", &vkvg_log_level); + } else if (strcmp(argv[i], "-L\0") == 0) { + if (argc - 1 < ++i) + _print_usage_and_exit(); + sscanf(argv[i], "%x", &vkvg_log_level); #endif - }else - _print_usage_and_exit(); - } - if (printTestDetailsAndExit) { + } else + _print_usage_and_exit(); + } + if (printTestDetailsAndExit) { #ifdef DEBUG - printf("Debug build\n"); + printf("Debug build\n"); #else - printf("Release build\n"); + printf("Release build\n"); #endif #ifdef VKVG_USE_RENDERDOC - printf("Render doc enabled\n"); + printf("Render doc enabled\n"); #endif #ifdef VKVG_USE_VALIDATION - printf("Validation:\tenabled\n"); + printf("Validation:\tenabled\n"); #else - printf("Validation:\no\n"); + printf("Validation:\no\n"); #endif - printf("surf dims:\t%d x %d\n", test_width, test_height); - printf("Samples:\t%d\n", samples); - printf("Gpu type:\t"); - switch (preferedPhysicalDeviceType) { - case VK_PHYSICAL_DEVICE_TYPE_OTHER: - printf("Other\n"); - break; - case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: - printf("Integrated\n"); - break; - case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: - printf("Discrete\n"); - break; - case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: - printf("Virtual\n"); - break; - case VK_PHYSICAL_DEVICE_TYPE_CPU: - printf("CPU\n"); - break; - } - - if (offscreen) - printf("Offscreen:\ttrue\n"); - else - printf("Offscreen:\tfalse\n"); - - if (fill_rule == VKVG_FILL_RULE_EVEN_ODD) - printf("Fillrule:\tEven/Odd\n"); - else - printf("Fillrule:\tNon zero\n"); - - printf("\n"); - exit(0); - } + printf("surf dims:\t%d x %d\n", test_width, test_height); + printf("Samples:\t%d\n", samples); + printf("Gpu type:\t"); + switch (preferedPhysicalDeviceType) { + case VK_PHYSICAL_DEVICE_TYPE_OTHER: + printf("Other\n"); + break; + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + printf("Integrated\n"); + break; + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + printf("Discrete\n"); + break; + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: + printf("Virtual\n"); + break; + case VK_PHYSICAL_DEVICE_TYPE_CPU: + printf("CPU\n"); + break; + } + + if (offscreen) + printf("Offscreen:\ttrue\n"); + else + printf("Offscreen:\tfalse\n"); + + if (fill_rule == VKVG_FILL_RULE_EVEN_ODD) + printf("Fillrule:\tEven/Odd\n"); + else + printf("Fillrule:\tNon zero\n"); + + printf("\n"); + exit(0); + } } -void _print_results (const char *testName, int argc, char* argv[], uint32_t i, double run_total, double* run_time_values) { - char* whoami; - (whoami = strrchr(argv[0], '/')) ? ++whoami : (whoami = argv[0]); +void _print_results(const char *testName, int argc, char *argv[], uint32_t i, double run_total, + double *run_time_values) { + char *whoami; + (whoami = strrchr(argv[0], '/')) ? ++whoami : (whoami = argv[0]); - double avg_run_time = run_total / (double)i; - double med_run_time = median_run_time (run_time_values, i); - double standard_dev = standard_deviation (run_time_values, i, avg_run_time); - double avg_frames_per_second = (1.0 / avg_run_time); - avg_frames_per_second = (avg_frames_per_second<9999) ? avg_frames_per_second:9999; + double avg_run_time = run_total / (double)i; + double med_run_time = median_run_time(run_time_values, i); + double standard_dev = standard_deviation(run_time_values, i, avg_run_time); + double avg_frames_per_second = (1.0 / avg_run_time); + avg_frames_per_second = (avg_frames_per_second < 9999) ? avg_frames_per_second : 9999; - if (!quiet && (test_index == 0 || test_index == single_test)) { + if (!quiet && (test_index == 0 || test_index == single_test)) { #if VKVG_DBG_STATS - printf ("_____________________________________________________________________________________________________________________________\n"); - printf ("| N° | Test File Name | Sub Test | Iter | Size | Pts |Pathes| Vx cache | Ix cache | VBO | IBO |\n"); - printf ("|----|-----------------|---------------------------|------|------|-------|------|----------|----------|----------|----------|\n"); + printf("_______________________________________________________________________________________________________" + "______________________\n"); + printf("| N° | Test File Name | Sub Test | Iter | Size | Pts |Pathes| Vx cache | Ix cache " + "| VBO | IBO |\n"); + printf("|----|-----------------|---------------------------|------|------|-------|------|----------|----------|" + "----------|----------|\n"); #else - printf ("__________________________________________________________________________________________________________\n"); - printf ("| N° | Test File Name | Sub Test | Iter | Size | FPS | Average | Median | Sigma |\n"); - printf ("|----|-----------------|---------------------------|------|------|---------|---------|---------|---------|\n"); + printf("_______________________________________________________________________________________________________" + "___\n"); + printf("| N° | Test File Name | Sub Test | Iter | Size | FPS | Average | Median | Sigma " + " |\n"); + printf("|----|-----------------|---------------------------|------|------|---------|---------|---------|-------" + "--|\n"); #endif - } - - printf ("| %2d | %-15s | %-25s | %4d | ", test_index, whoami, testName, i); - if (no_test_size) - printf ("%4d | ", 1); - else - printf ("%4d | ", test_size); + } + + printf("| %2d | %-15s | %-25s | %4d | ", test_index, whoami, testName, i); + if (no_test_size) + printf("%4d | ", 1); + else + printf("%4d | ", test_size); #if VKVG_DBG_STATS - vkvg_debug_stats_t dbgStats = vkvg_device_get_stats (device); - printf ("%5d | %4d | %8d | %8d | %8d | %8d |\n", - dbgStats.sizePoints, dbgStats.sizePathes, dbgStats.sizeVertices, - dbgStats.sizeIndices, dbgStats.sizeVBO, dbgStats.sizeIBO); -#else - printf ("%7.2f | %6.5f | %6.5f | %6.5f |\n", - avg_frames_per_second, avg_run_time, med_run_time, standard_dev); -#endif + vkvg_debug_stats_t dbgStats = vkvg_device_get_stats(device); + printf("%5d | %4d | %8d | %8d | %8d | %8d |\n", dbgStats.sizePoints, dbgStats.sizePathes, dbgStats.sizeVertices, + dbgStats.sizeIndices, dbgStats.sizeVBO, dbgStats.sizeIBO); +#else + printf("%7.2f | %6.5f | %6.5f | %6.5f |\n", avg_frames_per_second, avg_run_time, med_run_time, standard_dev); +#endif } #if VKVG_DBG_STATS -void _print_debug_stats () { +void _print_debug_stats() { - vkvg_debug_stats_t dbgStats = vkvg_device_get_stats (device); - printf ("| %8d | %8d | %8d | %8d | %8d | %8d |\n", dbgStats.sizePoints, dbgStats.sizePathes, dbgStats.sizeVertices, - dbgStats.sizeIndices, dbgStats.sizeVBO, dbgStats.sizeIBO); + vkvg_debug_stats_t dbgStats = vkvg_device_get_stats(device); + printf("| %8d | %8d | %8d | %8d | %8d | %8d |\n", dbgStats.sizePoints, dbgStats.sizePathes, dbgStats.sizeVertices, + dbgStats.sizeIndices, dbgStats.sizeVBO, dbgStats.sizeIBO); } #endif -void perform_test (void(*testfunc)(void), const char *testName, int argc, char* argv[]) { - setlocale(LC_ALL, ""); - //dumpLayerExts(); - _parse_args (argc, argv); +void perform_test(void (*testfunc)(void), const char *testName, int argc, char *argv[]) { + setlocale(LC_ALL, ""); + // dumpLayerExts(); + _parse_args(argc, argv); - //init random gen - struct timeval currentTime; - gettimeofday(¤tTime, NULL); - srand((unsigned)currentTime.tv_usec); + // init random gen + struct timeval currentTime; + gettimeofday(¤tTime, NULL); + srand((unsigned)currentTime.tv_usec); - if (iterations == 0) - iterations = 9999; + if (iterations == 0) + iterations = 9999; - if (single_test >= 0 && test_index != single_test) { - test_index++; - return; - } + if (single_test >= 0 && test_index != single_test) { + test_index++; + return; + } - if (offscreen) - perform_test_offscreen(testfunc, testName, argc, argv); - else - perform_test_onscreen(testfunc, testName, argc, argv); + if (offscreen) + perform_test_offscreen(testfunc, testName, argc, argv); + else + perform_test_onscreen(testfunc, testName, argc, argv); } -void perform_test_offscreen (void(*testfunc)(void), const char *testName, int argc, char* argv[]) { - uint32_t enabledExtsCount = 0, phyCount = 0; - const char* enabledExts [10]; +void perform_test_offscreen(void (*testfunc)(void), const char *testName, int argc, char *argv[]) { + uint32_t enabledExtsCount = 0, phyCount = 0; + const char *enabledExts[10]; #ifdef VKVG_USE_RENDERDOC - const uint32_t enabledLayersCount = 2; - const char* enabledLayers[] = {"VK_LAYER_KHRONOS_validation", "VK_LAYER_RENDERDOC_Capture"}; -#elif defined (VKVG_USE_VALIDATION) - const uint32_t enabledLayersCount = 1; - const char* enabledLayers[] = {"VK_LAYER_KHRONOS_validation"}; + const uint32_t enabledLayersCount = 2; + const char *enabledLayers[] = {"VK_LAYER_KHRONOS_validation", "VK_LAYER_RENDERDOC_Capture"}; +#elif defined(VKVG_USE_VALIDATION) + const uint32_t enabledLayersCount = 1; + const char *enabledLayers[] = {"VK_LAYER_KHRONOS_validation"}; #else - const uint32_t enabledLayersCount = 0; - const char* enabledLayers[] = {NULL}; + const uint32_t enabledLayersCount = 0; + const char *enabledLayers[] = {NULL}; #endif -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - enabledExts[enabledExtsCount] = "VK_EXT_debug_utils"; - enabledExtsCount++; +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + enabledExts[enabledExtsCount] = "VK_EXT_debug_utils"; + enabledExtsCount++; #endif - VkhApp app = vkh_app_create(1, 1, "vkvgTest", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_app_enable_debug_messenger(app - , VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT - , VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT - //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT - //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT - , NULL); + VkhApp app = vkh_app_create(1, 1, "vkvgTest", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_app_enable_debug_messenger( + app, + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT + //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT + , + NULL); #endif - bool deferredResolve = false; - VkhPhyInfo* phys = vkh_app_get_phyinfos (app, &phyCount, VK_NULL_HANDLE); - VkhPhyInfo pi = 0; - if (!vkengine_try_get_phyinfo(phys, phyCount, preferedPhysicalDeviceType, &pi)) - if (!vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, &pi)) - if (!vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, &pi)) - pi = phys[0]; - - uint32_t qCount = 0; - float qPriorities[] = {0.0}; - VkDeviceQueueCreateInfo pQueueInfos[] = { {0},{0},{0} }; - if (vkh_phyinfo_create_queues (pi, pi->gQueue, 1, qPriorities, &pQueueInfos[qCount])) - qCount++; - VkPhysicalDeviceFeatures enabledFeatures = { - .fillModeNonSolid = true, - }; - - VkDeviceCreateInfo device_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .queueCreateInfoCount = qCount, - .pQueueCreateInfos = (VkDeviceQueueCreateInfo*)&pQueueInfos, - .pEnabledFeatures = &enabledFeatures}; - - VkhDevice dev = vkh_device_create(app, pi, &device_info); + bool deferredResolve = false; + VkhPhyInfo *phys = vkh_app_get_phyinfos(app, &phyCount, VK_NULL_HANDLE); + VkhPhyInfo pi = 0; + if (!vkengine_try_get_phyinfo(phys, phyCount, preferedPhysicalDeviceType, &pi)) + if (!vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, &pi)) + if (!vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, &pi)) + pi = phys[0]; + + uint32_t qCount = 0; + float qPriorities[] = {0.0}; + VkDeviceQueueCreateInfo pQueueInfos[] = {{0}, {0}, {0}}; + if (vkh_phyinfo_create_queues(pi, pi->gQueue, 1, qPriorities, &pQueueInfos[qCount])) + qCount++; + VkPhysicalDeviceFeatures enabledFeatures = { + .fillModeNonSolid = true, + }; + + VkDeviceCreateInfo device_info = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .queueCreateInfoCount = qCount, + .pQueueCreateInfos = (VkDeviceQueueCreateInfo *)&pQueueInfos, + .pEnabledFeatures = &enabledFeatures}; + + VkhDevice dev = vkh_device_create(app, pi, &device_info); vkvg_device_create_info_t info = { - samples, - deferredResolve, - vkh_app_get_inst(e->app), - dev->phy, - dev->dev, - pi->gQueue, - 0 - }; + samples, deferredResolve, vkh_app_get_inst(e->app), dev->phy, dev->dev, pi->gQueue, 0}; device = vkvg_device_create(&info); - //vkvg_device_set_dpy(device, 96, 96); + // vkvg_device_set_dpy(device, 96, 96); - vkh_app_free_phyinfos (phyCount, phys); + vkh_app_free_phyinfos(phyCount, phys); - surf = vkvg_surface_create(device, test_width, test_height); + surf = vkvg_surface_create(device, test_width, test_height); - double start_time = 0.0, stop_time = 0.0, run_time = 0.0, run_total = 0.0, min_run_time = -1, max_run_time = 0.0; - double* run_time_values = (double*)malloc(iterations*sizeof(double)); + double start_time = 0.0, stop_time = 0.0, run_time = 0.0, run_total = 0.0, min_run_time = -1, max_run_time = 0.0; + double *run_time_values = (double *)malloc(iterations * sizeof(double)); - uint32_t i = 0; - while (i < iterations) { - start_time = get_tick(); + uint32_t i = 0; + while (i < iterations) { + start_time = get_tick(); - testfunc(); + testfunc(); - if (deferredResolve) - vkvg_surface_resolve(surf); + if (deferredResolve) + vkvg_surface_resolve(surf); - stop_time = get_tick(); - run_time = stop_time - start_time; - run_time_values[i] = run_time; + stop_time = get_tick(); + run_time = stop_time - start_time; + run_time_values[i] = run_time; - if (min_run_time < 0) - min_run_time = run_time; - else - min_run_time = MIN(run_time, min_run_time); - max_run_time = MAX(run_time, max_run_time); - run_total += run_time; - i++; - } + if (min_run_time < 0) + min_run_time = run_time; + else + min_run_time = MIN(run_time, min_run_time); + max_run_time = MAX(run_time, max_run_time); + run_total += run_time; + i++; + } - _print_results (testName, argc, argv, i, run_total, run_time_values); + _print_results(testName, argc, argv, i, run_total, run_time_values); - free (run_time_values); + free(run_time_values); - vkDeviceWaitIdle(dev->dev); + vkDeviceWaitIdle(dev->dev); - if (saveToPng) - vkvg_surface_write_to_png (surf, saveToPng); + if (saveToPng) + vkvg_surface_write_to_png(surf, saveToPng); - vkvg_surface_destroy (surf); - vkvg_device_destroy (device); + vkvg_surface_destroy(surf); + vkvg_device_destroy(device); - vkh_device_destroy (dev); - vkh_app_destroy (app); + vkh_device_destroy(dev); + vkh_app_destroy(app); - test_index++; + test_index++; } -void perform_test_onscreen (void(*testfunc)(void), const char *testName, int argc, char* argv[]) { - if (test_vsync) - e = vkengine_create (preferedPhysicalDeviceType, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); - else - e = vkengine_create (preferedPhysicalDeviceType, VK_PRESENT_MODE_MAILBOX_KHR, test_width, test_height); +void perform_test_onscreen(void (*testfunc)(void), const char *testName, int argc, char *argv[]) { + if (test_vsync) + e = vkengine_create(preferedPhysicalDeviceType, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); + else + e = vkengine_create(preferedPhysicalDeviceType, VK_PRESENT_MODE_MAILBOX_KHR, test_width, test_height); - VkhPresenter r = e->renderer; - vkengine_set_key_callback (e, key_callback); - vkengine_set_mouse_but_callback (e, mouse_button_callback); - vkengine_set_cursor_pos_callback (e, mouse_move_callback); - vkengine_set_scroll_callback (e, scroll_callback); + VkhPresenter r = e->renderer; + vkengine_set_key_callback(e, key_callback); + vkengine_set_mouse_but_callback(e, mouse_button_callback); + vkengine_set_cursor_pos_callback(e, mouse_move_callback); + vkengine_set_scroll_callback(e, scroll_callback); - vkvg_device_create_info_t info = { - samples, - false, - vkh_app_get_inst(e->app), - r->dev->phy, - r->dev->dev, - r->qFam, - 0 - }; - device = vkvg_device_create(&info); + vkvg_device_create_info_t info = {samples, false, vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0}; + device = vkvg_device_create(&info); - vkvg_device_set_dpy (device, 96, 96); - if (threadAware) - vkvg_device_set_thread_aware (device, 1); + vkvg_device_set_dpy(device, 96, 96); + if (threadAware) + vkvg_device_set_thread_aware(device, 1); #ifdef VKVG_TEST_DIRECT_DRAW - surfaces = (VkvgSurface*)malloc(r->imgCount * sizeof (VkvgSurface)); - for (uint32_t i=0; i < r->imgCount;i++) - surfaces[i] = vkvg_surface_create_for_VkhImage (device, r->ScBuffers[i]); + surfaces = (VkvgSurface *)malloc(r->imgCount * sizeof(VkvgSurface)); + for (uint32_t i = 0; i < r->imgCount; i++) + surfaces[i] = vkvg_surface_create_for_VkhImage(device, r->ScBuffers[i]); #else - surf = vkvg_surface_create (device, test_width, test_height); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); + surf = vkvg_surface_create(device, test_width, test_height); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); #endif - double start_time = 0.0, stop_time = 0.0, run_time = 0.0, run_total = 0.0, min_run_time = -1, max_run_time = 0.0; - double* run_time_values = (double*)malloc(iterations*sizeof(double)); + double start_time = 0.0, stop_time = 0.0, run_time = 0.0, run_total = 0.0, min_run_time = -1, max_run_time = 0.0; + double *run_time_values = (double *)malloc(iterations * sizeof(double)); - uint32_t i = 0; + uint32_t i = 0; - vkengine_set_title (e, testName); + vkengine_set_title(e, testName); - while (!vkengine_should_close (e) && i < iterations) { - glfwPollEvents(); + while (!vkengine_should_close(e) && i < iterations) { + glfwPollEvents(); - start_time = get_tick(); + start_time = get_tick(); #ifdef VKVG_TEST_DIRECT_DRAW - if (!vkh_presenter_acquireNextImage(r, NULL, NULL)) { - for (uint32_t i=0; i < r->imgCount;i++) - vkvg_surface_destroy (surfaces[i]); + if (!vkh_presenter_acquireNextImage(r, NULL, NULL)) { + for (uint32_t i = 0; i < r->imgCount; i++) + vkvg_surface_destroy(surfaces[i]); - vkh_presenter_create_swapchain (r); + vkh_presenter_create_swapchain(r); - for (uint32_t i=0; i < r->imgCount;i++) - surfaces[i] = vkvg_surface_create_for_VkhImage (device, r->ScBuffers[i]); - }else{ - surf = surfaces[r->currentScBufferIndex]; + for (uint32_t i = 0; i < r->imgCount; i++) + surfaces[i] = vkvg_surface_create_for_VkhImage(device, r->ScBuffers[i]); + } else { + surf = surfaces[r->currentScBufferIndex]; - testfunc(); + testfunc(); - if (deferredResolve) - vkvg_multisample_surface_resolve(surf); + if (deferredResolve) + vkvg_multisample_surface_resolve(surf); - VkPresentInfoKHR present = { .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - .swapchainCount = 1, - .pSwapchains = &r->swapChain, - .pImageIndices = &r->currentScBufferIndex }; + VkPresentInfoKHR present = {.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .swapchainCount = 1, + .pSwapchains = &r->swapChain, + .pImageIndices = &r->currentScBufferIndex}; - vkQueuePresentKHR(r->queue, &present); - } + vkQueuePresentKHR(r->queue, &present); + } #else - if (paused) - continue; + if (paused) + continue; - testfunc(); + testfunc(); if (info.deferredResolve) - vkvg_surface_resolve(surf); - if (!vkh_presenter_draw (r)){ - vkh_presenter_get_size (r, &test_width, &test_height); - vkvg_surface_destroy (surf); - surf = vkvg_surface_create(device, test_width, test_height); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); - vkDeviceWaitIdle(r->dev->dev); - continue; - } + vkvg_surface_resolve(surf); + if (!vkh_presenter_draw(r)) { + vkh_presenter_get_size(r, &test_width, &test_height); + vkvg_surface_destroy(surf); + surf = vkvg_surface_create(device, test_width, test_height); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); + vkDeviceWaitIdle(r->dev->dev); + continue; + } #endif - stop_time = get_tick(); - run_time = stop_time - start_time; - run_time_values[i] = run_time; + stop_time = get_tick(); + run_time = stop_time - start_time; + run_time_values[i] = run_time; - if (min_run_time < 0) - min_run_time = run_time; - else - min_run_time = MIN(run_time, min_run_time); - max_run_time = MAX(run_time, max_run_time); - run_total += run_time; - i++; - } + if (min_run_time < 0) + min_run_time = run_time; + else + min_run_time = MIN(run_time, min_run_time); + max_run_time = MAX(run_time, max_run_time); + run_total += run_time; + i++; + } - if (saveToPng) - vkvg_surface_write_to_png (surf, saveToPng); + if (saveToPng) + vkvg_surface_write_to_png(surf, saveToPng); - _print_results (testName, argc, argv, i, run_total, run_time_values); + _print_results(testName, argc, argv, i, run_total, run_time_values); - free (run_time_values); + free(run_time_values); - vkDeviceWaitIdle(e->dev->dev); + vkDeviceWaitIdle(e->dev->dev); #ifdef VKVG_TEST_DIRECT_DRAW - for (uint32_t i=0; iimgCount;i++) - vkvg_surface_destroy (surfaces[i]); + for (uint32_t i = 0; i < r->imgCount; i++) + vkvg_surface_destroy(surfaces[i]); - free (surfaces); + free(surfaces); #else - vkvg_surface_destroy (surf); + vkvg_surface_destroy(surf); #endif - - vkvg_device_destroy (device); - vkengine_destroy (e); - - test_index++; -} + vkvg_device_destroy(device); + vkengine_destroy(e); + + test_index++; +} /* common context init for several tests */ -vkvg_fill_rule_t fill_rule = VKVG_FILL_RULE_NON_ZERO; -vkvg_line_cap_t line_cap = VKVG_LINE_CAP_BUTT; -vkvg_line_join_t line_join = VKVG_LINE_JOIN_MITER; -float dashes[] = {10.0f, 6.0f}; -//float dashes[] = {0.0f, 10.0f}; -uint32_t dashes_count= 0; -float dash_offset = 0; -float line_width = 2.f; +vkvg_fill_rule_t fill_rule = VKVG_FILL_RULE_NON_ZERO; +vkvg_line_cap_t line_cap = VKVG_LINE_CAP_BUTT; +vkvg_line_join_t line_join = VKVG_LINE_JOIN_MITER; +float dashes[] = {10.0f, 6.0f}; +// float dashes[] = {0.0f, 10.0f}; +uint32_t dashes_count = 0; +float dash_offset = 0; +float line_width = 2.f; VkvgContext _initCtx() { - VkvgContext ctx = vkvg_create(surf); + VkvgContext ctx = vkvg_create(surf); - vkvg_set_line_width (ctx,line_width); - vkvg_set_line_join (ctx, line_join); - vkvg_set_line_cap (ctx, line_cap); - vkvg_set_dash (ctx, dashes, dashes_count, dash_offset); - vkvg_set_fill_rule (ctx, fill_rule); + vkvg_set_line_width(ctx, line_width); + vkvg_set_line_join(ctx, line_join); + vkvg_set_line_cap(ctx, line_cap); + vkvg_set_dash(ctx, dashes, dashes_count, dash_offset); + vkvg_set_fill_rule(ctx, fill_rule); - vkvg_clear (ctx); - return ctx; + vkvg_clear(ctx); + return ctx; } - - -const int star_points[11][2] = { - { 0, 85 }, - { 75, 75 }, - { 100, 10 }, - { 125, 75 }, - { 200, 85 }, - { 150, 125 }, - { 160, 190 }, - { 100, 150 }, - { 40, 190 }, - { 50, 125 }, - { 0, 85 } -}; -void randomize_color(VkvgContext ctx) { - vkvg_set_source_rgba(ctx, - rndf(), - rndf(), - rndf(), - rndf() - ); -} -void draw_random_shape (VkvgContext ctx, shape_t shape, float sizeFact) { - float w = (float)test_width; - float h = (float)test_height; - - float x, y, z, v, r; - - randomize_color (ctx); - - switch (shape) { - case SHAPE_LINE: - x = rndf() * w; - y = rndf() * h; - z = rndf() * w; - v = rndf() * h; - - vkvg_move_to(ctx, x, y); - vkvg_line_to(ctx, z, v); - vkvg_stroke(ctx); - break; - case SHAPE_RECTANGLE: - z = truncf((sizeFact*w*rndf())+1.f); - v = truncf((sizeFact*h*rndf())+1.f); - x = truncf((w-z)*rndf()); - y = truncf((h-v)*rndf()); - - vkvg_rectangle(ctx, x+1, y+1, z, v); - break; - case SHAPE_ROUNDED_RECTANGLE: - z = truncf((sizeFact*w*rndf())+1.f); - v = truncf((sizeFact*h*rndf())+1.f); - x = truncf((w-z)*rndf()); - y = truncf((h-v)*rndf()); - r = truncf((0.2f*z*rndf())+1.f); - - if ((r > v / 2) || (r > z / 2)) - r = MIN(v / 2, z / 2); - - vkvg_move_to(ctx, x, y + r); - vkvg_arc(ctx, x + r, y + r, r, (float)M_PI, (float)-M_PI_2); - vkvg_line_to(ctx, x + z - r, y); - vkvg_arc(ctx, x + z - r, y + r, r, (float)-M_PI_2, 0); - vkvg_line_to(ctx, x + z, y + v - r); - vkvg_arc(ctx, x + z - r, y + v - r, r, 0, (float)M_PI_2); - vkvg_line_to(ctx, x + r, y + v); - vkvg_arc(ctx, x + r, y + v - r, r, (float)M_PI_2, (float)M_PI); - vkvg_line_to(ctx, x, y + r); - vkvg_close_path(ctx); - break; - case SHAPE_CIRCLE: - /*x = truncf((float)w * rnd()/RAND_MAX); - y = truncf((float)h * rnd()/RAND_MAX); - v = truncf((float)w * rnd()/RAND_MAX * 0.2f);*/ - x = rndf() * w; - y = rndf() * h; - - r = truncf((sizeFact*MIN(w,h)*rndf())+1.f); - - /*float r = 0.5f*w*rand()/RAND_MAX; - float x = truncf(0.5f * w*rand()/RAND_MAX + r); - float y = truncf(0.5f * w*rand()/RAND_MAX + r);*/ - - vkvg_arc(ctx, x, y, r, 0, (float)M_PI * 2.0f); - break; - case SHAPE_TRIANGLE: - case SHAPE_STAR: - x = rndf() * w; - y = rndf() * h; - z = rndf() * sizeFact + 0.15f; //scale - - vkvg_move_to (ctx, x+star_points[0][0]*z, y+star_points[0][1]*z); - for (int s=1; s<11; s++) - vkvg_line_to (ctx, x+star_points[s][0]*z, y+star_points[s][1]*z); - vkvg_close_path (ctx); - break; - case SHAPE_RANDOM: - draw_random_shape(ctx, 1 + (rndf() * 4), sizeFact); - break; - } +const int star_points[11][2] = {{0, 85}, {75, 75}, {100, 10}, {125, 75}, {200, 85}, {150, 125}, + {160, 190}, {100, 150}, {40, 190}, {50, 125}, {0, 85}}; +void randomize_color(VkvgContext ctx) { vkvg_set_source_rgba(ctx, rndf(), rndf(), rndf(), rndf()); } +void draw_random_shape(VkvgContext ctx, shape_t shape, float sizeFact) { + float w = (float)test_width; + float h = (float)test_height; + + float x, y, z, v, r; + + randomize_color(ctx); + + switch (shape) { + case SHAPE_LINE: + x = rndf() * w; + y = rndf() * h; + z = rndf() * w; + v = rndf() * h; + + vkvg_move_to(ctx, x, y); + vkvg_line_to(ctx, z, v); + vkvg_stroke(ctx); + break; + case SHAPE_RECTANGLE: + z = truncf((sizeFact * w * rndf()) + 1.f); + v = truncf((sizeFact * h * rndf()) + 1.f); + x = truncf((w - z) * rndf()); + y = truncf((h - v) * rndf()); + + vkvg_rectangle(ctx, x + 1, y + 1, z, v); + break; + case SHAPE_ROUNDED_RECTANGLE: + z = truncf((sizeFact * w * rndf()) + 1.f); + v = truncf((sizeFact * h * rndf()) + 1.f); + x = truncf((w - z) * rndf()); + y = truncf((h - v) * rndf()); + r = truncf((0.2f * z * rndf()) + 1.f); + + if ((r > v / 2) || (r > z / 2)) + r = MIN(v / 2, z / 2); + + vkvg_move_to(ctx, x, y + r); + vkvg_arc(ctx, x + r, y + r, r, (float)M_PI, (float)-M_PI_2); + vkvg_line_to(ctx, x + z - r, y); + vkvg_arc(ctx, x + z - r, y + r, r, (float)-M_PI_2, 0); + vkvg_line_to(ctx, x + z, y + v - r); + vkvg_arc(ctx, x + z - r, y + v - r, r, 0, (float)M_PI_2); + vkvg_line_to(ctx, x + r, y + v); + vkvg_arc(ctx, x + r, y + v - r, r, (float)M_PI_2, (float)M_PI); + vkvg_line_to(ctx, x, y + r); + vkvg_close_path(ctx); + break; + case SHAPE_CIRCLE: + /*x = truncf((float)w * rnd()/RAND_MAX); + y = truncf((float)h * rnd()/RAND_MAX); + v = truncf((float)w * rnd()/RAND_MAX * 0.2f);*/ + x = rndf() * w; + y = rndf() * h; + + r = truncf((sizeFact * MIN(w, h) * rndf()) + 1.f); + + /*float r = 0.5f*w*rand()/RAND_MAX; + float x = truncf(0.5f * w*rand()/RAND_MAX + r); + float y = truncf(0.5f * w*rand()/RAND_MAX + r);*/ + + vkvg_arc(ctx, x, y, r, 0, (float)M_PI * 2.0f); + break; + case SHAPE_TRIANGLE: + case SHAPE_STAR: + x = rndf() * w; + y = rndf() * h; + z = rndf() * sizeFact + 0.15f; // scale + + vkvg_move_to(ctx, x + star_points[0][0] * z, y + star_points[0][1] * z); + for (int s = 1; s < 11; s++) + vkvg_line_to(ctx, x + star_points[s][0] * z, y + star_points[s][1] * z); + vkvg_close_path(ctx); + break; + case SHAPE_RANDOM: + draw_random_shape(ctx, 1 + (rndf() * 4), sizeFact); + break; + } } -void draw_random_curve (VkvgContext ctx) { - float w = (float)test_width; - float h = (float)test_height; - - float x2 = w*rndf(); - float y2 = h*rndf(); - float cp_x1 = w*rndf(); - float cp_y1 = h*rndf(); - float cp_x2 = w*rndf(); - float cp_y2 = h*rndf(); - - vkvg_curve_to(ctx, cp_x1, cp_y1, cp_x2, cp_y2, x2, y2); +void draw_random_curve(VkvgContext ctx) { + float w = (float)test_width; + float h = (float)test_height; + + float x2 = w * rndf(); + float y2 = h * rndf(); + float cp_x1 = w * rndf(); + float cp_y1 = h * rndf(); + float cp_x2 = w * rndf(); + float cp_y2 = h * rndf(); + + vkvg_curve_to(ctx, cp_x1, cp_y1, cp_x2, cp_y2, x2, y2); } /*void draw_random_shape (VkvgContext ctx, shape_t shape) { - float w = (float)test_width; - float h = (float)test_height; - randomize_color(ctx); - float z = truncf((0.5f*w*rand()/RAND_MAX)+1.f); - float v = truncf((0.5f*w*rand()/RAND_MAX)+1.f); - float x = truncf((w-z)*rand()/RAND_MAX); - float y = truncf((h-v)*rand()/RAND_MAX); - vkvg_rectangle(ctx, x, y, z, v); + float w = (float)test_width; + float h = (float)test_height; + randomize_color(ctx); + float z = truncf((0.5f*w*rand()/RAND_MAX)+1.f); + float v = truncf((0.5f*w*rand()/RAND_MAX)+1.f); + float x = truncf((w-z)*rand()/RAND_MAX); + float y = truncf((h-v)*rand()/RAND_MAX); + vkvg_rectangle(ctx, x, y, z, v); }*/ diff --git a/tests/common/test.h b/tests/common/test.h index d61858e..8079cec 100644 --- a/tests/common/test.h +++ b/tests/common/test.h @@ -12,113 +12,113 @@ #include "vkh_presenter.h" #include "vkh_phyinfo.h" -#define M_PIF 3.14159265359f /* float pi */ -#define M_PIF_MULT_2 6.28318530718f +#define M_PIF 3.14159265359f /* float pi */ +#define M_PIF_MULT_2 6.28318530718f #ifndef M_PI -# define M_PI 3.14159265358979323846 /* pi */ +#define M_PI 3.14159265358979323846 /* pi */ #endif #ifndef M_PI_2 -# define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ #endif #ifndef MIN -# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX -# define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif #define PERFORM_TEST(testName, argc, argv) perform_test(testName, #testName, argc, argv); #if defined(_WIN32) || defined(_WIN64) - #define WIN32_LEAN_AND_MEAN - #define NOMINMAX - #include // Windows.h -> WinDef.h defines min() max() - - /* - typedef uint16_t WORD ; - typedef uint32_t DWORD; - - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME; - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME, *PSYSTEMTIME; - */ - - // *sigh* Microsoft has this in winsock2.h because they are too lazy to put it in the standard location ... !?!? +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include // Windows.h -> WinDef.h defines min() max() + +/* + typedef uint16_t WORD ; + typedef uint32_t DWORD; + + typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; + } FILETIME; + + typedef struct _SYSTEMTIME { + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; + } SYSTEMTIME, *PSYSTEMTIME; +*/ + +// *sigh* Microsoft has this in winsock2.h because they are too lazy to put it in the standard location ... !?!? #ifdef _MSC_VER - typedef struct timeval { - long tv_sec; - long tv_usec; - } timeval; +typedef struct timeval { + long tv_sec; + long tv_usec; +} timeval; #endif - // *sigh* no gettimeofday on Win32/Win64 - int gettimeofday(struct timeval * tp, void * tzp); +// *sigh* no gettimeofday on Win32/Win64 +int gettimeofday(struct timeval *tp, void *tzp); #else - #include +#include #endif typedef enum _shape_t { - SHAPE_LINE, - SHAPE_RECTANGLE, - SHAPE_ROUNDED_RECTANGLE, - SHAPE_CIRCLE, - SHAPE_TRIANGLE, - SHAPE_STAR, - SHAPE_RANDOM, + SHAPE_LINE, + SHAPE_RECTANGLE, + SHAPE_ROUNDED_RECTANGLE, + SHAPE_CIRCLE, + SHAPE_TRIANGLE, + SHAPE_STAR, + SHAPE_RANDOM, } shape_t; extern uint32_t test_size; extern uint32_t iterations; extern uint32_t test_width; extern uint32_t test_height; -extern bool no_test_size; +extern bool no_test_size; extern float panX; extern float panY; extern float lastX; extern float lastY; extern float zoom; -extern bool mouseDown; +extern bool mouseDown; -extern VkvgDevice device; +extern VkvgDevice device; extern VkvgSurface surf; /* common context init for several tests */ -extern float dash_offset; -extern float line_width; +extern float dash_offset; +extern float line_width; extern vkvg_fill_rule_t fill_rule; -extern vkvg_line_cap_t line_cap; +extern vkvg_line_cap_t line_cap; extern vkvg_line_join_t line_join; -extern float dashes[]; -extern uint32_t dashes_count; +extern float dashes[]; +extern uint32_t dashes_count; VkvgContext _initCtx(); -void _parse_args (int argc, char* argv[]); +void _parse_args(int argc, char *argv[]); /*******************************/ -//run test in one step -void perform_test (void(*testfunc)(), const char* testName, int argc, char *argv[]); -void perform_test_onscreen (void(*testfunc)(void), const char *testName, int argc, char* argv[]); -void perform_test_offscreen (void(*testfunc)(void), const char *testName, int argc, char* argv[]); +// run test in one step +void perform_test(void (*testfunc)(), const char *testName, int argc, char *argv[]); +void perform_test_onscreen(void (*testfunc)(void), const char *testName, int argc, char *argv[]); +void perform_test_offscreen(void (*testfunc)(void), const char *testName, int argc, char *argv[]); -void randomize_color (VkvgContext ctx); -void draw_random_shape (VkvgContext ctx, shape_t shape, float sizeFact); -void draw_random_curve (VkvgContext ctx); +void randomize_color(VkvgContext ctx); +void draw_random_shape(VkvgContext ctx, shape_t shape, float sizeFact); +void draw_random_curve(VkvgContext ctx); -//run test in 3 step: init, run, clear. -void init_test (uint32_t width, uint32_t height); -void clear_test (); +// run test in 3 step: init, run, clear. +void init_test(uint32_t width, uint32_t height); +void clear_test(); diff --git a/tests/common/tinycthread.c b/tests/common/tinycthread.c index f9cea2e..5dcf01f 100644 --- a/tests/common/tinycthread.c +++ b/tests/common/tinycthread.c @@ -32,103 +32,96 @@ freely, subject to the following restrictions: /* Platform specific includes */ #if defined(_TTHREAD_POSIX_) - #include - #include - #include - #include - #include +#include +#include +#include +#include +#include #elif defined(_TTHREAD_WIN32_) - #include - #include +#include +#include #endif /* Standard, good-to-have defines */ #ifndef NULL - #define NULL (void*)0 +#define NULL (void *)0 #endif #ifndef TRUE - #define TRUE 1 +#define TRUE 1 #endif #ifndef FALSE - #define FALSE 0 +#define FALSE 0 #endif -int mtx_init(mtx_t *mtx, int type) -{ +int mtx_init(mtx_t *mtx, int type) { #if defined(_TTHREAD_WIN32_) - mtx->mAlreadyLocked = FALSE; - mtx->mRecursive = type & mtx_recursive; - InitializeCriticalSection(&mtx->mHandle); - return thrd_success; + mtx->mAlreadyLocked = FALSE; + mtx->mRecursive = type & mtx_recursive; + InitializeCriticalSection(&mtx->mHandle); + return thrd_success; #else - int ret; - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - if (type & mtx_recursive) - { - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - } - ret = pthread_mutex_init(mtx, &attr); - pthread_mutexattr_destroy(&attr); - return ret == 0 ? thrd_success : thrd_error; + int ret; + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + if (type & mtx_recursive) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + ret = pthread_mutex_init(mtx, &attr); + pthread_mutexattr_destroy(&attr); + return ret == 0 ? thrd_success : thrd_error; #endif } -void mtx_destroy(mtx_t *mtx) -{ +void mtx_destroy(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mtx->mHandle); + DeleteCriticalSection(&mtx->mHandle); #else - pthread_mutex_destroy(mtx); + pthread_mutex_destroy(mtx); #endif } -int mtx_lock(mtx_t *mtx) -{ +int mtx_lock(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mtx->mHandle); - if (!mtx->mRecursive) - { - while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */ - mtx->mAlreadyLocked = TRUE; - } - return thrd_success; + EnterCriticalSection(&mtx->mHandle); + if (!mtx->mRecursive) { + while (mtx->mAlreadyLocked) + Sleep(1000); /* Simulate deadlock... */ + mtx->mAlreadyLocked = TRUE; + } + return thrd_success; #else - return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; + return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; #endif } -int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) -{ - /* FIXME! */ - (void)mtx; - (void)ts; - return thrd_error; +int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) { + /* FIXME! */ + (void)mtx; + (void)ts; + return thrd_error; } -int mtx_trylock(mtx_t *mtx) -{ +int mtx_trylock(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; - if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) - { - LeaveCriticalSection(&mtx->mHandle); - ret = thrd_busy; - } - return ret; + int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; + if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) { + LeaveCriticalSection(&mtx->mHandle); + ret = thrd_busy; + } + return ret; #else - return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; + return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; #endif } -int mtx_unlock(mtx_t *mtx) -{ +int mtx_unlock(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - mtx->mAlreadyLocked = FALSE; - LeaveCriticalSection(&mtx->mHandle); - return thrd_success; + mtx->mAlreadyLocked = FALSE; + LeaveCriticalSection(&mtx->mHandle); + return thrd_success; #else - return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;; + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; + ; #endif } @@ -137,458 +130,397 @@ int mtx_unlock(mtx_t *mtx) #define _CONDITION_EVENT_ALL 1 #endif -int cnd_init(cnd_t *cond) -{ +int cnd_init(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - cond->mWaitersCount = 0; + cond->mWaitersCount = 0; - /* Init critical section */ - InitializeCriticalSection(&cond->mWaitersCountLock); + /* Init critical section */ + InitializeCriticalSection(&cond->mWaitersCountLock); - /* Init events */ - cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); - if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) - { - cond->mEvents[_CONDITION_EVENT_ALL] = NULL; - return thrd_error; - } - cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); - if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); - cond->mEvents[_CONDITION_EVENT_ONE] = NULL; - return thrd_error; - } + /* Init events */ + cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) { + cond->mEvents[_CONDITION_EVENT_ALL] = NULL; + return thrd_error; + } + cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + cond->mEvents[_CONDITION_EVENT_ONE] = NULL; + return thrd_error; + } - return thrd_success; + return thrd_success; #else - return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; + return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; #endif } -void cnd_destroy(cnd_t *cond) -{ +void cnd_destroy(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); - } - if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); - } - DeleteCriticalSection(&cond->mWaitersCountLock); + if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + } + if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); + } + DeleteCriticalSection(&cond->mWaitersCountLock); #else - pthread_cond_destroy(cond); + pthread_cond_destroy(cond); #endif } -int cnd_signal(cnd_t *cond) -{ +int cnd_signal(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - int haveWaiters; - - /* Are there any waiters? */ - EnterCriticalSection(&cond->mWaitersCountLock); - haveWaiters = (cond->mWaitersCount > 0); - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* If we have any waiting threads, send them a signal */ - if(haveWaiters) - { - if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) - { - return thrd_error; + int haveWaiters; + + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we have any waiting threads, send them a signal */ + if (haveWaiters) { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) { + return thrd_error; + } } - } - return thrd_success; + return thrd_success; #else - return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; #endif } -int cnd_broadcast(cnd_t *cond) -{ +int cnd_broadcast(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - int haveWaiters; - - /* Are there any waiters? */ - EnterCriticalSection(&cond->mWaitersCountLock); - haveWaiters = (cond->mWaitersCount > 0); - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* If we have any waiting threads, send them a signal */ - if(haveWaiters) - { - if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) - { - return thrd_error; + int haveWaiters; + + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we have any waiting threads, send them a signal */ + if (haveWaiters) { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) { + return thrd_error; + } } - } - return thrd_success; + return thrd_success; #else - return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; #endif } #if defined(_TTHREAD_WIN32_) -static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) -{ - int result, lastWaiter; - - /* Increment number of waiters */ - EnterCriticalSection(&cond->mWaitersCountLock); - ++ cond->mWaitersCount; - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* Release the mutex while waiting for the condition (will decrease - the number of waiters when done)... */ - mtx_unlock(mtx); - - /* Wait for either event to become signaled due to cnd_signal() or - cnd_broadcast() being called */ - result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); - if (result == WAIT_TIMEOUT) - { - return thrd_timeout; - } - else if (result == (int)WAIT_FAILED) - { - return thrd_error; - } - - /* Check if we are the last waiter */ - EnterCriticalSection(&cond->mWaitersCountLock); - -- cond->mWaitersCount; - lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && - (cond->mWaitersCount == 0); - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* If we are the last waiter to be notified to stop waiting, reset the event */ - if (lastWaiter) - { - if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) - { - return thrd_error; +static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) { + int result, lastWaiter; + + /* Increment number of waiters */ + EnterCriticalSection(&cond->mWaitersCountLock); + ++cond->mWaitersCount; + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* Release the mutex while waiting for the condition (will decrease + the number of waiters when done)... */ + mtx_unlock(mtx); + + /* Wait for either event to become signaled due to cnd_signal() or + cnd_broadcast() being called */ + result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); + if (result == WAIT_TIMEOUT) { + return thrd_timeout; + } else if (result == (int)WAIT_FAILED) { + return thrd_error; + } + + /* Check if we are the last waiter */ + EnterCriticalSection(&cond->mWaitersCountLock); + --cond->mWaitersCount; + lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && (cond->mWaitersCount == 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we are the last waiter to be notified to stop waiting, reset the event */ + if (lastWaiter) { + if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) { + return thrd_error; + } } - } - /* Re-acquire the mutex */ - mtx_lock(mtx); + /* Re-acquire the mutex */ + mtx_lock(mtx); - return thrd_success; + return thrd_success; } #endif -int cnd_wait(cnd_t *cond, mtx_t *mtx) -{ +int cnd_wait(cnd_t *cond, mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - return _cnd_timedwait_win32(cond, mtx, INFINITE); + return _cnd_timedwait_win32(cond, mtx, INFINITE); #else - return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; #endif } -int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) -{ +int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) { #if defined(_TTHREAD_WIN32_) - struct timespec now; - if (clock_gettime(CLOCK_REALTIME, &now) == 0) - { - DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 + - (ts->tv_nsec - now.tv_nsec + 500000) / 1000000); - return _cnd_timedwait_win32(cond, mtx, delta); - } - else - return thrd_error; + struct timespec now; + if (clock_gettime(CLOCK_REALTIME, &now) == 0) { + DWORD delta = (DWORD)((ts->tv_sec - now.tv_sec) * 1000 + (ts->tv_nsec - now.tv_nsec + 500000) / 1000000); + return _cnd_timedwait_win32(cond, mtx, delta); + } else + return thrd_error; #else - int ret; - ret = pthread_cond_timedwait(cond, mtx, ts); - if (ret == ETIMEDOUT) - { - return thrd_timeout; - } - return ret == 0 ? thrd_success : thrd_error; + int ret; + ret = pthread_cond_timedwait(cond, mtx, ts); + if (ret == ETIMEDOUT) { + return thrd_timeout; + } + return ret == 0 ? thrd_success : thrd_error; #endif } - /** Information to pass to the new thread (what to run). */ typedef struct { - thrd_start_t mFunction; /**< Pointer to the function to be executed. */ - void * mArg; /**< Function argument for the thread function. */ + thrd_start_t mFunction; /**< Pointer to the function to be executed. */ + void *mArg; /**< Function argument for the thread function. */ } _thread_start_info; /* Thread wrapper function. */ #if defined(_TTHREAD_WIN32_) -static unsigned WINAPI _thrd_wrapper_function(void * aArg) +static unsigned WINAPI _thrd_wrapper_function(void *aArg) #elif defined(_TTHREAD_POSIX_) -static void * _thrd_wrapper_function(void * aArg) +static void *_thrd_wrapper_function(void *aArg) #endif { - thrd_start_t fun; - void *arg; - int res; + thrd_start_t fun; + void *arg; + int res; #if defined(_TTHREAD_POSIX_) - void *pres; + void *pres; #endif - /* Get thread startup information */ - _thread_start_info *ti = (_thread_start_info *) aArg; - fun = ti->mFunction; - arg = ti->mArg; + /* Get thread startup information */ + _thread_start_info *ti = (_thread_start_info *)aArg; + fun = ti->mFunction; + arg = ti->mArg; - /* The thread is responsible for freeing the startup information */ - free((void *)ti); + /* The thread is responsible for freeing the startup information */ + free((void *)ti); - /* Call the actual client thread function */ - res = fun(arg); + /* Call the actual client thread function */ + res = fun(arg); #if defined(_TTHREAD_WIN32_) - return res; + return res; #else - pres = malloc(sizeof(int)); - if (pres != NULL) - { - *(int*)pres = res; - } - return pres; + pres = malloc(sizeof(int)); + if (pres != NULL) { + *(int *)pres = res; + } + return pres; #endif } -int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) -{ - /* Fill out the thread startup information (passed to the thread wrapper, - which will eventually free it) */ - _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info)); - if (ti == NULL) - { - return thrd_nomem; - } - ti->mFunction = func; - ti->mArg = arg; - - /* Create the thread */ +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { + /* Fill out the thread startup information (passed to the thread wrapper, + which will eventually free it) */ + _thread_start_info *ti = (_thread_start_info *)malloc(sizeof(_thread_start_info)); + if (ti == NULL) { + return thrd_nomem; + } + ti->mFunction = func; + ti->mArg = arg; + + /* Create the thread */ #if defined(_TTHREAD_WIN32_) - *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); + *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); #elif defined(_TTHREAD_POSIX_) - if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) - { - *thr = 0; - } + if (pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) { + *thr = 0; + } #endif - /* Did we fail to create the thread? */ - if(!*thr) - { - free(ti); - return thrd_error; - } + /* Did we fail to create the thread? */ + if (!*thr) { + free(ti); + return thrd_error; + } - return thrd_success; + return thrd_success; } -thrd_t thrd_current(void) -{ +thrd_t thrd_current(void) { #if defined(_TTHREAD_WIN32_) - return GetCurrentThread(); + return GetCurrentThread(); #else - return pthread_self(); + return pthread_self(); #endif } -int thrd_detach(thrd_t thr) -{ - /* FIXME! */ - (void)thr; - return thrd_error; +int thrd_detach(thrd_t thr) { + /* FIXME! */ + (void)thr; + return thrd_error; } -int thrd_equal(thrd_t thr0, thrd_t thr1) -{ +int thrd_equal(thrd_t thr0, thrd_t thr1) { #if defined(_TTHREAD_WIN32_) - return thr0 == thr1; + return thr0 == thr1; #else - return pthread_equal(thr0, thr1); + return pthread_equal(thr0, thr1); #endif } -void thrd_exit(int res) -{ +void thrd_exit(int res) { #if defined(_TTHREAD_WIN32_) - ExitThread(res); + ExitThread(res); #else - void *pres = malloc(sizeof(int)); - if (pres != NULL) - { - *(int*)pres = res; - } - pthread_exit(pres); + void *pres = malloc(sizeof(int)); + if (pres != NULL) { + *(int *)pres = res; + } + pthread_exit(pres); #endif } -int thrd_join(thrd_t thr, int *res) -{ +int thrd_join(thrd_t thr, int *res) { #if defined(_TTHREAD_WIN32_) - if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) - { - return thrd_error; - } - if (res != NULL) - { - DWORD dwRes; - GetExitCodeThread(thr, &dwRes); - *res = dwRes; - } + if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) { + return thrd_error; + } + if (res != NULL) { + DWORD dwRes; + GetExitCodeThread(thr, &dwRes); + *res = dwRes; + } #elif defined(_TTHREAD_POSIX_) - void *pres; - int ires = 0; - if (pthread_join(thr, &pres) != 0) - { - return thrd_error; - } - if (pres != NULL) - { - ires = *(int*)pres; - free(pres); - } - if (res != NULL) - { - *res = ires; - } -#endif - return thrd_success; + void *pres; + int ires = 0; + if (pthread_join(thr, &pres) != 0) { + return thrd_error; + } + if (pres != NULL) { + ires = *(int *)pres; + free(pres); + } + if (res != NULL) { + *res = ires; + } +#endif + return thrd_success; } -int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) -{ - struct timespec now; +int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) { + struct timespec now; #if defined(_TTHREAD_WIN32_) - DWORD delta; + DWORD delta; #else - long delta; + long delta; #endif - /* Get the current time */ - if (clock_gettime(CLOCK_REALTIME, &now) != 0) - return -2; // FIXME: Some specific error code? + /* Get the current time */ + if (clock_gettime(CLOCK_REALTIME, &now) != 0) + return -2; // FIXME: Some specific error code? #if defined(_TTHREAD_WIN32_) - /* Delta in milliseconds */ - delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 + - (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); - if (delta > 0) - { - Sleep(delta); - } + /* Delta in milliseconds */ + delta = (DWORD)((time_point->tv_sec - now.tv_sec) * 1000 + (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); + if (delta > 0) { + Sleep(delta); + } #else - /* Delta in microseconds */ - delta = (time_point->tv_sec - now.tv_sec) * 1000000L + - (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; - - /* On some systems, the usleep argument must be < 1000000 */ - while (delta > 999999L) - { - usleep(999999); - delta -= 999999L; - } - if (delta > 0L) - { - usleep((useconds_t)delta); - } -#endif - - /* We don't support waking up prematurely (yet) */ - if (remaining) - { - remaining->tv_sec = 0; - remaining->tv_nsec = 0; - } - return 0; + /* Delta in microseconds */ + delta = (time_point->tv_sec - now.tv_sec) * 1000000L + (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; + + /* On some systems, the usleep argument must be < 1000000 */ + while (delta > 999999L) { + usleep(999999); + delta -= 999999L; + } + if (delta > 0L) { + usleep((useconds_t)delta); + } +#endif + + /* We don't support waking up prematurely (yet) */ + if (remaining) { + remaining->tv_sec = 0; + remaining->tv_nsec = 0; + } + return 0; } -void thrd_yield(void) -{ +void thrd_yield(void) { #if defined(_TTHREAD_WIN32_) - Sleep(0); + Sleep(0); #else - sched_yield(); + sched_yield(); #endif } -int tss_create(tss_t *key, tss_dtor_t dtor) -{ +int tss_create(tss_t *key, tss_dtor_t dtor) { #if defined(_TTHREAD_WIN32_) - /* FIXME: The destructor function is not supported yet... */ - if (dtor != NULL) - { - return thrd_error; - } - *key = TlsAlloc(); - if (*key == TLS_OUT_OF_INDEXES) - { - return thrd_error; - } + /* FIXME: The destructor function is not supported yet... */ + if (dtor != NULL) { + return thrd_error; + } + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) { + return thrd_error; + } #else - if (pthread_key_create(key, dtor) != 0) - { - return thrd_error; - } + if (pthread_key_create(key, dtor) != 0) { + return thrd_error; + } #endif - return thrd_success; + return thrd_success; } -void tss_delete(tss_t key) -{ +void tss_delete(tss_t key) { #if defined(_TTHREAD_WIN32_) - TlsFree(key); + TlsFree(key); #else - pthread_key_delete(key); + pthread_key_delete(key); #endif } -void *tss_get(tss_t key) -{ +void *tss_get(tss_t key) { #if defined(_TTHREAD_WIN32_) - return TlsGetValue(key); + return TlsGetValue(key); #else - return pthread_getspecific(key); + return pthread_getspecific(key); #endif } -int tss_set(tss_t key, void *val) -{ +int tss_set(tss_t key, void *val) { #if defined(_TTHREAD_WIN32_) - if (TlsSetValue(key, val) == 0) - { - return thrd_error; - } + if (TlsSetValue(key, val) == 0) { + return thrd_error; + } #else - if (pthread_setspecific(key, val) != 0) - { - return thrd_error; - } + if (pthread_setspecific(key, val) != 0) { + return thrd_error; + } #endif - return thrd_success; + return thrd_success; } #if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_) -int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) -{ +int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) { #if defined(_TTHREAD_WIN32_) - struct _timeb tb; - _ftime(&tb); - ts->tv_sec = (time_t)tb.time; - ts->tv_nsec = 1000000L * (long)tb.millitm; + struct _timeb tb; + _ftime(&tb); + ts->tv_sec = (time_t)tb.time; + ts->tv_nsec = 1000000L * (long)tb.millitm; #else - struct timeval tv; - gettimeofday(&tv, NULL); - ts->tv_sec = (time_t)tv.tv_sec; - ts->tv_nsec = 1000L * (long)tv.tv_usec; + struct timeval tv; + gettimeofday(&tv, NULL); + ts->tv_sec = (time_t)tv.tv_sec; + ts->tv_nsec = 1000L * (long)tv.tv_usec; #endif - return 0; + return 0; } #endif // _TTHREAD_EMULATE_CLOCK_GETTIME_ - diff --git a/tests/common/tinycthread.h b/tests/common/tinycthread.h index 42958c3..eaacfbe 100644 --- a/tests/common/tinycthread.h +++ b/tests/common/tinycthread.h @@ -25,52 +25,52 @@ freely, subject to the following restrictions: #define _TINYCTHREAD_H_ /** -* @file -* @mainpage TinyCThread API Reference -* -* @section intro_sec Introduction -* TinyCThread is a minimal, portable implementation of basic threading -* classes for C. -* -* They closely mimic the functionality and naming of the C11 standard, and -* should be easily replaceable with the corresponding standard variants. -* -* @section port_sec Portability -* The Win32 variant uses the native Win32 API for implementing the thread -* classes, while for other systems, the POSIX threads API (pthread) is used. -* -* @section misc_sec Miscellaneous -* The following special keywords are available: #_Thread_local. -* -* For more detailed information, browse the different sections of this -* documentation. A good place to start is: -* tinycthread.h. -*/ + * @file + * @mainpage TinyCThread API Reference + * + * @section intro_sec Introduction + * TinyCThread is a minimal, portable implementation of basic threading + * classes for C. + * + * They closely mimic the functionality and naming of the C11 standard, and + * should be easily replaceable with the corresponding standard variants. + * + * @section port_sec Portability + * The Win32 variant uses the native Win32 API for implementing the thread + * classes, while for other systems, the POSIX threads API (pthread) is used. + * + * @section misc_sec Miscellaneous + * The following special keywords are available: #_Thread_local. + * + * For more detailed information, browse the different sections of this + * documentation. A good place to start is: + * tinycthread.h. + */ /* Which platform are we on? */ #if !defined(_TTHREAD_PLATFORM_DEFINED_) - #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) - #define _TTHREAD_WIN32_ - #else - #define _TTHREAD_POSIX_ - #endif - #define _TTHREAD_PLATFORM_DEFINED_ +#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) +#define _TTHREAD_WIN32_ +#else +#define _TTHREAD_POSIX_ +#endif +#define _TTHREAD_PLATFORM_DEFINED_ #endif /* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ #if defined(_TTHREAD_POSIX_) - #undef _FEATURES_H - #if !defined(_GNU_SOURCE) - #define _GNU_SOURCE - #endif - #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) - #undef _POSIX_C_SOURCE - #define _POSIX_C_SOURCE 199309L - #endif - #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) - #undef _XOPEN_SOURCE - #define _XOPEN_SOURCE 500 - #endif +#undef _FEATURES_H +#if !defined(_GNU_SOURCE) +#define _GNU_SOURCE +#endif +#if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 199309L +#endif +#if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) +#undef _XOPEN_SOURCE +#define _XOPEN_SOURCE 500 +#endif #endif /* Generic includes */ @@ -78,18 +78,18 @@ freely, subject to the following restrictions: /* Platform specific includes */ #if defined(_TTHREAD_POSIX_) - #include - #include +#include +#include #elif defined(_TTHREAD_WIN32_) - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #define __UNDEF_LEAN_AND_MEAN - #endif - #include - #ifdef __UNDEF_LEAN_AND_MEAN - #undef WIN32_LEAN_AND_MEAN - #undef __UNDEF_LEAN_AND_MEAN - #endif +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#define __UNDEF_LEAN_AND_MEAN +#endif +#include +#ifdef __UNDEF_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#undef __UNDEF_LEAN_AND_MEAN +#endif #endif /* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, @@ -97,11 +97,11 @@ freely, subject to the following restrictions: the only other supported time specifier: CLOCK_REALTIME (and if that fails, we're probably emulating clock_gettime anyway, so anything goes). */ #ifndef TIME_UTC - #ifdef CLOCK_REALTIME - #define TIME_UTC CLOCK_REALTIME - #else - #define TIME_UTC 0 - #endif +#ifdef CLOCK_REALTIME +#define TIME_UTC CLOCK_REALTIME +#else +#define TIME_UTC 0 +#endif #endif /* Workaround for missing clock_gettime (most Windows compilers, afaik) */ @@ -110,8 +110,8 @@ freely, subject to the following restrictions: /* Emulate struct timespec */ #if defined(_TTHREAD_WIN32_) struct _ttherad_timespec { - time_t tv_sec; - long tv_nsec; + time_t tv_sec; + long tv_nsec; }; #define timespec _ttherad_timespec #endif @@ -124,11 +124,10 @@ typedef int _tthread_clockid_t; int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); #define clock_gettime _tthread_clock_gettime #ifndef CLOCK_REALTIME - #define CLOCK_REALTIME 0 +#define CLOCK_REALTIME 0 #endif #endif - /** TinyCThread version (major number). */ #define TINYCTHREAD_VERSION_MAJOR 1 /** TinyCThread version (minor number). */ @@ -137,42 +136,44 @@ int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); #define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) /** -* @def _Thread_local -* Thread local storage keyword. -* A variable that is declared with the @c _Thread_local keyword makes the -* value of the variable local to each thread (known as thread-local storage, -* or TLS). Example usage: -* @code -* // This variable is local to each thread. -* _Thread_local int variable; -* @endcode -* @note The @c _Thread_local keyword is a macro that maps to the corresponding -* compiler directive (e.g. @c __declspec(thread)). -* @note This directive is currently not supported on Mac OS X (it will give -* a compiler error), since compile-time TLS is not supported in the Mac OS X -* executable format. Also, some older versions of MinGW (before GCC 4.x) do -* not support this directive. -* @hideinitializer -*/ + * @def _Thread_local + * Thread local storage keyword. + * A variable that is declared with the @c _Thread_local keyword makes the + * value of the variable local to each thread (known as thread-local storage, + * or TLS). Example usage: + * @code + * // This variable is local to each thread. + * _Thread_local int variable; + * @endcode + * @note The @c _Thread_local keyword is a macro that maps to the corresponding + * compiler directive (e.g. @c __declspec(thread)). + * @note This directive is currently not supported on Mac OS X (it will give + * a compiler error), since compile-time TLS is not supported in the Mac OS X + * executable format. Also, some older versions of MinGW (before GCC 4.x) do + * not support this directive. + * @hideinitializer + */ /* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) - #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) - #define _Thread_local __thread - #else - #define _Thread_local __declspec(thread) - #endif +#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) +#define _Thread_local __thread +#else +#define _Thread_local __declspec(thread) +#endif #endif /* Macros */ #define TSS_DTOR_ITERATIONS 0 /* Function return values */ -#define thrd_error 0 /**< The requested operation failed */ -#define thrd_success 1 /**< The requested operation succeeded */ -#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ -#define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ -#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ +#define thrd_error 0 /**< The requested operation failed */ +#define thrd_success 1 /**< The requested operation succeeded */ +#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ +#define thrd_busy \ + 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use \ + */ +#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ /* Mutex types */ #define mtx_plain 1 @@ -183,261 +184,259 @@ int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); /* Mutex */ #if defined(_TTHREAD_WIN32_) typedef struct { - CRITICAL_SECTION mHandle; /* Critical section handle */ - int mAlreadyLocked; /* TRUE if the mutex is already locked */ - int mRecursive; /* TRUE if the mutex is recursive */ + CRITICAL_SECTION mHandle; /* Critical section handle */ + int mAlreadyLocked; /* TRUE if the mutex is already locked */ + int mRecursive; /* TRUE if the mutex is recursive */ } mtx_t; #else typedef pthread_mutex_t mtx_t; #endif /** Create a mutex object. -* @param mtx A mutex object. -* @param type Bit-mask that must have one of the following six values: -* @li @c mtx_plain for a simple non-recursive mutex -* @li @c mtx_timed for a non-recursive mutex that supports timeout -* @li @c mtx_try for a non-recursive mutex that supports test and return -* @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) -* @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) -* @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param mtx A mutex object. + * @param type Bit-mask that must have one of the following six values: + * @li @c mtx_plain for a simple non-recursive mutex + * @li @c mtx_timed for a non-recursive mutex that supports timeout + * @li @c mtx_try for a non-recursive mutex that supports test and return + * @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) + * @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) + * @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int mtx_init(mtx_t *mtx, int type); /** Release any resources used by the given mutex. -* @param mtx A mutex object. -*/ + * @param mtx A mutex object. + */ void mtx_destroy(mtx_t *mtx); /** Lock the given mutex. -* Blocks until the given mutex can be locked. If the mutex is non-recursive, and -* the calling thread already has a lock on the mutex, this call will block -* forever. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * Blocks until the given mutex can be locked. If the mutex is non-recursive, and + * the calling thread already has a lock on the mutex, this call will block + * forever. + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int mtx_lock(mtx_t *mtx); /** NOT YET IMPLEMENTED. -*/ + */ int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); /** Try to lock the given mutex. -* The specified mutex shall support either test and return or timeout. If the -* mutex is already locked, the function returns without blocking. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_busy if the resource -* requested is already in use, or @ref thrd_error if the request could not be -* honored. -*/ + * The specified mutex shall support either test and return or timeout. If the + * mutex is already locked, the function returns without blocking. + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_busy if the resource + * requested is already in use, or @ref thrd_error if the request could not be + * honored. + */ int mtx_trylock(mtx_t *mtx); /** Unlock the given mutex. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int mtx_unlock(mtx_t *mtx); /* Condition variable */ #if defined(_TTHREAD_WIN32_) typedef struct { - HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ - unsigned int mWaitersCount; /* Count of the number of waiters. */ - CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ + HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ + unsigned int mWaitersCount; /* Count of the number of waiters. */ + CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ } cnd_t; #else -typedef pthread_cond_t cnd_t; +typedef pthread_cond_t cnd_t; #endif /** Create a condition variable object. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param cond A condition variable object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_init(cnd_t *cond); /** Release any resources used by the given condition variable. -* @param cond A condition variable object. -*/ + * @param cond A condition variable object. + */ void cnd_destroy(cnd_t *cond); /** Signal a condition variable. -* Unblocks one of the threads that are blocked on the given condition variable -* at the time of the call. If no threads are blocked on the condition variable -* at the time of the call, the function does nothing and return success. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * Unblocks one of the threads that are blocked on the given condition variable + * at the time of the call. If no threads are blocked on the condition variable + * at the time of the call, the function does nothing and return success. + * @param cond A condition variable object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_signal(cnd_t *cond); /** Broadcast a condition variable. -* Unblocks all of the threads that are blocked on the given condition variable -* at the time of the call. If no threads are blocked on the condition variable -* at the time of the call, the function does nothing and return success. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * Unblocks all of the threads that are blocked on the given condition variable + * at the time of the call. If no threads are blocked on the condition variable + * at the time of the call, the function does nothing and return success. + * @param cond A condition variable object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_broadcast(cnd_t *cond); /** Wait for a condition variable to become signaled. -* The function atomically unlocks the given mutex and endeavors to block until -* the given condition variable is signaled by a call to cnd_signal or to -* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex -* before it returns. -* @param cond A condition variable object. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * The function atomically unlocks the given mutex and endeavors to block until + * the given condition variable is signaled by a call to cnd_signal or to + * cnd_broadcast. When the calling thread becomes unblocked it locks the mutex + * before it returns. + * @param cond A condition variable object. + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_wait(cnd_t *cond, mtx_t *mtx); /** Wait for a condition variable to become signaled. -* The function atomically unlocks the given mutex and endeavors to block until -* the given condition variable is signaled by a call to cnd_signal or to -* cnd_broadcast, or until after the specified time. When the calling thread -* becomes unblocked it locks the mutex before it returns. -* @param cond A condition variable object. -* @param mtx A mutex object. -* @param xt A point in time at which the request will time out (absolute time). -* @return @ref thrd_success upon success, or @ref thrd_timeout if the time -* specified in the call was reached without acquiring the requested resource, or -* @ref thrd_error if the request could not be honored. -*/ + * The function atomically unlocks the given mutex and endeavors to block until + * the given condition variable is signaled by a call to cnd_signal or to + * cnd_broadcast, or until after the specified time. When the calling thread + * becomes unblocked it locks the mutex before it returns. + * @param cond A condition variable object. + * @param mtx A mutex object. + * @param xt A point in time at which the request will time out (absolute time). + * @return @ref thrd_success upon success, or @ref thrd_timeout if the time + * specified in the call was reached without acquiring the requested resource, or + * @ref thrd_error if the request could not be honored. + */ int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); /* Thread */ #if defined(_TTHREAD_WIN32_) typedef HANDLE thrd_t; #else -typedef pthread_t thrd_t; +typedef pthread_t thrd_t; #endif /** Thread start function. -* Any thread that is started with the @ref thrd_create() function must be -* started through a function of this type. -* @param arg The thread argument (the @c arg argument of the corresponding -* @ref thrd_create() call). -* @return The thread return value, which can be obtained by another thread -* by using the @ref thrd_join() function. -*/ + * Any thread that is started with the @ref thrd_create() function must be + * started through a function of this type. + * @param arg The thread argument (the @c arg argument of the corresponding + * @ref thrd_create() call). + * @return The thread return value, which can be obtained by another thread + * by using the @ref thrd_join() function. + */ typedef int (*thrd_start_t)(void *arg); /** Create a new thread. -* @param thr Identifier of the newly created thread. -* @param func A function pointer to the function that will be executed in -* the new thread. -* @param arg An argument to the thread function. -* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could -* be allocated for the thread requested, or @ref thrd_error if the request -* could not be honored. -* @note A thread’s identifier may be reused for a different thread once the -* original thread has exited and either been detached or joined to another -* thread. -*/ + * @param thr Identifier of the newly created thread. + * @param func A function pointer to the function that will be executed in + * the new thread. + * @param arg An argument to the thread function. + * @return @ref thrd_success on success, or @ref thrd_nomem if no memory could + * be allocated for the thread requested, or @ref thrd_error if the request + * could not be honored. + * @note A thread’s identifier may be reused for a different thread once the + * original thread has exited and either been detached or joined to another + * thread. + */ int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); /** Identify the calling thread. -* @return The identifier of the calling thread. -*/ + * @return The identifier of the calling thread. + */ thrd_t thrd_current(void); /** NOT YET IMPLEMENTED. -*/ + */ int thrd_detach(thrd_t thr); /** Compare two thread identifiers. -* The function determines if two thread identifiers refer to the same thread. -* @return Zero if the two thread identifiers refer to different threads. -* Otherwise a nonzero value is returned. -*/ + * The function determines if two thread identifiers refer to the same thread. + * @return Zero if the two thread identifiers refer to different threads. + * Otherwise a nonzero value is returned. + */ int thrd_equal(thrd_t thr0, thrd_t thr1); /** Terminate execution of the calling thread. -* @param res Result code of the calling thread. -*/ + * @param res Result code of the calling thread. + */ void thrd_exit(int res); /** Wait for a thread to terminate. -* The function joins the given thread with the current thread by blocking -* until the other thread has terminated. -* @param thr The thread to join with. -* @param res If this pointer is not NULL, the function will store the result -* code of the given thread in the integer pointed to by @c res. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * The function joins the given thread with the current thread by blocking + * until the other thread has terminated. + * @param thr The thread to join with. + * @param res If this pointer is not NULL, the function will store the result + * code of the given thread in the integer pointed to by @c res. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int thrd_join(thrd_t thr, int *res); /** Put the calling thread to sleep. -* Suspend execution of the calling thread. -* @param time_point A point in time at which the thread will resume (absolute time). -* @param remaining If non-NULL, this parameter will hold the remaining time until -* time_point upon return. This will typically be zero, but if -* the thread was woken up by a signal that is not ignored before -* time_point was reached @c remaining will hold a positive -* time. -* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. -*/ + * Suspend execution of the calling thread. + * @param time_point A point in time at which the thread will resume (absolute time). + * @param remaining If non-NULL, this parameter will hold the remaining time until + * time_point upon return. This will typically be zero, but if + * the thread was woken up by a signal that is not ignored before + * time_point was reached @c remaining will hold a positive + * time. + * @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. + */ int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); /** Yield execution to another thread. -* Permit other threads to run, even if the current thread would ordinarily -* continue to run. -*/ + * Permit other threads to run, even if the current thread would ordinarily + * continue to run. + */ void thrd_yield(void); /* Thread local storage */ #if defined(_TTHREAD_WIN32_) typedef DWORD tss_t; #else -typedef pthread_key_t tss_t; +typedef pthread_key_t tss_t; #endif /** Destructor function for a thread-specific storage. -* @param val The value of the destructed thread-specific storage. -*/ + * @param val The value of the destructed thread-specific storage. + */ typedef void (*tss_dtor_t)(void *val); /** Create a thread-specific storage. -* @param key The unique key identifier that will be set if the function is -* successful. -* @param dtor Destructor function. This can be NULL. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -* @note The destructor function is not supported under Windows. If @c dtor is -* not NULL when calling this function under Windows, the function will fail -* and return @ref thrd_error. -*/ + * @param key The unique key identifier that will be set if the function is + * successful. + * @param dtor Destructor function. This can be NULL. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + * @note The destructor function is not supported under Windows. If @c dtor is + * not NULL when calling this function under Windows, the function will fail + * and return @ref thrd_error. + */ int tss_create(tss_t *key, tss_dtor_t dtor); /** Delete a thread-specific storage. -* The function releases any resources used by the given thread-specific -* storage. -* @param key The key that shall be deleted. -*/ + * The function releases any resources used by the given thread-specific + * storage. + * @param key The key that shall be deleted. + */ void tss_delete(tss_t key); /** Get the value for a thread-specific storage. -* @param key The thread-specific storage identifier. -* @return The value for the current thread held in the given thread-specific -* storage. -*/ + * @param key The thread-specific storage identifier. + * @return The value for the current thread held in the given thread-specific + * storage. + */ void *tss_get(tss_t key); /** Set the value for a thread-specific storage. -* @param key The thread-specific storage identifier. -* @param val The value of the thread-specific storage to set for the current -* thread. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param key The thread-specific storage identifier. + * @param val The value of the thread-specific storage to set for the current + * thread. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int tss_set(tss_t key, void *val); - #endif /* _TINYTHREAD_H_ */ - diff --git a/tests/common/vkengine.c b/tests/common/vkengine.c index b1e8a9d..57307ff 100644 --- a/tests/common/vkengine.c +++ b/tests/common/vkengine.c @@ -30,281 +30,270 @@ #include "vkvg.h" -#define TRY_LOAD_DEVICE_EXT(ext) { \ -if (vkh_phyinfo_try_get_extension_properties(pi, #ext, NULL)) \ - enabledExts[enabledExtsCount++] = #ext; \ -} +#define TRY_LOAD_DEVICE_EXT(ext) \ + { \ + if (vkh_phyinfo_try_get_extension_properties(pi, #ext, NULL)) \ + enabledExts[enabledExtsCount++] = #ext; \ + } static void glfw_error_callback(int error, const char *description) { - fprintf(stderr, "vkengine: GLFW error %d: %s\n", error, description); + fprintf(stderr, "vkengine: GLFW error %d: %s\n", error, description); } -VkSampleCountFlagBits getMaxUsableSampleCount(VkSampleCountFlags counts) -{ - if (counts & VK_SAMPLE_COUNT_64_BIT) { return VK_SAMPLE_COUNT_64_BIT; } - if (counts & VK_SAMPLE_COUNT_32_BIT) { return VK_SAMPLE_COUNT_32_BIT; } - if (counts & VK_SAMPLE_COUNT_16_BIT) { return VK_SAMPLE_COUNT_16_BIT; } - if (counts & VK_SAMPLE_COUNT_8_BIT) { return VK_SAMPLE_COUNT_8_BIT; } - if (counts & VK_SAMPLE_COUNT_4_BIT) { return VK_SAMPLE_COUNT_4_BIT; } - if (counts & VK_SAMPLE_COUNT_2_BIT) { return VK_SAMPLE_COUNT_2_BIT; } - return VK_SAMPLE_COUNT_1_BIT; +VkSampleCountFlagBits getMaxUsableSampleCount(VkSampleCountFlags counts) { + if (counts & VK_SAMPLE_COUNT_64_BIT) { + return VK_SAMPLE_COUNT_64_BIT; + } + if (counts & VK_SAMPLE_COUNT_32_BIT) { + return VK_SAMPLE_COUNT_32_BIT; + } + if (counts & VK_SAMPLE_COUNT_16_BIT) { + return VK_SAMPLE_COUNT_16_BIT; + } + if (counts & VK_SAMPLE_COUNT_8_BIT) { + return VK_SAMPLE_COUNT_8_BIT; + } + if (counts & VK_SAMPLE_COUNT_4_BIT) { + return VK_SAMPLE_COUNT_4_BIT; + } + if (counts & VK_SAMPLE_COUNT_2_BIT) { + return VK_SAMPLE_COUNT_2_BIT; + } + return VK_SAMPLE_COUNT_1_BIT; } -void vkengine_dump_Infos (VkEngine e){ - printf("max samples = %d\n", getMaxUsableSampleCount(e->gpu_props.limits.framebufferColorSampleCounts)); - printf("max tex2d size = %d\n", e->gpu_props.limits.maxImageDimension2D); - printf("max tex array layers = %d\n", e->gpu_props.limits.maxImageArrayLayers); - printf("max mem alloc count = %d\n", e->gpu_props.limits.maxMemoryAllocationCount); - - for (uint32_t i = 0; i < e->memory_properties.memoryHeapCount; i++) { - printf("Mem Heap %d\n", i); - printf("\tflags= %d\n", e->memory_properties.memoryHeaps[i].flags); - printf("\tsize = %lu Mo\n", (unsigned long)e->memory_properties.memoryHeaps[i].size/ (uint32_t)(1024*1024)); - } - for (uint32_t i = 0; i < e->memory_properties.memoryTypeCount; i++) { - printf("Mem type %d\n", i); - printf("\theap %d: ", e->memory_properties.memoryTypes[i].heapIndex); - if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) - printf("VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT|"); - if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) - printf("VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|"); - if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) - printf("VK_MEMORY_PROPERTY_HOST_COHERENT_BIT|"); - if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) - printf("VK_MEMORY_PROPERTY_HOST_CACHED_BIT|"); - if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) - printf("VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT|"); - printf("\n"); - } +void vkengine_dump_Infos(VkEngine e) { + printf("max samples = %d\n", getMaxUsableSampleCount(e->gpu_props.limits.framebufferColorSampleCounts)); + printf("max tex2d size = %d\n", e->gpu_props.limits.maxImageDimension2D); + printf("max tex array layers = %d\n", e->gpu_props.limits.maxImageArrayLayers); + printf("max mem alloc count = %d\n", e->gpu_props.limits.maxMemoryAllocationCount); + + for (uint32_t i = 0; i < e->memory_properties.memoryHeapCount; i++) { + printf("Mem Heap %d\n", i); + printf("\tflags= %d\n", e->memory_properties.memoryHeaps[i].flags); + printf("\tsize = %lu Mo\n", (unsigned long)e->memory_properties.memoryHeaps[i].size / (uint32_t)(1024 * 1024)); + } + for (uint32_t i = 0; i < e->memory_properties.memoryTypeCount; i++) { + printf("Mem type %d\n", i); + printf("\theap %d: ", e->memory_properties.memoryTypes[i].heapIndex); + if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + printf("VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT|"); + if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + printf("VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|"); + if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) + printf("VK_MEMORY_PROPERTY_HOST_COHERENT_BIT|"); + if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) + printf("VK_MEMORY_PROPERTY_HOST_CACHED_BIT|"); + if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) + printf("VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT|"); + printf("\n"); + } } +void vkengine_dump_available_layers() { + uint32_t layerCount; + vkEnumerateInstanceLayerProperties(&layerCount, NULL); + VkLayerProperties *availableLayers = (VkLayerProperties *)malloc(layerCount * sizeof(VkLayerProperties)); + vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); -void vkengine_dump_available_layers () { - uint32_t layerCount; - vkEnumerateInstanceLayerProperties(&layerCount, NULL); - - VkLayerProperties* availableLayers = (VkLayerProperties*)malloc(layerCount*sizeof(VkLayerProperties)); - vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); - - printf("Available Layers:\n"); - printf("-----------------\n"); - for (uint32_t i=0; iproperties.deviceType == gpuType) { - *phy = phys[i]; - return true; - } - } - return false; +bool vkengine_try_get_phyinfo(VkhPhyInfo *phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo *phy) { + for (uint32_t i = 0; i < phyCount; i++) { + if (phys[i]->properties.deviceType == gpuType) { + *phy = phys[i]; + return true; + } + } + return false; } -bool instance_extension_supported (VkExtensionProperties* instanceExtProps, uint32_t extCount, const char* instanceName) { - for (uint32_t i=0; iapp = vkh_app_create(1, 2, "vkvg", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); + e->app = vkh_app_create(1, 2, "vkvg", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); #else - e->app = vkh_app_create(1, 1, "vkvg", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); + e->app = vkh_app_create(1, 1, "vkvg", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); #endif - -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_app_enable_debug_messenger(e->app - , VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT - //| VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT - //| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT - , VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT - //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT - //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT - , NULL); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_app_enable_debug_messenger(e->app, + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT + //| VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT + //| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT + , + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT + //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT + , + NULL); #endif - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); - glfwWindowHint(GLFW_FLOATING, GLFW_FALSE); - glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + glfwWindowHint(GLFW_FLOATING, GLFW_FALSE); + glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); - e->window = glfwCreateWindow ((int)width, (int)height, "Window Title", NULL, NULL); + e->window = glfwCreateWindow((int)width, (int)height, "Window Title", NULL, NULL); - VkSurfaceKHR surf; - VK_CHECK_RESULT (glfwCreateWindowSurface(e->app->inst, e->window, NULL, &surf)) + VkSurfaceKHR surf; + VK_CHECK_RESULT(glfwCreateWindowSurface(e->app->inst, e->window, NULL, &surf)) - VkhPhyInfo* phys = vkh_app_get_phyinfos (e->app, &phyCount, surf); + VkhPhyInfo *phys = vkh_app_get_phyinfos(e->app, &phyCount, surf); - VkhPhyInfo pi = 0; - if (!vkengine_try_get_phyinfo(phys, phyCount, preferedGPU, &pi) - && !vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, &pi) - && !vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, &pi)) - pi = phys[0]; - assert(pi && "No vulkan physical device found."); + VkhPhyInfo pi = 0; + if (!vkengine_try_get_phyinfo(phys, phyCount, preferedGPU, &pi) && + !vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, &pi) && + !vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, &pi)) + pi = phys[0]; + assert(pi && "No vulkan physical device found."); - e->memory_properties = pi->memProps; - e->gpu_props = pi->properties; + e->memory_properties = pi->memProps; + e->gpu_props = pi->properties; - uint32_t qCount = 0; - float qPriorities[] = {0.0}; + uint32_t qCount = 0; + float qPriorities[] = {0.0}; - VkDeviceQueueCreateInfo pQueueInfos[] = { {0},{0},{0} }; - if (vkh_phyinfo_create_presentable_queues (pi, 1, qPriorities, &pQueueInfos[qCount])) - qCount++; - /*if (vkh_phyinfo_create_compute_queues (pi, 1, qPriorities, &pQueueInfos[qCount])) - qCount++; - if (vkh_phyinfo_create_transfer_queues (pi, 1, qPriorities, &pQueueInfos[qCount])) - qCount++;*/ + VkDeviceQueueCreateInfo pQueueInfos[] = {{0}, {0}, {0}}; + if (vkh_phyinfo_create_presentable_queues(pi, 1, qPriorities, &pQueueInfos[qCount])) + qCount++; + /*if (vkh_phyinfo_create_compute_queues (pi, 1, qPriorities, &pQueueInfos[qCount])) + qCount++; + if (vkh_phyinfo_create_transfer_queues (pi, 1, qPriorities, &pQueueInfos[qCount])) + qCount++;*/ - enabledExtsCount=0; + enabledExtsCount = 0; - if (vkvg_get_required_device_extensions (pi->phy, enabledExts, &enabledExtsCount) != VKVG_STATUS_SUCCESS) { - perror ("vkvg_get_required_device_extensions failed, enable log for details.\n"); - exit(-1); - } - TRY_LOAD_DEVICE_EXT (VK_KHR_swapchain) + if (vkvg_get_required_device_extensions(pi->phy, enabledExts, &enabledExtsCount) != VKVG_STATUS_SUCCESS) { + perror("vkvg_get_required_device_extensions failed, enable log for details.\n"); + exit(-1); + } + TRY_LOAD_DEVICE_EXT(VK_KHR_swapchain) - VkPhysicalDeviceFeatures enabledFeatures = {0}; - const void* pNext = vkvg_get_device_requirements (&enabledFeatures); + VkPhysicalDeviceFeatures enabledFeatures = {0}; + const void *pNext = vkvg_get_device_requirements(&enabledFeatures); - VkDeviceCreateInfo device_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .queueCreateInfoCount = qCount, - .pQueueCreateInfos = (VkDeviceQueueCreateInfo*)&pQueueInfos, - .enabledExtensionCount = enabledExtsCount, - .ppEnabledExtensionNames = enabledExts, - .pEnabledFeatures = &enabledFeatures, - .pNext = pNext}; + VkDeviceCreateInfo device_info = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .queueCreateInfoCount = qCount, + .pQueueCreateInfos = (VkDeviceQueueCreateInfo *)&pQueueInfos, + .enabledExtensionCount = enabledExtsCount, + .ppEnabledExtensionNames = enabledExts, + .pEnabledFeatures = &enabledFeatures, + .pNext = pNext}; - e->dev = vkh_device_create(e->app, pi, &device_info); + e->dev = vkh_device_create(e->app, pi, &device_info); - e->renderer = vkh_presenter_create - (e->dev, (uint32_t) pi->pQueue, surf, width, height, VK_FORMAT_B8G8R8A8_UNORM, presentMode); + e->renderer = + vkh_presenter_create(e->dev, (uint32_t)pi->pQueue, surf, width, height, VK_FORMAT_B8G8R8A8_UNORM, presentMode); - vkh_app_free_phyinfos (phyCount, phys); + vkh_app_free_phyinfos(phyCount, phys); - return e; + return e; } -void vkengine_destroy (VkEngine e) { - //vkDeviceWaitIdle(e->dev->dev); +void vkengine_destroy(VkEngine e) { + // vkDeviceWaitIdle(e->dev->dev); - VkSurfaceKHR surf = e->renderer->surface; + VkSurfaceKHR surf = e->renderer->surface; - vkh_presenter_destroy (e->renderer); - vkDestroySurfaceKHR (e->app->inst, surf, NULL); + vkh_presenter_destroy(e->renderer); + vkDestroySurfaceKHR(e->app->inst, surf, NULL); - vkh_device_destroy (e->dev); + vkh_device_destroy(e->dev); - glfwDestroyWindow (e->window); - vkh_app_destroy (e->app); + glfwDestroyWindow(e->window); + vkh_app_destroy(e->app); - glfwTerminate (); + glfwTerminate(); - free(e); -} -void vkengine_close (VkEngine e) { - glfwSetWindowShouldClose(e->window, GLFW_TRUE); -} -void vkengine_blitter_run (VkEngine e, VkImage img, uint32_t width, uint32_t height) { - VkhPresenter p = e->renderer; - vkh_presenter_build_blit_cmd (p, img, width, height); - - while (!vkengine_should_close (e)) { - glfwPollEvents(); - if (!vkh_presenter_draw (p)) - vkh_presenter_build_blit_cmd (p, img, width, height); - } -} -bool vkengine_should_close (VkEngine e) { - return glfwWindowShouldClose (e->window); -} -void vkengine_set_title (VkEngine e, const char* title) { - glfwSetWindowTitle(e->window, title); -} -VkInstance vkengine_get_instance (VkEngine e){ - return e->dev->instance; -} -VkDevice vkengine_get_device (VkEngine e){ - return e->dev->dev; -} -VkPhysicalDevice vkengine_get_physical_device (VkEngine e){ - return e->dev->phy; -} -VkQueue vkengine_get_queue (VkEngine e){ - return e->renderer->queue; -} -uint32_t vkengine_get_queue_fam_idx (VkEngine e){ - return e->renderer->qFam; -} -void vkengine_wait_idle (VkEngine e) { - vkDeviceWaitIdle(e->dev->dev); -} - -void vkengine_set_key_callback (VkEngine e, GLFWkeyfun key_callback){ - glfwSetKeyCallback (e->window, key_callback); -} -void vkengine_set_mouse_but_callback (VkEngine e, GLFWmousebuttonfun onMouseBut){ - glfwSetMouseButtonCallback(e->window, onMouseBut); + free(e); } -void vkengine_set_cursor_pos_callback (VkEngine e, GLFWcursorposfun onMouseMove){ - glfwSetCursorPosCallback(e->window, onMouseMove); +void vkengine_close(VkEngine e) { glfwSetWindowShouldClose(e->window, GLFW_TRUE); } +void vkengine_blitter_run(VkEngine e, VkImage img, uint32_t width, uint32_t height) { + VkhPresenter p = e->renderer; + vkh_presenter_build_blit_cmd(p, img, width, height); + + while (!vkengine_should_close(e)) { + glfwPollEvents(); + if (!vkh_presenter_draw(p)) + vkh_presenter_build_blit_cmd(p, img, width, height); + } } -void vkengine_set_scroll_callback (VkEngine e, GLFWscrollfun onScroll){ - glfwSetScrollCallback(e->window, onScroll); +bool vkengine_should_close(VkEngine e) { return glfwWindowShouldClose(e->window); } +void vkengine_set_title(VkEngine e, const char *title) { glfwSetWindowTitle(e->window, title); } +VkInstance vkengine_get_instance(VkEngine e) { return e->dev->instance; } +VkDevice vkengine_get_device(VkEngine e) { return e->dev->dev; } +VkPhysicalDevice vkengine_get_physical_device(VkEngine e) { return e->dev->phy; } +VkQueue vkengine_get_queue(VkEngine e) { return e->renderer->queue; } +uint32_t vkengine_get_queue_fam_idx(VkEngine e) { return e->renderer->qFam; } +void vkengine_wait_idle(VkEngine e) { vkDeviceWaitIdle(e->dev->dev); } + +void vkengine_set_key_callback(VkEngine e, GLFWkeyfun key_callback) { glfwSetKeyCallback(e->window, key_callback); } +void vkengine_set_mouse_but_callback(VkEngine e, GLFWmousebuttonfun onMouseBut) { + glfwSetMouseButtonCallback(e->window, onMouseBut); } -void vkengine_set_char_callback (VkEngine e, GLFWcharfun onChar){ - glfwSetCharCallback(e->window, onChar); +void vkengine_set_cursor_pos_callback(VkEngine e, GLFWcursorposfun onMouseMove) { + glfwSetCursorPosCallback(e->window, onMouseMove); } +void vkengine_set_scroll_callback(VkEngine e, GLFWscrollfun onScroll) { glfwSetScrollCallback(e->window, onScroll); } +void vkengine_set_char_callback(VkEngine e, GLFWcharfun onChar) { glfwSetCharCallback(e->window, onChar); } diff --git a/tests/common/vkengine.h b/tests/common/vkengine.h index ebed772..a8016ec 100644 --- a/tests/common/vkengine.h +++ b/tests/common/vkengine.h @@ -36,38 +36,39 @@ #define FENCE_TIMEOUT 100000000 -typedef struct _vk_engine_t* VkEngine; +typedef struct _vk_engine_t *VkEngine; typedef struct _vk_engine_t { - VkhApp app; - VkPhysicalDeviceMemoryProperties memory_properties; - VkPhysicalDeviceProperties gpu_props; - VkhDevice dev; - GLFWwindow* window; - VkhPresenter renderer; -}vk_engine_t; + VkhApp app; + VkPhysicalDeviceMemoryProperties memory_properties; + VkPhysicalDeviceProperties gpu_props; + VkhDevice dev; + GLFWwindow *window; + VkhPresenter renderer; +} vk_engine_t; -vk_engine_t* vkengine_create (VkPhysicalDeviceType preferedGPU, VkPresentModeKHR presentMode, uint32_t width, uint32_t height); -void vkengine_dump_available_layers (); -bool vkengine_try_get_phyinfo (VkhPhyInfo* phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo* phy); -void vkengine_destroy (VkEngine e); -bool vkengine_should_close (VkEngine e); -void vkengine_close (VkEngine e); -void vkengine_dump_Infos (VkEngine e); -void vkengine_set_title (VkEngine e, const char* title); -VkInstance vkengine_get_instance (VkEngine e); -VkDevice vkengine_get_device (VkEngine e); -VkPhysicalDevice vkengine_get_physical_device(VkEngine e); -VkQueue vkengine_get_queue (VkEngine e); -uint32_t vkengine_get_queue_fam_idx (VkEngine e); +vk_engine_t *vkengine_create(VkPhysicalDeviceType preferedGPU, VkPresentModeKHR presentMode, uint32_t width, + uint32_t height); +void vkengine_dump_available_layers(); +bool vkengine_try_get_phyinfo(VkhPhyInfo *phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo *phy); +void vkengine_destroy(VkEngine e); +bool vkengine_should_close(VkEngine e); +void vkengine_close(VkEngine e); +void vkengine_dump_Infos(VkEngine e); +void vkengine_set_title(VkEngine e, const char *title); +VkInstance vkengine_get_instance(VkEngine e); +VkDevice vkengine_get_device(VkEngine e); +VkPhysicalDevice vkengine_get_physical_device(VkEngine e); +VkQueue vkengine_get_queue(VkEngine e); +uint32_t vkengine_get_queue_fam_idx(VkEngine e); -void vkengine_get_queues_properties (vk_engine_t* e, VkQueueFamilyProperties** qFamProps, uint32_t* count); +void vkengine_get_queues_properties(vk_engine_t *e, VkQueueFamilyProperties **qFamProps, uint32_t *count); -void vkengine_set_key_callback (VkEngine e, GLFWkeyfun key_callback); -void vkengine_set_mouse_but_callback (VkEngine e, GLFWmousebuttonfun onMouseBut); -void vkengine_set_cursor_pos_callback (VkEngine e, GLFWcursorposfun onMouseMove); -void vkengine_set_scroll_callback (VkEngine e, GLFWscrollfun onScroll); -void vkengine_set_char_callback (VkEngine e, GLFWcharfun onChar); +void vkengine_set_key_callback(VkEngine e, GLFWkeyfun key_callback); +void vkengine_set_mouse_but_callback(VkEngine e, GLFWmousebuttonfun onMouseBut); +void vkengine_set_cursor_pos_callback(VkEngine e, GLFWcursorposfun onMouseMove); +void vkengine_set_scroll_callback(VkEngine e, GLFWscrollfun onScroll); +void vkengine_set_char_callback(VkEngine e, GLFWcharfun onChar); -void vkengine_wait_idle (VkEngine e); +void vkengine_wait_idle(VkEngine e); #endif diff --git a/tests/compositing.c b/tests/compositing.c index 54711b4..76e9490 100644 --- a/tests/compositing.c +++ b/tests/compositing.c @@ -1,40 +1,39 @@ #include "test.h" -void compositing(){ - VkvgContext ctx = vkvg_create(surf); - vkvg_clear(ctx); +void compositing() { + VkvgContext ctx = vkvg_create(surf); + vkvg_clear(ctx); - vkvg_set_source_rgba(ctx, 1,0,0,0.5f); - vkvg_rectangle(ctx,100,100,200,200); - vkvg_fill(ctx); + vkvg_set_source_rgba(ctx, 1, 0, 0, 0.5f); + vkvg_rectangle(ctx, 100, 100, 200, 200); + vkvg_fill(ctx); - vkvg_set_source_rgba(ctx, 0,0,1,0.5f); - vkvg_rectangle(ctx,200,200,200,200); - vkvg_fill(ctx); + vkvg_set_source_rgba(ctx, 0, 0, 1, 0.5f); + vkvg_rectangle(ctx, 200, 200, 200, 200); + vkvg_fill(ctx); - vkvg_destroy(ctx); + vkvg_destroy(ctx); } -void opacity(){ - VkvgContext ctx = vkvg_create(surf); - vkvg_clear(ctx); +void opacity() { + VkvgContext ctx = vkvg_create(surf); + vkvg_clear(ctx); - vkvg_set_source_rgba(ctx, 1,0,0,1.0f); - vkvg_rectangle(ctx,100,100,200,200); - vkvg_fill(ctx); + vkvg_set_source_rgba(ctx, 1, 0, 0, 1.0f); + vkvg_rectangle(ctx, 100, 100, 200, 200); + vkvg_fill(ctx); - vkvg_set_opacity(ctx,0.5f); + vkvg_set_opacity(ctx, 0.5f); - vkvg_set_source_rgba(ctx, 0,0,1,1.0f); - vkvg_rectangle(ctx,200,200,200,200); - vkvg_fill(ctx); + vkvg_set_source_rgba(ctx, 0, 0, 1, 1.0f); + vkvg_rectangle(ctx, 200, 200, 200, 200); + vkvg_fill(ctx); - vkvg_destroy(ctx); + vkvg_destroy(ctx); } - int main(int argc, char *argv[]) { - no_test_size = true; - PERFORM_TEST (compositing, argc, argv); - PERFORM_TEST (opacity, argc, argv); - return 0; + no_test_size = true; + PERFORM_TEST(compositing, argc, argv); + PERFORM_TEST(opacity, argc, argv); + return 0; } diff --git a/tests/context.c b/tests/context.c index b22da8a..caf0a26 100644 --- a/tests/context.c +++ b/tests/context.c @@ -1,22 +1,22 @@ #include "test.h" -void create_destroy_multi(){ - VkvgContext* ctxs = (VkvgContext*)malloc(sizeof(VkvgContext)*test_size); - for (uint32_t i = 0; i < test_size; i++) - ctxs[i] = vkvg_create(surf); - for (uint32_t i = 0; i < test_size; i++) - vkvg_destroy(ctxs[i]); - free(ctxs); +void create_destroy_multi() { + VkvgContext *ctxs = (VkvgContext *)malloc(sizeof(VkvgContext) * test_size); + for (uint32_t i = 0; i < test_size; i++) + ctxs[i] = vkvg_create(surf); + for (uint32_t i = 0; i < test_size; i++) + vkvg_destroy(ctxs[i]); + free(ctxs); } -void create_destroy_single(){ - VkvgContext ctx = vkvg_create(surf); - vkvg_destroy(ctx); +void create_destroy_single() { + VkvgContext ctx = vkvg_create(surf); + vkvg_destroy(ctx); } int main(int argc, char *argv[]) { - PERFORM_TEST (create_destroy_multi, argc, argv); - no_test_size = true; - PERFORM_TEST (create_destroy_single, argc, argv); - return 0; + PERFORM_TEST(create_destroy_multi, argc, argv); + no_test_size = true; + PERFORM_TEST(create_destroy_single, argc, argv); + return 0; } diff --git a/tests/curve.c b/tests/curve.c index ff78bc8..d1bcfd1 100644 --- a/tests/curve.c +++ b/tests/curve.c @@ -2,203 +2,200 @@ //"M80 170 C100 170 160 170 180 170 lZ" void test3() { - VkvgContext ctx = vkvg_create(surf); - vkvg_clear (ctx); - vkvg_set_line_width(ctx, 20); - vkvg_set_source_rgb (ctx,1,0,0); - vkvg_move_to (ctx,80,170); - vkvg_curve_to (ctx, 100,170,160,171,180,170); - //vkvg_rel_line_to (ctx, -30,100); - vkvg_close_path (ctx); - vkvg_stroke (ctx); - vkvg_destroy (ctx); - + VkvgContext ctx = vkvg_create(surf); + vkvg_clear(ctx); + vkvg_set_line_width(ctx, 20); + vkvg_set_source_rgb(ctx, 1, 0, 0); + vkvg_move_to(ctx, 80, 170); + vkvg_curve_to(ctx, 100, 170, 160, 171, 180, 170); + // vkvg_rel_line_to (ctx, -30,100); + vkvg_close_path(ctx); + vkvg_stroke(ctx); + vkvg_destroy(ctx); } -void test(){ - VkvgContext ctx = vkvg_create(surf); - - vkvg_set_line_width(ctx, 20); - - vkvg_scale(ctx,2,2); - vkvg_set_line_join(ctx, VKVG_LINE_JOIN_BEVEL); - - //vkvg_arc (ctx, 200, 500, 100, 0, M_PI); - - vkvg_set_source_rgb (ctx, 0.5f,0,0); - - - /*vkvg_move_to(ctx,100,100); - vkvg_line_to(ctx,300,100); - vkvg_line_to(ctx,500,300); - vkvg_line_to(ctx,300,500); - //vkvg_arc (ctx, 200, 500, 100, 0, M_PI); - vkvg_line_to(ctx,300,700); - vkvg_line_to(ctx,100,500);*/ - - /*vkvg_arc(ctx, 300, 300, 100, 0, M_PI); - vkvg_line_to(ctx,100,200); - vkvg_line_to(ctx,200,100); - vkvg_arc(ctx, 250, 100, 50, M_PI, M_PI * 1.5f); - vkvg_line_to(ctx,350,50); - vkvg_arc(ctx, 350, 100, 50, M_PI*1.5f, M_PI * 2.0f); - - vkvg_stroke(ctx); - vkvg_translate(ctx,400,30); - - */ - //vkvg_set_fill_rule(ctx,VKVG_FILL_RULE_EVEN_ODD); - vkvg_translate(ctx,200,30); - vkvg_arc(ctx, 200, 200, 20, 0, M_PIF*2); - //vkvg_stroke(ctx); - - vkvg_set_source_rgba (ctx, 0.5f,0.0f,1.0f,0.5f); - vkvg_move_to(ctx,100,100); - vkvg_line_to(ctx,200,100); - //vkvg_move_to(ctx,200,100); - vkvg_curve_to(ctx,250,100,300,150,300,200); - vkvg_line_to(ctx,300,300); - vkvg_curve_to(ctx,300,350,250,400,200,400); - vkvg_line_to(ctx,100,400); - vkvg_curve_to(ctx,50,400,10,350,10,300); - vkvg_line_to(ctx,10,200); - vkvg_curve_to(ctx,10,150,50,100,100,100); - //vkvg_close_path(ctx); - vkvg_fill_preserve(ctx); - vkvg_set_source_rgba (ctx, 0.1f,0.3f,0.7f,0.5f); - vkvg_stroke(ctx); - - - vkvg_destroy(ctx); +void test() { + VkvgContext ctx = vkvg_create(surf); + + vkvg_set_line_width(ctx, 20); + + vkvg_scale(ctx, 2, 2); + vkvg_set_line_join(ctx, VKVG_LINE_JOIN_BEVEL); + + // vkvg_arc (ctx, 200, 500, 100, 0, M_PI); + + vkvg_set_source_rgb(ctx, 0.5f, 0, 0); + + /*vkvg_move_to(ctx,100,100); + vkvg_line_to(ctx,300,100); + vkvg_line_to(ctx,500,300); + vkvg_line_to(ctx,300,500); + //vkvg_arc (ctx, 200, 500, 100, 0, M_PI); + vkvg_line_to(ctx,300,700); + vkvg_line_to(ctx,100,500);*/ + + /*vkvg_arc(ctx, 300, 300, 100, 0, M_PI); + vkvg_line_to(ctx,100,200); + vkvg_line_to(ctx,200,100); + vkvg_arc(ctx, 250, 100, 50, M_PI, M_PI * 1.5f); + vkvg_line_to(ctx,350,50); + vkvg_arc(ctx, 350, 100, 50, M_PI*1.5f, M_PI * 2.0f); + + vkvg_stroke(ctx); + vkvg_translate(ctx,400,30); + + */ + // vkvg_set_fill_rule(ctx,VKVG_FILL_RULE_EVEN_ODD); + vkvg_translate(ctx, 200, 30); + vkvg_arc(ctx, 200, 200, 20, 0, M_PIF * 2); + // vkvg_stroke(ctx); + + vkvg_set_source_rgba(ctx, 0.5f, 0.0f, 1.0f, 0.5f); + vkvg_move_to(ctx, 100, 100); + vkvg_line_to(ctx, 200, 100); + // vkvg_move_to(ctx,200,100); + vkvg_curve_to(ctx, 250, 100, 300, 150, 300, 200); + vkvg_line_to(ctx, 300, 300); + vkvg_curve_to(ctx, 300, 350, 250, 400, 200, 400); + vkvg_line_to(ctx, 100, 400); + vkvg_curve_to(ctx, 50, 400, 10, 350, 10, 300); + vkvg_line_to(ctx, 10, 200); + vkvg_curve_to(ctx, 10, 150, 50, 100, 100, 100); + // vkvg_close_path(ctx); + vkvg_fill_preserve(ctx); + vkvg_set_source_rgba(ctx, 0.1f, 0.3f, 0.7f, 0.5f); + vkvg_stroke(ctx); + + vkvg_destroy(ctx); } void curved_rect() { - VkvgContext ctx = vkvg_create(surf); - - float x = 50, y = 50, width = 150, height = 140, radius = 30; - - vkvg_scale(ctx, 2, 2); - //vkvg_rotate(ctx,0.5f); - - vkvg_set_line_width(ctx, 15); - vkvg_set_source_rgba(ctx, 0, 0.5f, 0.4f, 1); - - if ((radius > height / 2) || (radius > width / 2)) - radius = MIN(height / 2, width / 2); - - vkvg_move_to(ctx, x, y + radius); - vkvg_arc(ctx, x + radius, y + radius, radius, M_PIF, (float)-M_PI_2); - vkvg_line_to(ctx, x + width - radius, y); - vkvg_arc(ctx, x + width - radius, y + radius, radius, (float)-M_PI_2, 0); - vkvg_line_to(ctx, x + width, y + height - radius); - vkvg_arc(ctx, x + width - radius, y + height - radius, radius, 0, (float)M_PI_2); - vkvg_line_to(ctx, x + radius, y + height); - vkvg_arc(ctx, x + radius, y + height - radius, radius, (float)M_PI_2, M_PIF); - vkvg_line_to(ctx, x, y + radius); - vkvg_close_path(ctx); - vkvg_fill_preserve(ctx); - vkvg_set_source_rgba(ctx, 0.5f, 0, 0, 0.5f); - vkvg_stroke(ctx); - - vkvg_destroy(ctx); + VkvgContext ctx = vkvg_create(surf); + + float x = 50, y = 50, width = 150, height = 140, radius = 30; + + vkvg_scale(ctx, 2, 2); + // vkvg_rotate(ctx,0.5f); + + vkvg_set_line_width(ctx, 15); + vkvg_set_source_rgba(ctx, 0, 0.5f, 0.4f, 1); + + if ((radius > height / 2) || (radius > width / 2)) + radius = MIN(height / 2, width / 2); + + vkvg_move_to(ctx, x, y + radius); + vkvg_arc(ctx, x + radius, y + radius, radius, M_PIF, (float)-M_PI_2); + vkvg_line_to(ctx, x + width - radius, y); + vkvg_arc(ctx, x + width - radius, y + radius, radius, (float)-M_PI_2, 0); + vkvg_line_to(ctx, x + width, y + height - radius); + vkvg_arc(ctx, x + width - radius, y + height - radius, radius, 0, (float)M_PI_2); + vkvg_line_to(ctx, x + radius, y + height); + vkvg_arc(ctx, x + radius, y + height - radius, radius, (float)M_PI_2, M_PIF); + vkvg_line_to(ctx, x, y + radius); + vkvg_close_path(ctx); + vkvg_fill_preserve(ctx); + vkvg_set_source_rgba(ctx, 0.5f, 0, 0, 0.5f); + vkvg_stroke(ctx); + + vkvg_destroy(ctx); } void test2() { - VkvgContext ctx = vkvg_create(surf); + VkvgContext ctx = vkvg_create(surf); - vkvg_move_to(ctx, 100, 400); - vkvg_curve_to(ctx, 100, 100, 600, 700, 600, 400); - vkvg_curve_to(ctx, 1000, 100, 100, 800, 1000, 800); - vkvg_curve_to(ctx, 1000, 500, 700, 500, 700, 100); - vkvg_close_path(ctx); + vkvg_move_to(ctx, 100, 400); + vkvg_curve_to(ctx, 100, 100, 600, 700, 600, 400); + vkvg_curve_to(ctx, 1000, 100, 100, 800, 1000, 800); + vkvg_curve_to(ctx, 1000, 500, 700, 500, 700, 100); + vkvg_close_path(ctx); - //vkvg_set_source_rgba (ctx, 0.5,0.0,1.0,0.5); - //vkvg_fill_preserve(ctx); + // vkvg_set_source_rgba (ctx, 0.5,0.0,1.0,0.5); + // vkvg_fill_preserve(ctx); - vkvg_set_source_rgba(ctx, 1, 0, 0, 1); - vkvg_set_line_width(ctx, 40); - vkvg_stroke(ctx); + vkvg_set_source_rgba(ctx, 1, 0, 0, 1); + vkvg_set_line_width(ctx, 40); + vkvg_stroke(ctx); - vkvg_destroy(ctx); + vkvg_destroy(ctx); } static bool fillAndStroke = true; -void random_curves_stroke () { - float w = (float)test_width; - float h = (float)test_height; +void random_curves_stroke() { + float w = (float)test_width; + float h = (float)test_height; - VkvgContext ctx = _initCtx(); + VkvgContext ctx = _initCtx(); - for (uint32_t i=0; i VKVG_PATTERN_TYPE_RADIAL) - patternType = VKVG_PATTERN_TYPE_LINEAR; - break; - case GLFW_KEY_S : - vkengine_wait_idle(e); - vkvg_surface_write_to_png(surf, "/home/jp/test.png"); - break; - case GLFW_KEY_KP_ADD : - if (ptsCount < initPtsCount) - ptsCount++; - break; - case GLFW_KEY_KP_SUBTRACT : - if (ptsCount > 1) - ptsCount--; - break; - } +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { + if (action != GLFW_PRESS) + return; + switch (key) { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GLFW_TRUE); + break; + case GLFW_KEY_P: + patternType++; + if (patternType > VKVG_PATTERN_TYPE_RADIAL) + patternType = VKVG_PATTERN_TYPE_LINEAR; + break; + case GLFW_KEY_S: + vkengine_wait_idle(e); + vkvg_surface_write_to_png(surf, "/home/jp/test.png"); + break; + case GLFW_KEY_KP_ADD: + if (ptsCount < initPtsCount) + ptsCount++; + break; + case GLFW_KEY_KP_SUBTRACT: + if (ptsCount > 1) + ptsCount--; + break; + } } -static void mouse_move_callback(GLFWwindow* window, double x, double y){ - if (mouseDown) { - if (hoverPt < 0) - return; - pts[hoverPt].x = x; - pts[hoverPt].y = y; - } else { - for (int i=0; i pts[i].x - pointSize && - x < pts[i].x + pointSize && - y > pts[i].y - pointSize && - y < pts[i].y + pointSize) { - hoverPt = i; - return; - } - } - hoverPt = -1; - } +static void mouse_move_callback(GLFWwindow *window, double x, double y) { + if (mouseDown) { + if (hoverPt < 0) + return; + pts[hoverPt].x = x; + pts[hoverPt].y = y; + } else { + for (int i = 0; i < ptsCount; i++) { + if (x > pts[i].x - pointSize && x < pts[i].x + pointSize && y > pts[i].y - pointSize && + y < pts[i].y + pointSize) { + hoverPt = i; + return; + } + } + hoverPt = -1; + } } -static void scroll_callback(GLFWwindow* window, double x, double y){ - if (y<0.f) - zoom *= 0.5f; - else - zoom *= 2.0f; +static void scroll_callback(GLFWwindow *window, double x, double y) { + if (y < 0.f) + zoom *= 0.5f; + else + zoom *= 2.0f; } -static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif){ - if (but != GLFW_MOUSE_BUTTON_1) - return; - if (state == GLFW_TRUE) - mouseDown = true; - else - mouseDown = false; +static void mouse_button_callback(GLFWwindow *window, int but, int state, int modif) { + if (but != GLFW_MOUSE_BUTTON_1) + return; + if (state == GLFW_TRUE) + mouseDown = true; + else + mouseDown = false; } +int main(int argc, char *argv[]) { + _parse_args(argc, argv); -int main(int argc, char* argv[]) { + e = vkengine_create(VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); - _parse_args (argc, argv); + VkhPresenter r = e->renderer; + vkengine_set_key_callback(e, key_callback); + vkengine_set_mouse_but_callback(e, mouse_button_callback); + vkengine_set_cursor_pos_callback(e, mouse_move_callback); + vkengine_set_scroll_callback(e, scroll_callback); - e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); + vkvg_device_create_info_t info = {samples, false, vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0}; + device = vkvg_device_create(&info); + surf = vkvg_surface_create(device, test_width, test_height); - VkhPresenter r = e->renderer; - vkengine_set_key_callback (e, key_callback); - vkengine_set_mouse_but_callback(e, mouse_button_callback); - vkengine_set_cursor_pos_callback(e, mouse_move_callback); - vkengine_set_scroll_callback(e, scroll_callback); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); - vkvg_device_create_info_t info = { - samples, - false, - vkh_app_get_inst(e->app), - r->dev->phy, - r->dev->dev, - r->qFam, - 0 - }; - device = vkvg_device_create(&info); - surf = vkvg_surface_create(device, test_width, test_height); + while (!vkengine_should_close(e)) { + glfwPollEvents(); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); + draw(); - while (!vkengine_should_close (e)) { - glfwPollEvents(); + if (!vkh_presenter_draw(r)) { + vkh_presenter_get_size(r, &test_width, &test_height); + vkvg_surface_destroy(surf); + surf = vkvg_surface_create(device, test_width, test_height); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); + vkDeviceWaitIdle(r->dev->dev); + continue; + } + } + vkDeviceWaitIdle(e->dev->dev); - draw (); + vkvg_surface_destroy(surf); - if (!vkh_presenter_draw (r)){ - vkh_presenter_get_size (r, &test_width, &test_height); - vkvg_surface_destroy (surf); - surf = vkvg_surface_create(device, test_width, test_height); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); - vkDeviceWaitIdle(r->dev->dev); - continue; - } - } - vkDeviceWaitIdle(e->dev->dev); + vkvg_device_destroy(device); - vkvg_surface_destroy (surf); + vkengine_destroy(e); - vkvg_device_destroy (device); - - vkengine_destroy (e); - - return 0; + return 0; } diff --git a/tests/img_surf.c b/tests/img_surf.c index bffc65c..66d66b7 100644 --- a/tests/img_surf.c +++ b/tests/img_surf.c @@ -1,174 +1,174 @@ #include "test.h" -const char* imgPath = "data/miroir.jpg"; -void paint () { - VkvgContext ctx = vkvg_create(surf); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); +const char *imgPath = "data/miroir.jpg"; +void paint() { + VkvgContext ctx = vkvg_create(surf); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - vkvg_set_source_surface(ctx, imgSurf, 0, 0); - vkvg_paint(ctx); + vkvg_set_source_surface(ctx, imgSurf, 0, 0); + vkvg_paint(ctx); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } -void paint_offset () { - VkvgContext ctx = vkvg_create(surf); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); +void paint_offset() { + VkvgContext ctx = vkvg_create(surf); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - vkvg_set_source_surface(ctx, imgSurf, 100, 100); - vkvg_paint(ctx); + vkvg_set_source_surface(ctx, imgSurf, 100, 100); + vkvg_paint(ctx); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } -void paint_with_scale(){ - VkvgContext ctx = vkvg_create(surf); - vkvg_scale (ctx, 0.2f,0.2f); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - vkvg_set_source_surface(ctx, imgSurf, 0, 0); +void paint_with_scale() { + VkvgContext ctx = vkvg_create(surf); + vkvg_scale(ctx, 0.2f, 0.2f); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); + vkvg_set_source_surface(ctx, imgSurf, 0, 0); - vkvg_paint(ctx); + vkvg_paint(ctx); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } -void translate(){ - VkvgContext ctx = vkvg_create(surf); - vkvg_translate (ctx, 150,50); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - vkvg_set_source_surface(ctx, imgSurf, 0, 0); +void translate() { + VkvgContext ctx = vkvg_create(surf); + vkvg_translate(ctx, 150, 50); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); + vkvg_set_source_surface(ctx, imgSurf, 0, 0); - vkvg_paint(ctx); + vkvg_paint(ctx); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } -void offset_and_scale(){ - VkvgContext ctx = vkvg_create(surf); - vkvg_scale (ctx, 0.2f,0.2f); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - vkvg_set_source_surface(ctx, imgSurf, 100, 100); +void offset_and_scale() { + VkvgContext ctx = vkvg_create(surf); + vkvg_scale(ctx, 0.2f, 0.2f); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); + vkvg_set_source_surface(ctx, imgSurf, 100, 100); - vkvg_paint(ctx); + vkvg_paint(ctx); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } static float angle = 0; -void paint_with_rot(){ - angle += 0.005; - VkvgContext ctx = vkvg_create(surf); - vkvg_clear(ctx); +void paint_with_rot() { + angle += 0.005; + VkvgContext ctx = vkvg_create(surf); + vkvg_clear(ctx); - vkvg_rotate (ctx, angle); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - vkvg_set_source_surface(ctx, imgSurf, 0, 0); + vkvg_rotate(ctx, angle); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); + vkvg_set_source_surface(ctx, imgSurf, 0, 0); - vkvg_paint(ctx); + vkvg_paint(ctx); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } -void offset_and_rot(){ - angle += 0.005; - VkvgContext ctx = vkvg_create(surf); - vkvg_clear(ctx); +void offset_and_rot() { + angle += 0.005; + VkvgContext ctx = vkvg_create(surf); + vkvg_clear(ctx); - vkvg_rotate (ctx, angle); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - vkvg_set_source_surface(ctx, imgSurf, 100, 100); + vkvg_rotate(ctx, angle); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); + vkvg_set_source_surface(ctx, imgSurf, 100, 100); - vkvg_paint(ctx); + vkvg_paint(ctx); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } -void paint_pattern () { - VkvgContext ctx = vkvg_create(surf); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - VkvgPattern pat = vkvg_pattern_create_for_surface(imgSurf); - vkvg_set_source(ctx, pat); - vkvg_paint(ctx); - vkvg_pattern_destroy(pat); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); +void paint_pattern() { + VkvgContext ctx = vkvg_create(surf); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); + VkvgPattern pat = vkvg_pattern_create_for_surface(imgSurf); + vkvg_set_source(ctx, pat); + vkvg_paint(ctx); + vkvg_pattern_destroy(pat); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } -void paint_patt_repeat () { - VkvgContext ctx = vkvg_create(surf); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - VkvgPattern pat = vkvg_pattern_create_for_surface(imgSurf); - vkvg_pattern_set_extend(pat,VKVG_EXTEND_REPEAT); - vkvg_set_source(ctx, pat); - vkvg_paint(ctx); - vkvg_pattern_destroy(pat); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); +void paint_patt_repeat() { + VkvgContext ctx = vkvg_create(surf); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); + VkvgPattern pat = vkvg_pattern_create_for_surface(imgSurf); + vkvg_pattern_set_extend(pat, VKVG_EXTEND_REPEAT); + vkvg_set_source(ctx, pat); + vkvg_paint(ctx); + vkvg_pattern_destroy(pat); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } -void paint_patt_repeat_scalled () { - VkvgContext ctx = vkvg_create(surf); - vkvg_scale (ctx, 0.2f,0.2f); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - VkvgPattern pat = vkvg_pattern_create_for_surface(imgSurf); - vkvg_pattern_set_extend(pat,VKVG_EXTEND_REPEAT); - vkvg_set_source(ctx, pat); - vkvg_paint(ctx); - vkvg_pattern_destroy(pat); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); +void paint_patt_repeat_scalled() { + VkvgContext ctx = vkvg_create(surf); + vkvg_scale(ctx, 0.2f, 0.2f); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); + VkvgPattern pat = vkvg_pattern_create_for_surface(imgSurf); + vkvg_pattern_set_extend(pat, VKVG_EXTEND_REPEAT); + vkvg_set_source(ctx, pat); + vkvg_paint(ctx); + vkvg_pattern_destroy(pat); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } -void paint_patt_pad () { - VkvgContext ctx = vkvg_create(surf); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - VkvgPattern pat = vkvg_pattern_create_for_surface(imgSurf); - vkvg_pattern_set_extend(pat,VKVG_EXTEND_PAD); - vkvg_set_source(ctx, pat); - vkvg_paint(ctx); - vkvg_pattern_destroy(pat); - vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); +void paint_patt_pad() { + VkvgContext ctx = vkvg_create(surf); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); + VkvgPattern pat = vkvg_pattern_create_for_surface(imgSurf); + vkvg_pattern_set_extend(pat, VKVG_EXTEND_PAD); + vkvg_set_source(ctx, pat); + vkvg_paint(ctx); + vkvg_pattern_destroy(pat); + vkvg_surface_destroy(imgSurf); + vkvg_destroy(ctx); } -void test(){ - VkvgContext ctx = vkvg_create(surf); - vkvg_set_fill_rule(ctx,VKVG_FILL_RULE_EVEN_ODD); - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); +void test() { + VkvgContext ctx = vkvg_create(surf); + vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_EVEN_ODD); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - vkvg_translate(ctx,200,200); - //vkvg_rotate(ctx,M_PI_4); + vkvg_translate(ctx, 200, 200); + // vkvg_rotate(ctx,M_PI_4); - vkvg_set_line_width(ctx,20.f); - //vkvg_set_source_rgba(ctx,1,0,0,1); - vkvg_arc(ctx,200,200,200,0,2.f*M_PIF); - vkvg_new_sub_path(ctx); - vkvg_arc(ctx,200,200,100,0,2.f*M_PIF); + vkvg_set_line_width(ctx, 20.f); + // vkvg_set_source_rgba(ctx,1,0,0,1); + vkvg_arc(ctx, 200, 200, 200, 0, 2.f * M_PIF); + vkvg_new_sub_path(ctx); + vkvg_arc(ctx, 200, 200, 100, 0, 2.f * M_PIF); - vkvg_set_source_surface(ctx, imgSurf, 0, 0); - vkvg_fill_preserve(ctx); - vkvg_set_source_rgba(ctx,0.2f,0.3f,0.8f,1); + vkvg_set_source_surface(ctx, imgSurf, 0, 0); + vkvg_fill_preserve(ctx); + vkvg_set_source_rgba(ctx, 0.2f, 0.3f, 0.8f, 1); - vkvg_stroke(ctx); + vkvg_stroke(ctx); - vkvg_surface_destroy(imgSurf); + vkvg_surface_destroy(imgSurf); - vkvg_destroy(ctx); + vkvg_destroy(ctx); } int main(int argc, char *argv[]) { - no_test_size = true; - PERFORM_TEST (paint, argc, argv); - PERFORM_TEST (paint_offset, argc, argv); - PERFORM_TEST (paint_with_scale, argc, argv); - PERFORM_TEST (offset_and_scale, argc, argv); - PERFORM_TEST (translate, argc, argv); - PERFORM_TEST (paint_with_rot, argc, argv); - PERFORM_TEST (offset_and_rot, argc, argv); - PERFORM_TEST (paint_pattern, argc, argv); - PERFORM_TEST (paint_patt_repeat, argc, argv); - PERFORM_TEST (paint_patt_repeat_scalled, argc, argv); - PERFORM_TEST (paint_patt_pad, argc, argv); - PERFORM_TEST (test, argc, argv); - - return 0; + no_test_size = true; + PERFORM_TEST(paint, argc, argv); + PERFORM_TEST(paint_offset, argc, argv); + PERFORM_TEST(paint_with_scale, argc, argv); + PERFORM_TEST(offset_and_scale, argc, argv); + PERFORM_TEST(translate, argc, argv); + PERFORM_TEST(paint_with_rot, argc, argv); + PERFORM_TEST(offset_and_rot, argc, argv); + PERFORM_TEST(paint_pattern, argc, argv); + PERFORM_TEST(paint_patt_repeat, argc, argv); + PERFORM_TEST(paint_patt_repeat_scalled, argc, argv); + PERFORM_TEST(paint_patt_pad, argc, argv); + PERFORM_TEST(test, argc, argv); + + return 0; } diff --git a/tests/inverse_colinear.c b/tests/inverse_colinear.c index 38b4adc..2b5735c 100644 --- a/tests/inverse_colinear.c +++ b/tests/inverse_colinear.c @@ -1,227 +1,209 @@ #include "test.h" #include "vectors.h" -vkvg_fill_rule_t fillrule = VKVG_FILL_RULE_NON_ZERO; -static VkSampleCountFlags samples = VK_SAMPLE_COUNT_8_BIT; -float lineWidth = 50.0f; -vkvg_line_join_t lineJoin = VKVG_LINE_JOIN_MITER; -vkvg_line_cap_t lineCap = VKVG_LINE_CAP_BUTT; -bool isClosed = false; -bool startWithArc = false, endWithArc = false; - -int ptsCount = 4; -int initPtsCount = 5; -vec2 pts[] = { - {150,150}, - {200,300}, - {250,150}, - {280,350}, - {300,100}, +vkvg_fill_rule_t fillrule = VKVG_FILL_RULE_NON_ZERO; +static VkSampleCountFlags samples = VK_SAMPLE_COUNT_8_BIT; +float lineWidth = 50.0f; +vkvg_line_join_t lineJoin = VKVG_LINE_JOIN_MITER; +vkvg_line_cap_t lineCap = VKVG_LINE_CAP_BUTT; +bool isClosed = false; +bool startWithArc = false, endWithArc = false; + +int ptsCount = 4; +int initPtsCount = 5; +vec2 pts[] = { + {150, 150}, {200, 300}, {250, 150}, {280, 350}, {300, 100}, }; /*vec2 pts[] = { - {150,150}, - {250,150}, - {100,150}, - {150,200}, + {150,150}, + {250,150}, + {100,150}, + {150,200}, };*/ -int hoverPt = -1; +int hoverPt = -1; double pointSize = 7; -float dash[] = {0, 60}; +float dash[] = {0, 60}; uint32_t dashCountInit = 2; -uint32_t dashCount = 0; -float miterLimit = 10.0f; - - - -void draw (){ - - VkvgContext ctx = vkvg_create(surf); - vkvg_clear(ctx); - if (dashCount > 0) - vkvg_set_dash(ctx, dash, dashCount,0); - vkvg_set_source_rgba (ctx,1,0,0,0.3f); - vkvg_set_line_width (ctx,lineWidth); - vkvg_set_line_join (ctx, lineJoin); - vkvg_set_line_cap (ctx, lineCap); - vkvg_set_miter_limit (ctx, miterLimit); - - if (startWithArc) - vkvg_arc_negative(ctx,pts[0].x,pts[0].y,200, M_PIF*1.5f, M_PIF); - else - vkvg_move_to(ctx,pts[0].x,pts[0].y); - for (int i=1; i=0) { - vkvg_stroke_preserve(ctx); - vkvg_set_dash(ctx, NULL, 0, 0); - vkvg_set_line_width(ctx,2); - vkvg_set_source_rgba(ctx,0,0,0,1); - vkvg_stroke(ctx); - vkvg_set_source_rgba(ctx,0.5f,0.5f,1.0f,0.7f); - vkvg_arc (ctx, pts[hoverPt].x, pts[hoverPt].y, pointSize, 0, M_PIF*2); - vkvg_fill_preserve(ctx); - vkvg_stroke(ctx); - } else - vkvg_stroke(ctx); - - //draw_v(ctx, 200, 20, VKVG_LINE_JOIN_BEVEL); - //draw_v(ctx, 300, 80, VKVG_LINE_JOIN_ROUND); - vkvg_destroy(ctx); +uint32_t dashCount = 0; +float miterLimit = 10.0f; + +void draw() { + + VkvgContext ctx = vkvg_create(surf); + vkvg_clear(ctx); + if (dashCount > 0) + vkvg_set_dash(ctx, dash, dashCount, 0); + vkvg_set_source_rgba(ctx, 1, 0, 0, 0.3f); + vkvg_set_line_width(ctx, lineWidth); + vkvg_set_line_join(ctx, lineJoin); + vkvg_set_line_cap(ctx, lineCap); + vkvg_set_miter_limit(ctx, miterLimit); + + if (startWithArc) + vkvg_arc_negative(ctx, pts[0].x, pts[0].y, 200, M_PIF * 1.5f, M_PIF); + else + vkvg_move_to(ctx, pts[0].x, pts[0].y); + for (int i = 1; i < ptsCount - 1; i++) + vkvg_line_to(ctx, pts[i].x, pts[i].y); + if (endWithArc) + vkvg_arc_negative(ctx, pts[ptsCount - 1].x, pts[ptsCount - 1].y, 200, M_PIF * 1.5f, M_PIF); + else + vkvg_line_to(ctx, pts[ptsCount - 1].x, pts[ptsCount - 1].y); + + if (isClosed) + vkvg_close_path(ctx); + + if (hoverPt >= 0) { + vkvg_stroke_preserve(ctx); + vkvg_set_dash(ctx, NULL, 0, 0); + vkvg_set_line_width(ctx, 2); + vkvg_set_source_rgba(ctx, 0, 0, 0, 1); + vkvg_stroke(ctx); + vkvg_set_source_rgba(ctx, 0.5f, 0.5f, 1.0f, 0.7f); + vkvg_arc(ctx, pts[hoverPt].x, pts[hoverPt].y, pointSize, 0, M_PIF * 2); + vkvg_fill_preserve(ctx); + vkvg_stroke(ctx); + } else + vkvg_stroke(ctx); + + // draw_v(ctx, 200, 20, VKVG_LINE_JOIN_BEVEL); + // draw_v(ctx, 300, 80, VKVG_LINE_JOIN_ROUND); + vkvg_destroy(ctx); } -static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { - if (action == GLFW_RELEASE) - return; - switch (key) { - case GLFW_KEY_ESCAPE : - glfwSetWindowShouldClose(window, GLFW_TRUE); - break; - case GLFW_KEY_W : - isClosed ^= true; - break; - case GLFW_KEY_Q : - startWithArc ^= true; - break; - case GLFW_KEY_A : - endWithArc ^= true; - break; - case GLFW_KEY_J : - lineJoin++; - if (lineJoin > 2) - lineJoin = 0; - break; - case GLFW_KEY_C : - lineCap++; - if (lineCap > 2) - lineCap = 0; - break; - case GLFW_KEY_D : - if (dashCount == 0) - dashCount = dashCountInit; - else - dashCount = 0; - break; - case GLFW_KEY_E : - if (dash[0] > 0) - dash[0] = 0; - else - dash[0] = 80; - break; - case GLFW_KEY_L : - if (mods & GLFW_MOD_SHIFT) - miterLimit /= 2.0f; - else - miterLimit *= 2.0f; - break; - case GLFW_KEY_P : - if (mods & GLFW_MOD_SHIFT) { - if (ptsCount > 1) - ptsCount--; - } else { - if (ptsCount < initPtsCount) - ptsCount++; - } - break; - case GLFW_KEY_KP_ADD : - lineWidth++; - break; - case GLFW_KEY_KP_SUBTRACT : - if (lineWidth > 1) - lineWidth--; - break; - } +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { + if (action == GLFW_RELEASE) + return; + switch (key) { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GLFW_TRUE); + break; + case GLFW_KEY_W: + isClosed ^= true; + break; + case GLFW_KEY_Q: + startWithArc ^= true; + break; + case GLFW_KEY_A: + endWithArc ^= true; + break; + case GLFW_KEY_J: + lineJoin++; + if (lineJoin > 2) + lineJoin = 0; + break; + case GLFW_KEY_C: + lineCap++; + if (lineCap > 2) + lineCap = 0; + break; + case GLFW_KEY_D: + if (dashCount == 0) + dashCount = dashCountInit; + else + dashCount = 0; + break; + case GLFW_KEY_E: + if (dash[0] > 0) + dash[0] = 0; + else + dash[0] = 80; + break; + case GLFW_KEY_L: + if (mods & GLFW_MOD_SHIFT) + miterLimit /= 2.0f; + else + miterLimit *= 2.0f; + break; + case GLFW_KEY_P: + if (mods & GLFW_MOD_SHIFT) { + if (ptsCount > 1) + ptsCount--; + } else { + if (ptsCount < initPtsCount) + ptsCount++; + } + break; + case GLFW_KEY_KP_ADD: + lineWidth++; + break; + case GLFW_KEY_KP_SUBTRACT: + if (lineWidth > 1) + lineWidth--; + break; + } } -static void mouse_move_callback(GLFWwindow* window, double x, double y){ - if (mouseDown) { - if (hoverPt < 0) - return; - pts[hoverPt].x = x; - pts[hoverPt].y = y; - } else { - for (int i=0; i pts[i].x - pointSize && - x < pts[i].x + pointSize && - y > pts[i].y - pointSize && - y < pts[i].y + pointSize) { - hoverPt = i; - return; - } - } - hoverPt = -1; - } +static void mouse_move_callback(GLFWwindow *window, double x, double y) { + if (mouseDown) { + if (hoverPt < 0) + return; + pts[hoverPt].x = x; + pts[hoverPt].y = y; + } else { + for (int i = 0; i < ptsCount; i++) { + if (x > pts[i].x - pointSize && x < pts[i].x + pointSize && y > pts[i].y - pointSize && + y < pts[i].y + pointSize) { + hoverPt = i; + return; + } + } + hoverPt = -1; + } } -static void scroll_callback(GLFWwindow* window, double x, double y){ - if (y<0.f) - zoom *= 0.5f; - else - zoom *= 2.0f; +static void scroll_callback(GLFWwindow *window, double x, double y) { + if (y < 0.f) + zoom *= 0.5f; + else + zoom *= 2.0f; } -static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif){ - if (but != GLFW_MOUSE_BUTTON_1) - return; - if (state == GLFW_TRUE) - mouseDown = true; - else - mouseDown = false; +static void mouse_button_callback(GLFWwindow *window, int but, int state, int modif) { + if (but != GLFW_MOUSE_BUTTON_1) + return; + if (state == GLFW_TRUE) + mouseDown = true; + else + mouseDown = false; } +int main(int argc, char *argv[]) { + _parse_args(argc, argv); + VkEngine e; + e = vkengine_create(VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); -int main(int argc, char* argv[]) { + VkhPresenter r = e->renderer; + vkengine_set_key_callback(e, key_callback); + vkengine_set_mouse_but_callback(e, mouse_button_callback); + vkengine_set_cursor_pos_callback(e, mouse_move_callback); + vkengine_set_scroll_callback(e, scroll_callback); - _parse_args (argc, argv); - VkEngine e; - e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); + vkvg_device_create_info_t info = {samples, false, vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0}; + device = vkvg_device_create(&info); + surf = vkvg_surface_create(device, test_width, test_height); - VkhPresenter r = e->renderer; - vkengine_set_key_callback (e, key_callback); - vkengine_set_mouse_but_callback(e, mouse_button_callback); - vkengine_set_cursor_pos_callback(e, mouse_move_callback); - vkengine_set_scroll_callback(e, scroll_callback); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); - vkvg_device_create_info_t info = { - samples, - false, - vkh_app_get_inst(e->app), - r->dev->phy, - r->dev->dev, - r->qFam, - 0 - }; - device = vkvg_device_create(&info); - surf = vkvg_surface_create(device, test_width, test_height); + while (!vkengine_should_close(e)) { + glfwPollEvents(); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); + draw(); - while (!vkengine_should_close (e)) { - glfwPollEvents(); + if (!vkh_presenter_draw(r)) { + vkh_presenter_get_size(r, &test_width, &test_height); + vkvg_surface_destroy(surf); + surf = vkvg_surface_create(device, test_width, test_height); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); + vkDeviceWaitIdle(r->dev->dev); + continue; + } + } + vkDeviceWaitIdle(e->dev->dev); - draw (); + vkvg_surface_destroy(surf); - if (!vkh_presenter_draw (r)){ - vkh_presenter_get_size (r, &test_width, &test_height); - vkvg_surface_destroy (surf); - surf = vkvg_surface_create(device, test_width, test_height); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); - vkDeviceWaitIdle(r->dev->dev); - continue; - } - } - vkDeviceWaitIdle(e->dev->dev); + vkvg_device_destroy(device); - vkvg_surface_destroy (surf); + vkengine_destroy(e); - vkvg_device_destroy (device); - - vkengine_destroy (e); - - return 0; + return 0; } diff --git a/tests/line_caps.c b/tests/line_caps.c index 2ad0129..82a33dc 100644 --- a/tests/line_caps.c +++ b/tests/line_caps.c @@ -1,58 +1,58 @@ #include "test.h" -void test(){ - VkvgContext ctx = vkvg_create(surf); - vkvg_set_source_rgba(ctx,0.9f,0.9f,0.9f,1); - vkvg_paint(ctx); +void test() { + VkvgContext ctx = vkvg_create(surf); + vkvg_set_source_rgba(ctx, 0.9f, 0.9f, 0.9f, 1); + vkvg_paint(ctx); - float x = 20, y = 20, dx = 40, dy = 60; + float x = 20, y = 20, dx = 40, dy = 60; - //vkvg_scale(ctx,5,5); - vkvg_set_line_width(ctx,30); - vkvg_set_source_rgba(ctx,0.0,0.0,0,1); - vkvg_move_to(ctx,x,y); - vkvg_rel_line_to(ctx,0,dy); - vkvg_stroke(ctx); - vkvg_set_line_cap(ctx,VKVG_LINE_CAP_SQUARE); - vkvg_move_to(ctx,x+dx,y); - vkvg_rel_line_to(ctx,0,dy); - vkvg_stroke(ctx); - vkvg_set_line_cap(ctx,VKVG_LINE_CAP_ROUND); - vkvg_move_to(ctx,x+2*dx,y); - vkvg_rel_line_to(ctx,0,dy); - vkvg_rel_move_to(ctx,dx,-dy); - vkvg_rel_line_to(ctx,dx,dy); - vkvg_rel_move_to(ctx,dx,-dy/2.f); - vkvg_rel_line_to(ctx,dx,0); - vkvg_rel_move_to(ctx,dx,dy/2.f); - vkvg_rel_line_to(ctx,dx,-dy); - vkvg_rel_move_to(ctx,dx,dy); - vkvg_rel_line_to(ctx,0,-dy); - vkvg_rel_move_to(ctx,dx*2.f,dy); - vkvg_rel_line_to(ctx,-dx,-dy); - vkvg_rel_move_to(ctx,dx*3.f,dy/2.f); - vkvg_rel_line_to(ctx,-dx,0); - //vkvg_rel_line_to(ctx,0,-dy); - //vkvg_rel_move_to(ctx,dx,dy/2); - //vkvg_rel_line_to(ctx,dx,0); - vkvg_stroke(ctx); + // vkvg_scale(ctx,5,5); + vkvg_set_line_width(ctx, 30); + vkvg_set_source_rgba(ctx, 0.0, 0.0, 0, 1); + vkvg_move_to(ctx, x, y); + vkvg_rel_line_to(ctx, 0, dy); + vkvg_stroke(ctx); + vkvg_set_line_cap(ctx, VKVG_LINE_CAP_SQUARE); + vkvg_move_to(ctx, x + dx, y); + vkvg_rel_line_to(ctx, 0, dy); + vkvg_stroke(ctx); + vkvg_set_line_cap(ctx, VKVG_LINE_CAP_ROUND); + vkvg_move_to(ctx, x + 2 * dx, y); + vkvg_rel_line_to(ctx, 0, dy); + vkvg_rel_move_to(ctx, dx, -dy); + vkvg_rel_line_to(ctx, dx, dy); + vkvg_rel_move_to(ctx, dx, -dy / 2.f); + vkvg_rel_line_to(ctx, dx, 0); + vkvg_rel_move_to(ctx, dx, dy / 2.f); + vkvg_rel_line_to(ctx, dx, -dy); + vkvg_rel_move_to(ctx, dx, dy); + vkvg_rel_line_to(ctx, 0, -dy); + vkvg_rel_move_to(ctx, dx * 2.f, dy); + vkvg_rel_line_to(ctx, -dx, -dy); + vkvg_rel_move_to(ctx, dx * 3.f, dy / 2.f); + vkvg_rel_line_to(ctx, -dx, 0); + // vkvg_rel_line_to(ctx,0,-dy); + // vkvg_rel_move_to(ctx,dx,dy/2); + // vkvg_rel_line_to(ctx,dx,0); + vkvg_stroke(ctx); - vkvg_set_line_cap(ctx,VKVG_LINE_CAP_BUTT); - vkvg_set_line_width(ctx,1); - vkvg_set_source_rgba(ctx,1,0,0,1); - vkvg_move_to(ctx,x,y); - vkvg_rel_line_to(ctx,0,dy); - vkvg_rel_move_to(ctx,dx,-dy); - vkvg_rel_line_to(ctx,0,dy); - vkvg_rel_move_to(ctx,dx,-dy); - vkvg_rel_line_to(ctx,0,dy); - vkvg_stroke(ctx); + vkvg_set_line_cap(ctx, VKVG_LINE_CAP_BUTT); + vkvg_set_line_width(ctx, 1); + vkvg_set_source_rgba(ctx, 1, 0, 0, 1); + vkvg_move_to(ctx, x, y); + vkvg_rel_line_to(ctx, 0, dy); + vkvg_rel_move_to(ctx, dx, -dy); + vkvg_rel_line_to(ctx, 0, dy); + vkvg_rel_move_to(ctx, dx, -dy); + vkvg_rel_line_to(ctx, 0, dy); + vkvg_stroke(ctx); - vkvg_destroy(ctx); + vkvg_destroy(ctx); } int main(int argc, char *argv[]) { - no_test_size = true; - PERFORM_TEST (test, argc, argv); - return 0; + no_test_size = true; + PERFORM_TEST(test, argc, argv); + return 0; } diff --git a/tests/line_join.c b/tests/line_join.c index 779b8cc..f34ad70 100644 --- a/tests/line_join.c +++ b/tests/line_join.c @@ -1,182 +1,180 @@ #include "test.h" -void test(){ - VkvgContext ctx = vkvg_create(surf); - - float x = 250, y = 150; - - //vkvg_scale(ctx,2,2); - - vkvg_set_line_width(ctx,100); - vkvg_set_source_rgba(ctx,0,1,0,1); - - - vkvg_set_line_join(ctx,VKVG_LINE_JOIN_ROUND); - //vkvg_rectangle(ctx,x,y,dx,dy); - - vkvg_move_to(ctx,x,y); - vkvg_rel_line_to(ctx,-50,30); - vkvg_rel_line_to(ctx,0,60); - vkvg_rel_line_to(ctx,50,30); - /* - vkvg_rel_line_to(ctx,50,-30); - vkvg_rel_line_to(ctx,50,0); - vkvg_rel_line_to(ctx,50,30); - vkvg_rel_line_to(ctx,0,60); - vkvg_rel_line_to(ctx,-50,70); - vkvg_rel_line_to(ctx,-50,0); - vkvg_rel_line_to(ctx,-50,-70); - vkvg_close_path(ctx); - vkvg_stroke(ctx); - - vkvg_set_source_rgba(ctx,1,0,0,1); - vkvg_move_to(ctx,x+200,y); - vkvg_rel_line_to(ctx,50,70); - vkvg_rel_line_to(ctx,50,0); - vkvg_rel_line_to(ctx,50,-70); - vkvg_rel_line_to(ctx,0,-60); - vkvg_rel_line_to(ctx,-50,-30); - vkvg_rel_line_to(ctx,-50,0); - vkvg_rel_line_to(ctx,-50,30);*/ - vkvg_close_path(ctx); - vkvg_stroke(ctx); - - vkvg_set_source_rgba(ctx,0,0,1,1); - vkvg_move_to(ctx,x+250,y); - vkvg_rel_line_to(ctx,50,-30); - vkvg_rel_line_to(ctx,50,0); - vkvg_rel_line_to(ctx,50,30); - vkvg_rel_line_to(ctx,0,60); - vkvg_rel_line_to(ctx,-50,70); - vkvg_rel_line_to(ctx,-50,0); - vkvg_rel_line_to(ctx,-50,-70); - vkvg_close_path(ctx); - vkvg_stroke(ctx); - -// float dx = 150, dy = 140; -// vkvg_rel_line_to(ctx,dx,-dy); -// vkvg_rel_line_to(ctx,dx,dy); -// vkvg_stroke(ctx); -// vkvg_set_line_join(ctx,VKVG_LINE_JOIN_BEVEL); -// vkvg_rel_move_to(ctx,-dx*2,abs(dy*1.5)); -// vkvg_rel_line_to(ctx,dx,-dy); -// vkvg_rel_line_to(ctx,dx,dy); -// vkvg_stroke(ctx); -// vkvg_set_line_join(ctx,VKVG_LINE_JOIN_ROUND); -// vkvg_rel_move_to(ctx,-dx*2,abs(dy*1.5)); -// vkvg_rel_line_to(ctx,dx,-dy); -// vkvg_rel_line_to(ctx,dx,dy); -// vkvg_stroke(ctx); -// vkvg_set_line_join(ctx,VKVG_LINE_JOIN_MITER); - - vkvg_destroy(ctx); +void test() { + VkvgContext ctx = vkvg_create(surf); + + float x = 250, y = 150; + + // vkvg_scale(ctx,2,2); + + vkvg_set_line_width(ctx, 100); + vkvg_set_source_rgba(ctx, 0, 1, 0, 1); + + vkvg_set_line_join(ctx, VKVG_LINE_JOIN_ROUND); + // vkvg_rectangle(ctx,x,y,dx,dy); + + vkvg_move_to(ctx, x, y); + vkvg_rel_line_to(ctx, -50, 30); + vkvg_rel_line_to(ctx, 0, 60); + vkvg_rel_line_to(ctx, 50, 30); + /* + vkvg_rel_line_to(ctx,50,-30); + vkvg_rel_line_to(ctx,50,0); + vkvg_rel_line_to(ctx,50,30); + vkvg_rel_line_to(ctx,0,60); + vkvg_rel_line_to(ctx,-50,70); + vkvg_rel_line_to(ctx,-50,0); + vkvg_rel_line_to(ctx,-50,-70); + vkvg_close_path(ctx); + vkvg_stroke(ctx); + + vkvg_set_source_rgba(ctx,1,0,0,1); + vkvg_move_to(ctx,x+200,y); + vkvg_rel_line_to(ctx,50,70); + vkvg_rel_line_to(ctx,50,0); + vkvg_rel_line_to(ctx,50,-70); + vkvg_rel_line_to(ctx,0,-60); + vkvg_rel_line_to(ctx,-50,-30); + vkvg_rel_line_to(ctx,-50,0); + vkvg_rel_line_to(ctx,-50,30);*/ + vkvg_close_path(ctx); + vkvg_stroke(ctx); + + vkvg_set_source_rgba(ctx, 0, 0, 1, 1); + vkvg_move_to(ctx, x + 250, y); + vkvg_rel_line_to(ctx, 50, -30); + vkvg_rel_line_to(ctx, 50, 0); + vkvg_rel_line_to(ctx, 50, 30); + vkvg_rel_line_to(ctx, 0, 60); + vkvg_rel_line_to(ctx, -50, 70); + vkvg_rel_line_to(ctx, -50, 0); + vkvg_rel_line_to(ctx, -50, -70); + vkvg_close_path(ctx); + vkvg_stroke(ctx); + + // float dx = 150, dy = 140; + // vkvg_rel_line_to(ctx,dx,-dy); + // vkvg_rel_line_to(ctx,dx,dy); + // vkvg_stroke(ctx); + // vkvg_set_line_join(ctx,VKVG_LINE_JOIN_BEVEL); + // vkvg_rel_move_to(ctx,-dx*2,abs(dy*1.5)); + // vkvg_rel_line_to(ctx,dx,-dy); + // vkvg_rel_line_to(ctx,dx,dy); + // vkvg_stroke(ctx); + // vkvg_set_line_join(ctx,VKVG_LINE_JOIN_ROUND); + // vkvg_rel_move_to(ctx,-dx*2,abs(dy*1.5)); + // vkvg_rel_line_to(ctx,dx,-dy); + // vkvg_rel_line_to(ctx,dx,dy); + // vkvg_stroke(ctx); + // vkvg_set_line_join(ctx,VKVG_LINE_JOIN_MITER); + + vkvg_destroy(ctx); } void test2() { - VkvgContext ctx = vkvg_create(surf); - - vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_EVEN_ODD); - vkvg_set_line_width(ctx, 30); - - vkvg_set_line_join(ctx, VKVG_LINE_JOIN_ROUND); - - //vkvg_arc (ctx, 200, 500, 100, 0, M_PI); - - vkvg_translate(ctx, -50, -50); - - vkvg_set_source_rgb(ctx, 0.5, 0, 0); - - for (int j = 0; j < 2; j++) { - int i = 0; - vkvg_move_to(ctx, 100, 100); - for (i = 0; i < 5; i++) { - vkvg_rel_line_to(ctx, 70, 50); - vkvg_rel_line_to(ctx, -70, 50); - } - vkvg_stroke(ctx); - - vkvg_move_to(ctx, 200, 600); - for (i = 0; i < 5; i++) { - vkvg_rel_line_to(ctx, 70, -50); - vkvg_rel_line_to(ctx, -70, -50); - } - vkvg_stroke(ctx); - - vkvg_move_to(ctx, 400, 100); - for (i = 0; i < 5; i++) { - vkvg_rel_line_to(ctx, -70, 50); - vkvg_rel_line_to(ctx, 70, 50); - } - vkvg_stroke(ctx); - - vkvg_move_to(ctx, 500, 600); - for (i = 0; i < 5; i++) { - vkvg_rel_line_to(ctx, -70, -50); - vkvg_rel_line_to(ctx, 70, -50); - } - vkvg_stroke(ctx); - vkvg_set_line_join(ctx, VKVG_LINE_JOIN_BEVEL); - vkvg_translate(ctx, 500, 0); - } - - vkvg_destroy(ctx); + VkvgContext ctx = vkvg_create(surf); + + vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_EVEN_ODD); + vkvg_set_line_width(ctx, 30); + + vkvg_set_line_join(ctx, VKVG_LINE_JOIN_ROUND); + + // vkvg_arc (ctx, 200, 500, 100, 0, M_PI); + + vkvg_translate(ctx, -50, -50); + + vkvg_set_source_rgb(ctx, 0.5, 0, 0); + + for (int j = 0; j < 2; j++) { + int i = 0; + vkvg_move_to(ctx, 100, 100); + for (i = 0; i < 5; i++) { + vkvg_rel_line_to(ctx, 70, 50); + vkvg_rel_line_to(ctx, -70, 50); + } + vkvg_stroke(ctx); + + vkvg_move_to(ctx, 200, 600); + for (i = 0; i < 5; i++) { + vkvg_rel_line_to(ctx, 70, -50); + vkvg_rel_line_to(ctx, -70, -50); + } + vkvg_stroke(ctx); + + vkvg_move_to(ctx, 400, 100); + for (i = 0; i < 5; i++) { + vkvg_rel_line_to(ctx, -70, 50); + vkvg_rel_line_to(ctx, 70, 50); + } + vkvg_stroke(ctx); + + vkvg_move_to(ctx, 500, 600); + for (i = 0; i < 5; i++) { + vkvg_rel_line_to(ctx, -70, -50); + vkvg_rel_line_to(ctx, 70, -50); + } + vkvg_stroke(ctx); + vkvg_set_line_join(ctx, VKVG_LINE_JOIN_BEVEL); + vkvg_translate(ctx, 500, 0); + } + + vkvg_destroy(ctx); } void test3() { - VkvgContext ctx = vkvg_create(surf); - - vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_EVEN_ODD); - vkvg_set_line_width(ctx, 30); - - vkvg_set_line_join(ctx, VKVG_LINE_JOIN_ROUND); - - //vkvg_arc (ctx, 200, 500, 100, 0, M_PI); - - vkvg_translate(ctx, -50, -50); - - vkvg_set_source_rgb(ctx, 0.5, 0, 0); - - for (int j = 0; j < 2; j++) { - int i = 0; - vkvg_move_to(ctx, 100, 100); - for (i = 0; i < 4; i++) { - vkvg_rel_line_to(ctx, 50, 70); - vkvg_rel_line_to(ctx, 50, -70); - } - vkvg_stroke(ctx); - - vkvg_move_to(ctx, 500, 200); - for (i = 0; i < 4; i++) { - vkvg_rel_line_to(ctx, -50, 70); - vkvg_rel_line_to(ctx, -50, -70); - } - vkvg_stroke(ctx); - - vkvg_move_to(ctx, 100, 400); - for (i = 0; i < 4; i++) { - vkvg_rel_line_to(ctx, 50, -70); - vkvg_rel_line_to(ctx, 50, 70); - } - vkvg_stroke(ctx); - - vkvg_move_to(ctx, 500, 500); - for (i = 0; i < 4; i++) { - vkvg_rel_line_to(ctx, -50, -70); - vkvg_rel_line_to(ctx, -50, 70); - } - vkvg_stroke(ctx); - vkvg_set_line_join(ctx, VKVG_LINE_JOIN_BEVEL); - vkvg_translate(ctx, 450, 0); - } - - vkvg_destroy(ctx); + VkvgContext ctx = vkvg_create(surf); + + vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_EVEN_ODD); + vkvg_set_line_width(ctx, 30); + + vkvg_set_line_join(ctx, VKVG_LINE_JOIN_ROUND); + + // vkvg_arc (ctx, 200, 500, 100, 0, M_PI); + + vkvg_translate(ctx, -50, -50); + + vkvg_set_source_rgb(ctx, 0.5, 0, 0); + + for (int j = 0; j < 2; j++) { + int i = 0; + vkvg_move_to(ctx, 100, 100); + for (i = 0; i < 4; i++) { + vkvg_rel_line_to(ctx, 50, 70); + vkvg_rel_line_to(ctx, 50, -70); + } + vkvg_stroke(ctx); + + vkvg_move_to(ctx, 500, 200); + for (i = 0; i < 4; i++) { + vkvg_rel_line_to(ctx, -50, 70); + vkvg_rel_line_to(ctx, -50, -70); + } + vkvg_stroke(ctx); + + vkvg_move_to(ctx, 100, 400); + for (i = 0; i < 4; i++) { + vkvg_rel_line_to(ctx, 50, -70); + vkvg_rel_line_to(ctx, 50, 70); + } + vkvg_stroke(ctx); + + vkvg_move_to(ctx, 500, 500); + for (i = 0; i < 4; i++) { + vkvg_rel_line_to(ctx, -50, -70); + vkvg_rel_line_to(ctx, -50, 70); + } + vkvg_stroke(ctx); + vkvg_set_line_join(ctx, VKVG_LINE_JOIN_BEVEL); + vkvg_translate(ctx, 450, 0); + } + + vkvg_destroy(ctx); } - int main(int argc, char *argv[]) { - no_test_size = true; - PERFORM_TEST(test, argc, argv); - PERFORM_TEST(test2, argc, argv); - PERFORM_TEST(test3, argc, argv); - return 0; + no_test_size = true; + PERFORM_TEST(test, argc, argv); + PERFORM_TEST(test2, argc, argv); + PERFORM_TEST(test3, argc, argv); + return 0; } diff --git a/tests/lines.c b/tests/lines.c index ef26d85..efd7e3d 100644 --- a/tests/lines.c +++ b/tests/lines.c @@ -1,110 +1,110 @@ #include "test.h" void horizontal() { - float w = (float)test_width; - float h = (float)test_height; - - VkvgContext ctx = _initCtx(); - - for (uint32_t i=0; i=0) { - if (isClosed) - vkvg_fill_preserve(ctx); - vkvg_set_source_rgba(ctx,1,0.2,0.2,0.5); - vkvg_stroke_preserve(ctx); - vkvg_set_dash(ctx, NULL, 0, 0); - vkvg_set_line_width(ctx,1); - vkvg_set_source_rgba(ctx,0,0,0,1); - vkvg_stroke(ctx); - vkvg_set_source_rgba(ctx,0.5f,0.5f,1.0f,0.7f); - vkvg_arc (ctx, pts[hoverPt].x, pts[hoverPt].y, pointSize, 0, M_PIF*2); - vkvg_fill_preserve(ctx); - vkvg_stroke(ctx); - } else { - if (isClosed) - vkvg_fill_preserve(ctx); - vkvg_set_source_rgba(ctx,1,0.2,0.2,0.5); - vkvg_stroke(ctx); - } - - vkvg_rectangle(ctx, x1, y1, x2 - x1, y2 - y1); - vkvg_set_dash(ctx, _dashes, _ndashes, 0); - vkvg_set_line_width(ctx,1); - vkvg_set_source_rgba(ctx,0,1,0,1); - vkvg_stroke(ctx); - - vkvg_destroy(ctx); +void draw() { + refresh = false; + + VkvgContext ctx = vkvg_create(surf); + vkvg_clear(ctx); + vkvg_set_source_rgba(ctx, 1, 0, 0, 1); + vkvg_set_line_width(ctx, lineWidth); + vkvg_set_line_join(ctx, lineJoin); + vkvg_set_line_cap(ctx, lineCap); + + emit_path(ctx); + float x1, y1, x2, y2; + vkvg_path_extents(ctx, &x1, &y1, &x2, &y2); + vkvg_set_source_rgba(ctx, 0.2, 0.2, 1, 0.5); + if (hoverPt >= 0) { + if (isClosed) + vkvg_fill_preserve(ctx); + vkvg_set_source_rgba(ctx, 1, 0.2, 0.2, 0.5); + vkvg_stroke_preserve(ctx); + vkvg_set_dash(ctx, NULL, 0, 0); + vkvg_set_line_width(ctx, 1); + vkvg_set_source_rgba(ctx, 0, 0, 0, 1); + vkvg_stroke(ctx); + vkvg_set_source_rgba(ctx, 0.5f, 0.5f, 1.0f, 0.7f); + vkvg_arc(ctx, pts[hoverPt].x, pts[hoverPt].y, pointSize, 0, M_PIF * 2); + vkvg_fill_preserve(ctx); + vkvg_stroke(ctx); + } else { + if (isClosed) + vkvg_fill_preserve(ctx); + vkvg_set_source_rgba(ctx, 1, 0.2, 0.2, 0.5); + vkvg_stroke(ctx); + } + + vkvg_rectangle(ctx, x1, y1, x2 - x1, y2 - y1); + vkvg_set_dash(ctx, _dashes, _ndashes, 0); + vkvg_set_line_width(ctx, 1); + vkvg_set_source_rgba(ctx, 0, 1, 0, 1); + vkvg_stroke(ctx); + + vkvg_destroy(ctx); } -static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { - if (action != GLFW_PRESS) - return; - switch (key) { - case GLFW_KEY_ESCAPE : - glfwSetWindowShouldClose(window, GLFW_TRUE); - break; - case GLFW_KEY_W : - isClosed ^= true; - break; - case GLFW_KEY_DELETE : - ptsCount = 0; - break; - case GLFW_KEY_J : - lineJoin++; - if (lineJoin > 2) - lineJoin = 0; - break; - case GLFW_KEY_C : - lineCap++; - if (lineCap > 2) - lineCap = 0; - break; - case GLFW_KEY_KP_SUBTRACT : - if (ptsCount > 1) - ptsCount--; - break; - } - refresh = true; +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { + if (action != GLFW_PRESS) + return; + switch (key) { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GLFW_TRUE); + break; + case GLFW_KEY_W: + isClosed ^= true; + break; + case GLFW_KEY_DELETE: + ptsCount = 0; + break; + case GLFW_KEY_J: + lineJoin++; + if (lineJoin > 2) + lineJoin = 0; + break; + case GLFW_KEY_C: + lineCap++; + if (lineCap > 2) + lineCap = 0; + break; + case GLFW_KEY_KP_SUBTRACT: + if (ptsCount > 1) + ptsCount--; + break; + } + refresh = true; } static vec2 mousePos; -static void mouse_move_callback(GLFWwindow* window, double x, double y){ - mousePos = (vec2) {x, y}; - if (mouseDown) { - if (hoverPt < 0) - return; - pts[hoverPt] = mousePos; - refresh = true; - } else { - for (int i=0; i pts[i].x - pointSize && - x < pts[i].x + pointSize && - y > pts[i].y - pointSize && - y < pts[i].y + pointSize) { - hoverPt = i; - refresh = true; - return; - } - } - refresh = true; - hoverPt = -1; - } +static void mouse_move_callback(GLFWwindow *window, double x, double y) { + mousePos = (vec2){x, y}; + if (mouseDown) { + if (hoverPt < 0) + return; + pts[hoverPt] = mousePos; + refresh = true; + } else { + for (int i = 0; i < ptsCount; i++) { + if (x > pts[i].x - pointSize && x < pts[i].x + pointSize && y > pts[i].y - pointSize && + y < pts[i].y + pointSize) { + hoverPt = i; + refresh = true; + return; + } + } + refresh = true; + hoverPt = -1; + } } -static void scroll_callback(GLFWwindow* window, double x, double y){ - if (y<0.f) - zoom *= 0.5f; - else - zoom *= 2.0f; +static void scroll_callback(GLFWwindow *window, double x, double y) { + if (y < 0.f) + zoom *= 0.5f; + else + zoom *= 2.0f; } -static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif){ - if (but != GLFW_MOUSE_BUTTON_1) - return; - if (state == GLFW_TRUE) - mouseDown = true; - else - mouseDown = false; - if (state == GLFW_TRUE && hoverPt < 0) - pts[ptsCount++] = mousePos; - refresh = true; +static void mouse_button_callback(GLFWwindow *window, int but, int state, int modif) { + if (but != GLFW_MOUSE_BUTTON_1) + return; + if (state == GLFW_TRUE) + mouseDown = true; + else + mouseDown = false; + if (state == GLFW_TRUE && hoverPt < 0) + pts[ptsCount++] = mousePos; + refresh = true; } +int main(int argc, char *argv[]) { + _parse_args(argc, argv); + VkEngine e; + e = vkengine_create(VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); -int main(int argc, char* argv[]) { + VkhPresenter r = e->renderer; + vkengine_set_key_callback(e, key_callback); + vkengine_set_mouse_but_callback(e, mouse_button_callback); + vkengine_set_cursor_pos_callback(e, mouse_move_callback); + vkengine_set_scroll_callback(e, scroll_callback); - _parse_args (argc, argv); - VkEngine e; - e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); + vkvg_device_create_info_t info = {samples, false, vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0}; + device = vkvg_device_create(&info); + surf = vkvg_surface_create(device, test_width, test_height); - VkhPresenter r = e->renderer; - vkengine_set_key_callback (e, key_callback); - vkengine_set_mouse_but_callback(e, mouse_button_callback); - vkengine_set_cursor_pos_callback(e, mouse_move_callback); - vkengine_set_scroll_callback(e, scroll_callback); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); - vkvg_device_create_info_t info = { - samples, - false, - vkh_app_get_inst(e->app), - r->dev->phy, - r->dev->dev, - r->qFam, - 0 - }; - device = vkvg_device_create(&info); - surf = vkvg_surface_create(device, test_width, test_height); + while (!vkengine_should_close(e)) { + glfwPollEvents(); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); + if (refresh) + draw(); - while (!vkengine_should_close (e)) { - glfwPollEvents(); + if (!vkh_presenter_draw(r)) { + vkh_presenter_get_size(r, &test_width, &test_height); + vkvg_surface_destroy(surf); + surf = vkvg_surface_create(device, test_width, test_height); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); + vkDeviceWaitIdle(r->dev->dev); + continue; + } + } + vkDeviceWaitIdle(e->dev->dev); - if (refresh) - draw (); + vkvg_surface_destroy(surf); - if (!vkh_presenter_draw (r)){ - vkh_presenter_get_size (r, &test_width, &test_height); - vkvg_surface_destroy (surf); - surf = vkvg_surface_create(device, test_width, test_height); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); - vkDeviceWaitIdle(r->dev->dev); - continue; - } - } - vkDeviceWaitIdle(e->dev->dev); + vkvg_device_destroy(device); - vkvg_surface_destroy (surf); + vkengine_destroy(e); - vkvg_device_destroy (device); - - vkengine_destroy (e); - - return 0; + return 0; } diff --git a/tests/pattern_transforms.c b/tests/pattern_transforms.c index 18e528a..58651c9 100644 --- a/tests/pattern_transforms.c +++ b/tests/pattern_transforms.c @@ -1,93 +1,93 @@ #include "test.h" -float lineWidth = 10.f; -const char* imgPath = "data/miroir.jpg"; - -VkvgPattern create_grad (VkvgContext ctx) { - VkvgPattern pat = vkvg_pattern_create_linear(0,0,200,0); - vkvg_pattern_add_color_stop(pat, 0, 1, 0, 0, 1); - vkvg_pattern_add_color_stop(pat, 0.5, 0, 1, 0, 1); - vkvg_pattern_add_color_stop(pat, 1.0, 0, 0, 1, 1); - return pat; +float lineWidth = 10.f; +const char *imgPath = "data/miroir.jpg"; + +VkvgPattern create_grad(VkvgContext ctx) { + VkvgPattern pat = vkvg_pattern_create_linear(0, 0, 200, 0); + vkvg_pattern_add_color_stop(pat, 0, 1, 0, 0, 1); + vkvg_pattern_add_color_stop(pat, 0.5, 0, 1, 0, 1); + vkvg_pattern_add_color_stop(pat, 1.0, 0, 0, 1, 1); + return pat; } -VkvgSurface createSurf (uint32_t width, uint32_t height) { - VkvgSurface s = vkvg_surface_create(device, width, height); - VkvgContext ctx = _initCtx(surf); - vkvg_set_line_width(ctx,lineWidth); - float hlw = lineWidth/2.f; - /* - vkvg_set_source_rgba(ctx,0,1,0,0.5); - vkvg_fill_preserve(ctx);*/ - vkvg_set_source_rgba(ctx,1,0,0,0.5); - vkvg_paint(ctx); - vkvg_set_source_rgba(ctx,0,0,1,0.5); - vkvg_rectangle(ctx,hlw,hlw,(float)width-lineWidth,(float)height-lineWidth); - vkvg_stroke(ctx); - vkvg_destroy(ctx); - return s; +VkvgSurface createSurf(uint32_t width, uint32_t height) { + VkvgSurface s = vkvg_surface_create(device, width, height); + VkvgContext ctx = _initCtx(surf); + vkvg_set_line_width(ctx, lineWidth); + float hlw = lineWidth / 2.f; + /* + vkvg_set_source_rgba(ctx,0,1,0,0.5); + vkvg_fill_preserve(ctx);*/ + vkvg_set_source_rgba(ctx, 1, 0, 0, 0.5); + vkvg_paint(ctx); + vkvg_set_source_rgba(ctx, 0, 0, 1, 0.5); + vkvg_rectangle(ctx, hlw, hlw, (float)width - lineWidth, (float)height - lineWidth); + vkvg_stroke(ctx); + vkvg_destroy(ctx); + return s; } void img_scale() { - VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); - VkvgPattern pat = vkvg_pattern_create_for_surface(imgSurf); - VkvgContext ctx = _initCtx(surf); - - vkvg_translate(ctx, 100,100); - - vkvg_matrix_t mat; - vkvg_matrix_init_scale(&mat, 2.0, 2.0); - vkvg_pattern_set_matrix (pat, &mat); - - vkvg_set_source (ctx, pat); - vkvg_rectangle(ctx, 0 , 0, 200, 140); - vkvg_fill(ctx); - vkvg_destroy(ctx); - vkvg_pattern_destroy(pat); - vkvg_surface_destroy(imgSurf); + VkvgSurface imgSurf = vkvg_surface_create_from_image(device, imgPath); + VkvgPattern pat = vkvg_pattern_create_for_surface(imgSurf); + VkvgContext ctx = _initCtx(surf); + + vkvg_translate(ctx, 100, 100); + + vkvg_matrix_t mat; + vkvg_matrix_init_scale(&mat, 2.0, 2.0); + vkvg_pattern_set_matrix(pat, &mat); + + vkvg_set_source(ctx, pat); + vkvg_rectangle(ctx, 0, 0, 200, 140); + vkvg_fill(ctx); + vkvg_destroy(ctx); + vkvg_pattern_destroy(pat); + vkvg_surface_destroy(imgSurf); } -void pat_scale(){ +void pat_scale() { - VkvgContext ctx = _initCtx(surf); - VkvgPattern pat = create_grad(ctx); + VkvgContext ctx = _initCtx(surf); + VkvgPattern pat = create_grad(ctx); - vkvg_translate(ctx, 100,100); + vkvg_translate(ctx, 100, 100); - vkvg_matrix_t mat; - vkvg_matrix_init_scale(&mat, 0.5, 0.5); - vkvg_pattern_set_matrix (pat, &mat); + vkvg_matrix_t mat; + vkvg_matrix_init_scale(&mat, 0.5, 0.5); + vkvg_pattern_set_matrix(pat, &mat); - vkvg_set_source (ctx, pat); - vkvg_rectangle(ctx, 0 , 0, 200, 140); - vkvg_fill(ctx); - vkvg_destroy(ctx); - vkvg_pattern_destroy(pat); + vkvg_set_source(ctx, pat); + vkvg_rectangle(ctx, 0, 0, 200, 140); + vkvg_fill(ctx); + vkvg_destroy(ctx); + vkvg_pattern_destroy(pat); } static float angle = 0; -void pat_rotate(){ - angle += 0.001f; +void pat_rotate() { + angle += 0.001f; - VkvgContext ctx = _initCtx(surf); - VkvgPattern pat = create_grad(ctx); + VkvgContext ctx = _initCtx(surf); + VkvgPattern pat = create_grad(ctx); - //vkvg_translate(ctx, 100,100); + // vkvg_translate(ctx, 100,100); - vkvg_matrix_t mat; - vkvg_matrix_init_translate(&mat, 100, 70); - vkvg_matrix_rotate(&mat, angle); - vkvg_pattern_set_matrix (pat, &mat); + vkvg_matrix_t mat; + vkvg_matrix_init_translate(&mat, 100, 70); + vkvg_matrix_rotate(&mat, angle); + vkvg_pattern_set_matrix(pat, &mat); - vkvg_set_source (ctx, pat); - vkvg_rectangle(ctx, 0 , 0, 200, 140); - vkvg_fill(ctx); - vkvg_destroy(ctx); - vkvg_pattern_destroy(pat); + vkvg_set_source(ctx, pat); + vkvg_rectangle(ctx, 0, 0, 200, 140); + vkvg_fill(ctx); + vkvg_destroy(ctx); + vkvg_pattern_destroy(pat); } int main(int argc, char *argv[]) { - no_test_size = true; - PERFORM_TEST (pat_scale, argc, argv); - PERFORM_TEST (pat_rotate, argc, argv); - PERFORM_TEST (img_scale, argc, argv); - return 0; + no_test_size = true; + PERFORM_TEST(pat_scale, argc, argv); + PERFORM_TEST(pat_rotate, argc, argv); + PERFORM_TEST(img_scale, argc, argv); + return 0; } diff --git a/tests/perfs/random_rects.c b/tests/perfs/random_rects.c index e5b1dc4..4762b5e 100644 --- a/tests/perfs/random_rects.c +++ b/tests/perfs/random_rects.c @@ -1,25 +1,25 @@ #include "test.h" -void drawRandomRect (VkvgContext ctx, float s) { - float w = (float)test_width; - float h = (float)test_height; - randomize_color(ctx); +void drawRandomRect(VkvgContext ctx, float s) { + float w = (float)test_width; + float h = (float)test_height; + randomize_color(ctx); - float x = truncf(w*rndf()); - float y = truncf(h*rndf()); + float x = truncf(w * rndf()); + float y = truncf(h * rndf()); - vkvg_rectangle(ctx, x, y, s, s); + vkvg_rectangle(ctx, x, y, s, s); } -void fixedSizeRects(){ - VkvgContext ctx = _initCtx (); - for (uint32_t i=0; irenderer; + vkengine_set_key_callback(e, key_callback); + vkengine_set_mouse_but_callback(e, mouse_button_callback); + vkengine_set_cursor_pos_callback(e, mouse_move_callback); + vkengine_set_scroll_callback(e, scroll_callback); - _parse_args (argc, argv); - VkEngine e; - e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); + bool deferredResolve = false; - VkhPresenter r = e->renderer; - vkengine_set_key_callback (e, key_callback); - vkengine_set_mouse_but_callback(e, mouse_button_callback); - vkengine_set_cursor_pos_callback(e, mouse_move_callback); - vkengine_set_scroll_callback(e, scroll_callback); + device = vkvg_device_create_from_vk_multisample(vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0, + samples, deferredResolve); + surf = vkvg_surface_create(device, test_width, test_height); - bool deferredResolve = false; + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); - device = vkvg_device_create_from_vk_multisample(vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0, samples, deferredResolve); - surf = vkvg_surface_create(device, test_width, test_height); + mouse = (vec2){test_width * 0.75, test_height * 0.5f}; - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); + while (!vkengine_should_close(e)) { + glfwPollEvents(); - mouse = (vec2){test_width*0.75,test_height*0.5f}; + draw(); - while (!vkengine_should_close (e)) { - glfwPollEvents(); + if (!vkh_presenter_draw(r)) { + vkh_presenter_get_size(r, &test_width, &test_height); + vkvg_surface_destroy(surf); + surf = vkvg_surface_create(device, test_width, test_height); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); + vkDeviceWaitIdle(r->dev->dev); + continue; + } + } + vkDeviceWaitIdle(e->dev->dev); - draw (); + vkvg_surface_destroy(surf); - if (!vkh_presenter_draw (r)){ - vkh_presenter_get_size (r, &test_width, &test_height); - vkvg_surface_destroy (surf); - surf = vkvg_surface_create(device, test_width, test_height); - vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); - vkDeviceWaitIdle(r->dev->dev); - continue; - } - } - vkDeviceWaitIdle(e->dev->dev); + vkvg_device_destroy(device); - vkvg_surface_destroy (surf); + vkengine_destroy(e); - vkvg_device_destroy (device); - - vkengine_destroy (e); - - return 0; + return 0; } diff --git a/tests/transform.c b/tests/transform.c index b89db50..cc282b0 100644 --- a/tests/transform.c +++ b/tests/transform.c @@ -22,95 +22,89 @@ #include "test.h" - -void _test_rounded_rect (VkvgContext cr) { - /* a custom shape that could be wrapped in a function */ - float x0 = -100, /* parameters like vkvg_rectangle */ - y0 = -100, - rect_width = 200, - rect_height = 200, - radius = 102.4f; /* and an approximate curvature radius */ - - float x1,y1; - - x1=x0+rect_width; - y1=y0+rect_height; - if (!rect_width || !rect_height) - return; - if (rect_width/2 #include -static VkvgDevice dev; +static VkvgDevice dev; static VkvgSurface svgSurf = NULL; -static double scale = 1; - - -static char* filename = NULL; -static char* directory = NULL; -static DIR * pCurrentDir = NULL; -struct dirent *dir = NULL; -static int iconSize = -1; -static VkSampleCountFlags samples = VK_SAMPLE_COUNT_8_BIT; -static uint32_t width=512, height=512, margin = 10; -static double scrollX, scrollY; -static bool paused = false, repaintIconList = true; - +static double scale = 1; + +static char *filename = NULL; +static char *directory = NULL; +static DIR *pCurrentDir = NULL; +struct dirent *dir = NULL; +static int iconSize = -1; +static VkSampleCountFlags samples = VK_SAMPLE_COUNT_8_BIT; +static uint32_t width = 512, height = 512, margin = 10; +static double scrollX, scrollY; +static bool paused = false, repaintIconList = true; struct stat file_stat; -#define NORMAL_COLOR "\x1B[0m" -#define GREEN "\x1B[32m" -#define BLUE "\x1B[34m" +#define NORMAL_COLOR "\x1B[0m" +#define GREEN "\x1B[32m" +#define BLUE "\x1B[34m" -static int svg_file_count; +static int svg_file_count; static float maxScroll; /* not defined in c11, ok to define here only for sample */ #ifndef DT_DIR - # define DT_DIR 4 +#define DT_DIR 4 #endif -int _count_svg_files () { - struct dirent *de; - rewinddir (pCurrentDir); - int i = 0; - while ((de = readdir(pCurrentDir)) != NULL) { - if(de->d_type != DT_DIR && !strcasecmp(strrchr(de->d_name, '\0') - 4, ".svg")) - i++; - } - return i; +int _count_svg_files() { + struct dirent *de; + rewinddir(pCurrentDir); + int i = 0; + while ((de = readdir(pCurrentDir)) != NULL) { + if (de->d_type != DT_DIR && !strcasecmp(strrchr(de->d_name, '\0') - 4, ".svg")) + i++; + } + return i; } -void readSVG (VkEngine e) { - struct stat sb; - VkvgSurface newSvgSurf = NULL; - if (iconSize > 0 && pCurrentDir) { - if (!repaintIconList) - return; - char tmp[FILENAME_MAX]; - double x = 0, y = 0; - int cellSize = iconSize + margin; - int iconPerLine = ceil((double)(width-iconSize) / cellSize); - int lineToSkip = floor(scrollY / cellSize); - int iconToSkip = lineToSkip * iconPerLine; - - y = (lineToSkip * cellSize) - scrollY; - - newSvgSurf = vkvg_surface_create(dev, width, height); - VkvgContext ctx = vkvg_create(newSvgSurf); - - struct dirent *de; - rewinddir (pCurrentDir); - int i = 0; - while ((de = readdir(pCurrentDir)) != NULL) { - if(de->d_type != DT_DIR) { - if (!strcasecmp(strrchr(de->d_name, '\0') - 4, ".svg")) { - if (i >= iconToSkip) { - sprintf(tmp, "%s%s", directory, de->d_name); - VkvgSurface surf = vkvg_surface_create_from_svg (dev, iconSize, iconSize, tmp); - - if (surf) { - vkvg_set_source_surface(ctx, surf, x, y); - vkvg_paint(ctx); - vkvg_surface_destroy(surf); - } - x += iconSize + margin; - if (x > width - iconSize) { - x = 0; - y += iconSize + margin; - if (y >= height) - break; - } - } - i++; - } - } - } - vkvg_destroy(ctx); - repaintIconList = false; - }else if (filename) { - vkengine_set_title(e, filename); - if (stat(filename, &sb) == -1) { - printf ("Unable to stat file: %s\n", filename); - exit(EXIT_FAILURE); - } - if (sb.st_mtime == file_stat.st_mtime) - return; - file_stat = sb; - newSvgSurf = vkvg_surface_create_from_svg(dev, width, height, filename); - } else if (dir) { - char tmp[FILENAME_MAX]; - sprintf(tmp, "%s/%s", directory, dir->d_name); - vkengine_set_title(e, tmp); - if (stat(tmp, &sb) == -1) { - printf ("Unable to stat file: %s\n", tmp); - exit(EXIT_FAILURE); - } - if (sb.st_mtime == file_stat.st_mtime) - return; - file_stat = sb; - newSvgSurf = vkvg_surface_create_from_svg(dev, width, height, tmp); - } - - //vkengine_wait_idle(e); - - if (svgSurf) - vkvg_surface_destroy(svgSurf); - svgSurf = newSvgSurf; - - //vkengine_wait_idle(e); +void readSVG(VkEngine e) { + struct stat sb; + VkvgSurface newSvgSurf = NULL; + if (iconSize > 0 && pCurrentDir) { + if (!repaintIconList) + return; + char tmp[FILENAME_MAX]; + double x = 0, y = 0; + int cellSize = iconSize + margin; + int iconPerLine = ceil((double)(width - iconSize) / cellSize); + int lineToSkip = floor(scrollY / cellSize); + int iconToSkip = lineToSkip * iconPerLine; + + y = (lineToSkip * cellSize) - scrollY; + + newSvgSurf = vkvg_surface_create(dev, width, height); + VkvgContext ctx = vkvg_create(newSvgSurf); + + struct dirent *de; + rewinddir(pCurrentDir); + int i = 0; + while ((de = readdir(pCurrentDir)) != NULL) { + if (de->d_type != DT_DIR) { + if (!strcasecmp(strrchr(de->d_name, '\0') - 4, ".svg")) { + if (i >= iconToSkip) { + sprintf(tmp, "%s%s", directory, de->d_name); + VkvgSurface surf = vkvg_surface_create_from_svg(dev, iconSize, iconSize, tmp); + + if (surf) { + vkvg_set_source_surface(ctx, surf, x, y); + vkvg_paint(ctx); + vkvg_surface_destroy(surf); + } + x += iconSize + margin; + if (x > width - iconSize) { + x = 0; + y += iconSize + margin; + if (y >= height) + break; + } + } + i++; + } + } + } + vkvg_destroy(ctx); + repaintIconList = false; + } else if (filename) { + vkengine_set_title(e, filename); + if (stat(filename, &sb) == -1) { + printf("Unable to stat file: %s\n", filename); + exit(EXIT_FAILURE); + } + if (sb.st_mtime == file_stat.st_mtime) + return; + file_stat = sb; + newSvgSurf = vkvg_surface_create_from_svg(dev, width, height, filename); + } else if (dir) { + char tmp[FILENAME_MAX]; + sprintf(tmp, "%s/%s", directory, dir->d_name); + vkengine_set_title(e, tmp); + if (stat(tmp, &sb) == -1) { + printf("Unable to stat file: %s\n", tmp); + exit(EXIT_FAILURE); + } + if (sb.st_mtime == file_stat.st_mtime) + return; + file_stat = sb; + newSvgSurf = vkvg_surface_create_from_svg(dev, width, height, tmp); + } + + // vkengine_wait_idle(e); + + if (svgSurf) + vkvg_surface_destroy(svgSurf); + svgSurf = newSvgSurf; + + // vkengine_wait_idle(e); #ifdef VKVG_DBG_STATS - vkvg_debug_stats_t dbgStats = vkvg_device_get_stats (dev); - vkvg_device_reset_stats (dev); - printf("maximum point array size = %d\n", dbgStats.sizePoints); - printf("maximum path array size = %d\n", dbgStats.sizePathes); - printf("maximum size of host vertice cache = %d\n", dbgStats.sizeVertices); - printf("maximum size of host index cache = %d\n", dbgStats.sizeIndices); - printf("maximum size of vulkan vertex buffer = %d\n", dbgStats.sizeVBO); - printf("maximum size of vulkan index buffer = %d\n", dbgStats.sizeIBO); + vkvg_debug_stats_t dbgStats = vkvg_device_get_stats(dev); + vkvg_device_reset_stats(dev); + printf("maximum point array size = %d\n", dbgStats.sizePoints); + printf("maximum path array size = %d\n", dbgStats.sizePathes); + printf("maximum size of host vertice cache = %d\n", dbgStats.sizeVertices); + printf("maximum size of host index cache = %d\n", dbgStats.sizeIndices); + printf("maximum size of vulkan vertex buffer = %d\n", dbgStats.sizeVBO); + printf("maximum size of vulkan index buffer = %d\n", dbgStats.sizeIBO); #endif - } -struct dirent *get_next_svg_file_in_current_directory (bool cycle) { - struct dirent *de; - while ((de = readdir(pCurrentDir)) != NULL) { - if(de->d_type != DT_DIR) { - if (!strcasecmp(strrchr(de->d_name, '\0') - 4, ".svg")) - return de; - } - } - if (!cycle) - return NULL; - rewinddir (pCurrentDir); - return get_next_svg_file_in_current_directory (false); +struct dirent *get_next_svg_file_in_current_directory(bool cycle) { + struct dirent *de; + while ((de = readdir(pCurrentDir)) != NULL) { + if (de->d_type != DT_DIR) { + if (!strcasecmp(strrchr(de->d_name, '\0') - 4, ".svg")) + return de; + } + } + if (!cycle) + return NULL; + rewinddir(pCurrentDir); + return get_next_svg_file_in_current_directory(false); } - -static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { - if (action == GLFW_RELEASE) - return; - switch (key) { - case GLFW_KEY_SPACE: - paused = !paused; - break; - case GLFW_KEY_R: - //recording = !recording; - file_stat = (struct stat){0}; - break; - case GLFW_KEY_ESCAPE : - glfwSetWindowShouldClose(window, GLFW_TRUE); - break; - case GLFW_KEY_ENTER : - if (!pCurrentDir) - break; - dir = get_next_svg_file_in_current_directory(true); - file_stat = (struct stat){0}; - break; - case GLFW_KEY_KP_ADD: - scale*=2.0; - file_stat = (struct stat){0}; - break; - case GLFW_KEY_KP_SUBTRACT: - scale/=2.0; - file_stat = (struct stat){0}; - break; - } +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { + if (action == GLFW_RELEASE) + return; + switch (key) { + case GLFW_KEY_SPACE: + paused = !paused; + break; + case GLFW_KEY_R: + // recording = !recording; + file_stat = (struct stat){0}; + break; + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GLFW_TRUE); + break; + case GLFW_KEY_ENTER: + if (!pCurrentDir) + break; + dir = get_next_svg_file_in_current_directory(true); + file_stat = (struct stat){0}; + break; + case GLFW_KEY_KP_ADD: + scale *= 2.0; + file_stat = (struct stat){0}; + break; + case GLFW_KEY_KP_SUBTRACT: + scale /= 2.0; + file_stat = (struct stat){0}; + break; + } } -static void scroll_callback(GLFWwindow* window, double x, double y) { - if (iconSize == 0) - return; - scrollX -= x * 25; - scrollY -= y * 25; - if (scrollX < 0) - scrollX = 0; - if (scrollY < 0) - scrollY = 0; - else if (scrollY > maxScroll) - scrollY = maxScroll; - repaintIconList = true; +static void scroll_callback(GLFWwindow *window, double x, double y) { + if (iconSize == 0) + return; + scrollX -= x * 25; + scrollY -= y * 25; + if (scrollX < 0) + scrollX = 0; + if (scrollY < 0) + scrollY = 0; + else if (scrollY > maxScroll) + scrollY = maxScroll; + repaintIconList = true; } -void print_help_and_exit () { - printf("\nUsage: svgviewer [options] [svgfilepath]\n\n"); - printf("\t-o file.png:\toutput result to file then exit.\n"); - printf("\t-d directory:\tdirectory containing svg files, cycle pressing Enter.\n"); - printf("\t\t\tif the -d option is not specified, svgfile path is mandatory.\n"); - printf("\t-i size:\tif -d option is present, display all svg files as a list with the size specified.\n"); - printf("\t-m margin:\tset margin for the -i option\n"); - printf("\t-w width:\tset output surface width.\n"); - printf("\t-h height:\tset output surface height.\n"); - printf("\t-s samples:\tset sample count, set to 1 to disable multisampling.\n"); - printf("\n"); - exit(-1); +void print_help_and_exit() { + printf("\nUsage: svgviewer [options] [svgfilepath]\n\n"); + printf("\t-o file.png:\toutput result to file then exit.\n"); + printf("\t-d directory:\tdirectory containing svg files, cycle pressing Enter.\n"); + printf("\t\t\tif the -d option is not specified, svgfile path is mandatory.\n"); + printf("\t-i size:\tif -d option is present, display all svg files as a list with the size specified.\n"); + printf("\t-m margin:\tset margin for the -i option\n"); + printf("\t-w width:\tset output surface width.\n"); + printf("\t-h height:\tset output surface height.\n"); + printf("\t-s samples:\tset sample count, set to 1 to disable multisampling.\n"); + printf("\n"); + exit(-1); } - -int main (int argc, char *argv[]){ - int i = 1; - char* output = NULL; - - while (i < argc) { - int argLen = strlen(argv[i]); - if (argv[i][0] == '-') { - - if (argLen < 2) print_help_and_exit (); - - switch (argv[i][1]) { - case 'd': - if (argc < ++i + 1) print_help_and_exit(); - directory = argv[i]; - break; - case 'w': - if (argc < ++i + 1) print_help_and_exit(); - width = atoi(argv[i]); - break; - case 'h': - if (argc < ++i + 1) print_help_and_exit(); - height = atoi(argv[i]); - break; - case 's': - if (argc < ++i + 1) print_help_and_exit(); - samples = (VkSampleCountFlags)atoi(argv[i]); - break; - case 'i': - if (argc < ++i + 1) print_help_and_exit(); - iconSize = atoi(argv[i]); - break; - case 'm': - if (argc < ++i + 1) print_help_and_exit(); - margin = atoi(argv[i]); - break; - case 'o': - if (argc < ++i + 1) print_help_and_exit(); - output = argv[i]; - break; - default: - print_help_and_exit(); - } - } else - filename = argv[i]; - i++; - } - if (!filename && !directory) - print_help_and_exit(); - - VkEngine e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU,VK_PRESENT_MODE_FIFO_KHR, width, height); - vkengine_set_key_callback (e, key_callback); - vkengine_set_scroll_callback(e, scroll_callback); - vkvg_device_create_info_t info = { - samples, - false, - vkh_app_get_inst(e->app), - vkengine_get_physical_device(e), - vkengine_get_device(e), - vkengine_get_queue_fam_idx(e), - 0 - }; - dev = vkvg_device_create(&info); - - VkvgSurface surf = NULL; - - if (output) { - surf = vkvg_surface_create_from_svg(dev, width, height, filename); - vkvg_surface_write_to_png (surf, output); - } else { - - surf = vkvg_surface_create(dev, width, height); - - vkh_presenter_build_blit_cmd (e->renderer, vkvg_surface_get_vk_image(surf), width, height); - - if (directory) { - pCurrentDir = opendir(directory); - if(!pCurrentDir) { - printf ("Directory not found: %s\n", directory); - exit(EXIT_FAILURE); - } - dir = get_next_svg_file_in_current_directory(false); - if (!dir) { - printf ("No .svg file found in %s\n", directory); - closedir(pCurrentDir); - exit(EXIT_FAILURE); - } - if (iconSize > 0) { - svg_file_count = _count_svg_files(); - int cellSize = iconSize + margin; - int iconPerLine = ceil((double)(width-iconSize) / cellSize); - int visibleLines = ceil((double)(height) / cellSize); - int totLines = ceil((double)svg_file_count / iconPerLine); - maxScroll = (totLines-visibleLines) * cellSize; - } - } - - - - while (!vkengine_should_close (e)) { - //vkvg_log_level = VKVG_LOG_INFO_CMD; - readSVG (e); - //vkvg_log_level = VKVG_LOG_ERR; - - VkvgContext ctx = vkvg_create(surf); - vkvg_set_source_rgb(ctx,0.1,0.1,0.1); - vkvg_paint(ctx); - - if (svgSurf) { - vkvg_set_source_surface(ctx, svgSurf, 0, 0); - vkvg_paint(ctx); - } else { - vkvg_set_line_width(ctx,10); - vkvg_set_source_rgb(ctx,1,0,0); - vkvg_move_to(ctx, 0,0); - vkvg_line_to(ctx, 512,512); - vkvg_move_to(ctx, 0,512); - vkvg_line_to(ctx, 512,0); - vkvg_stroke(ctx); - - } - vkvg_destroy(ctx); - - glfwPollEvents(); - - if (!vkh_presenter_draw (e->renderer)){ - vkh_presenter_get_size (e->renderer, &width, &height); - vkvg_surface_destroy (surf); - surf = vkvg_surface_create(dev, width, height); - vkh_presenter_build_blit_cmd (e->renderer, vkvg_surface_get_vk_image(surf), width, height); - vkengine_wait_idle(e); - repaintIconList = true; - continue; - } - - } - - vkengine_wait_idle(e); - - } - - if (svgSurf) - vkvg_surface_destroy(svgSurf); - vkvg_surface_destroy(surf); - vkvg_device_destroy(dev); - vkengine_destroy(e); - - if (pCurrentDir) - closedir(pCurrentDir); +int main(int argc, char *argv[]) { + int i = 1; + char *output = NULL; + + while (i < argc) { + int argLen = strlen(argv[i]); + if (argv[i][0] == '-') { + + if (argLen < 2) + print_help_and_exit(); + + switch (argv[i][1]) { + case 'd': + if (argc < ++i + 1) + print_help_and_exit(); + directory = argv[i]; + break; + case 'w': + if (argc < ++i + 1) + print_help_and_exit(); + width = atoi(argv[i]); + break; + case 'h': + if (argc < ++i + 1) + print_help_and_exit(); + height = atoi(argv[i]); + break; + case 's': + if (argc < ++i + 1) + print_help_and_exit(); + samples = (VkSampleCountFlags)atoi(argv[i]); + break; + case 'i': + if (argc < ++i + 1) + print_help_and_exit(); + iconSize = atoi(argv[i]); + break; + case 'm': + if (argc < ++i + 1) + print_help_and_exit(); + margin = atoi(argv[i]); + break; + case 'o': + if (argc < ++i + 1) + print_help_and_exit(); + output = argv[i]; + break; + default: + print_help_and_exit(); + } + } else + filename = argv[i]; + i++; + } + if (!filename && !directory) + print_help_and_exit(); + + VkEngine e = vkengine_create(VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, width, height); + vkengine_set_key_callback(e, key_callback); + vkengine_set_scroll_callback(e, scroll_callback); + vkvg_device_create_info_t info = {samples, + false, + vkh_app_get_inst(e->app), + vkengine_get_physical_device(e), + vkengine_get_device(e), + vkengine_get_queue_fam_idx(e), + 0}; + dev = vkvg_device_create(&info); + + VkvgSurface surf = NULL; + + if (output) { + surf = vkvg_surface_create_from_svg(dev, width, height, filename); + vkvg_surface_write_to_png(surf, output); + } else { + + surf = vkvg_surface_create(dev, width, height); + + vkh_presenter_build_blit_cmd(e->renderer, vkvg_surface_get_vk_image(surf), width, height); + + if (directory) { + pCurrentDir = opendir(directory); + if (!pCurrentDir) { + printf("Directory not found: %s\n", directory); + exit(EXIT_FAILURE); + } + dir = get_next_svg_file_in_current_directory(false); + if (!dir) { + printf("No .svg file found in %s\n", directory); + closedir(pCurrentDir); + exit(EXIT_FAILURE); + } + if (iconSize > 0) { + svg_file_count = _count_svg_files(); + int cellSize = iconSize + margin; + int iconPerLine = ceil((double)(width - iconSize) / cellSize); + int visibleLines = ceil((double)(height) / cellSize); + int totLines = ceil((double)svg_file_count / iconPerLine); + maxScroll = (totLines - visibleLines) * cellSize; + } + } + + while (!vkengine_should_close(e)) { + // vkvg_log_level = VKVG_LOG_INFO_CMD; + readSVG(e); + // vkvg_log_level = VKVG_LOG_ERR; + + VkvgContext ctx = vkvg_create(surf); + vkvg_set_source_rgb(ctx, 0.1, 0.1, 0.1); + vkvg_paint(ctx); + + if (svgSurf) { + vkvg_set_source_surface(ctx, svgSurf, 0, 0); + vkvg_paint(ctx); + } else { + vkvg_set_line_width(ctx, 10); + vkvg_set_source_rgb(ctx, 1, 0, 0); + vkvg_move_to(ctx, 0, 0); + vkvg_line_to(ctx, 512, 512); + vkvg_move_to(ctx, 0, 512); + vkvg_line_to(ctx, 512, 0); + vkvg_stroke(ctx); + } + vkvg_destroy(ctx); + + glfwPollEvents(); + + if (!vkh_presenter_draw(e->renderer)) { + vkh_presenter_get_size(e->renderer, &width, &height); + vkvg_surface_destroy(surf); + surf = vkvg_surface_create(dev, width, height); + vkh_presenter_build_blit_cmd(e->renderer, vkvg_surface_get_vk_image(surf), width, height); + vkengine_wait_idle(e); + repaintIconList = true; + continue; + } + } + + vkengine_wait_idle(e); + } + + if (svgSurf) + vkvg_surface_destroy(svgSurf); + vkvg_surface_destroy(surf); + vkvg_device_destroy(dev); + vkengine_destroy(e); + + if (pCurrentDir) + closedir(pCurrentDir); } -- 2.47.3