├── LICENSE ├── README.md ├── ft-path.c ├── ft-path.h ├── khash.h ├── kvec.h ├── pr.c ├── pr.h ├── svg-path.c └── svg-path.h /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Atılım Çetin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | /* work in progress */ 2 | 3 | 4 | # Path Rendering 5 | This is a high quality vector graphics rendering library for OpenGL and OpenGL ES. It's mostly based on 'GPU Accelerated Path Rendering' paper (stencil and cover method) from NVIDIA. 6 | 7 | [![Video](http://img.youtube.com/vi/Ysg2L2CR4AM/0.jpg)](http://www.youtube.com/watch?v=Ysg2L2CR4AM) 8 | 9 | # Usage 10 | 11 | The API is based on [NV_path_rendering extension](https://www.opengl.org/registry/specs/NV/path_rendering.txt). 12 | 13 | # API Reference 14 | 15 | See the header file pr.h for API reference. 16 | 17 | # Status 18 | 19 | ### Finished 20 | 21 | * All geometric primitives (line, quadratic bezier, cubic bezier, arc) 22 | * Filling and Stroking 23 | * End cap (flat, square, round, triangulate) 24 | * Join style (miter, bevel, round) 25 | * Attribute interpolation 26 | * SVG path description syntax 27 | * Glyphs paths using Freetype 2 28 | 29 | ### In progress 30 | 31 | * Dashing 32 | 33 | ### License 34 | 35 | MIT License 36 | -------------------------------------------------------------------------------- /ft-path.c: -------------------------------------------------------------------------------- 1 | #include "ft-path.h" 2 | #include "kvec.h" 3 | 4 | #define FT_THROW(error) 1 5 | #define FT_TRACE5(varformat) 6 | 7 | typedef int 8 | (*FT_Outline_CloseFunc)( void* user ); 9 | 10 | typedef struct FT_Outline_Funcs_Ex_ 11 | { 12 | FT_Outline_MoveToFunc move_to; 13 | FT_Outline_LineToFunc line_to; 14 | FT_Outline_ConicToFunc conic_to; 15 | FT_Outline_CubicToFunc cubic_to; 16 | FT_Outline_CloseFunc close; 17 | 18 | int shift; 19 | FT_Pos delta; 20 | 21 | } FT_Outline_Funcs_Ex; 22 | 23 | static FT_Error 24 | FT_Outline_Decompose_Ex( FT_Outline* outline, 25 | const FT_Outline_Funcs_Ex* func_interface, 26 | void* user ) 27 | { 28 | #undef SCALED 29 | #define SCALED( x ) ( ( (x) << shift ) - delta ) 30 | 31 | FT_Vector v_last; 32 | FT_Vector v_control; 33 | FT_Vector v_start; 34 | 35 | FT_Vector* point; 36 | FT_Vector* limit; 37 | char* tags; 38 | 39 | FT_Error error; 40 | 41 | FT_Int n; /* index of contour in outline */ 42 | FT_UInt first; /* index of first point in contour */ 43 | FT_Int tag; /* current point's state */ 44 | 45 | FT_Int shift; 46 | FT_Pos delta; 47 | 48 | 49 | if ( !outline || !func_interface ) 50 | return FT_THROW( Invalid_Argument ); 51 | 52 | shift = func_interface->shift; 53 | delta = func_interface->delta; 54 | first = 0; 55 | 56 | for ( n = 0; n < outline->n_contours; n++ ) 57 | { 58 | FT_Int last; /* index of last point in contour */ 59 | 60 | 61 | FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n )); 62 | 63 | last = outline->contours[n]; 64 | if ( last < 0 ) 65 | goto Invalid_Outline; 66 | limit = outline->points + last; 67 | 68 | v_start = outline->points[first]; 69 | v_start.x = SCALED( v_start.x ); 70 | v_start.y = SCALED( v_start.y ); 71 | 72 | v_last = outline->points[last]; 73 | v_last.x = SCALED( v_last.x ); 74 | v_last.y = SCALED( v_last.y ); 75 | 76 | v_control = v_start; 77 | 78 | point = outline->points + first; 79 | tags = outline->tags + first; 80 | tag = FT_CURVE_TAG( tags[0] ); 81 | 82 | /* A contour cannot start with a cubic control point! */ 83 | if ( tag == FT_CURVE_TAG_CUBIC ) 84 | goto Invalid_Outline; 85 | 86 | /* check first point to determine origin */ 87 | if ( tag == FT_CURVE_TAG_CONIC ) 88 | { 89 | /* first point is conic control. Yes, this happens. */ 90 | if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) 91 | { 92 | /* start at last point if it is on the curve */ 93 | v_start = v_last; 94 | limit--; 95 | } 96 | else 97 | { 98 | /* if both first and last points are conic, */ 99 | /* start at their middle and record its position */ 100 | /* for closure */ 101 | v_start.x = ( v_start.x + v_last.x ) / 2; 102 | v_start.y = ( v_start.y + v_last.y ) / 2; 103 | 104 | /* v_last = v_start; */ 105 | } 106 | point--; 107 | tags--; 108 | } 109 | 110 | FT_TRACE5(( " move to (%.2f, %.2f)\n", 111 | v_start.x / 64.0, v_start.y / 64.0 )); 112 | error = func_interface->move_to( &v_start, user ); 113 | if ( error ) 114 | goto Exit; 115 | 116 | while ( point < limit ) 117 | { 118 | point++; 119 | tags++; 120 | 121 | tag = FT_CURVE_TAG( tags[0] ); 122 | switch ( tag ) 123 | { 124 | case FT_CURVE_TAG_ON: /* emit a single line_to */ 125 | { 126 | FT_Vector vec; 127 | 128 | 129 | vec.x = SCALED( point->x ); 130 | vec.y = SCALED( point->y ); 131 | 132 | FT_TRACE5(( " line to (%.2f, %.2f)\n", 133 | vec.x / 64.0, vec.y / 64.0 )); 134 | error = func_interface->line_to( &vec, user ); 135 | if ( error ) 136 | goto Exit; 137 | continue; 138 | } 139 | 140 | case FT_CURVE_TAG_CONIC: /* consume conic arcs */ 141 | v_control.x = SCALED( point->x ); 142 | v_control.y = SCALED( point->y ); 143 | 144 | Do_Conic: 145 | if ( point < limit ) 146 | { 147 | FT_Vector vec; 148 | FT_Vector v_middle; 149 | 150 | 151 | point++; 152 | tags++; 153 | tag = FT_CURVE_TAG( tags[0] ); 154 | 155 | vec.x = SCALED( point->x ); 156 | vec.y = SCALED( point->y ); 157 | 158 | if ( tag == FT_CURVE_TAG_ON ) 159 | { 160 | FT_TRACE5(( " conic to (%.2f, %.2f)" 161 | " with control (%.2f, %.2f)\n", 162 | vec.x / 64.0, vec.y / 64.0, 163 | v_control.x / 64.0, v_control.y / 64.0 )); 164 | error = func_interface->conic_to( &v_control, &vec, user ); 165 | if ( error ) 166 | goto Exit; 167 | continue; 168 | } 169 | 170 | if ( tag != FT_CURVE_TAG_CONIC ) 171 | goto Invalid_Outline; 172 | 173 | v_middle.x = ( v_control.x + vec.x ) / 2; 174 | v_middle.y = ( v_control.y + vec.y ) / 2; 175 | 176 | FT_TRACE5(( " conic to (%.2f, %.2f)" 177 | " with control (%.2f, %.2f)\n", 178 | v_middle.x / 64.0, v_middle.y / 64.0, 179 | v_control.x / 64.0, v_control.y / 64.0 )); 180 | error = func_interface->conic_to( &v_control, &v_middle, user ); 181 | if ( error ) 182 | goto Exit; 183 | 184 | v_control = vec; 185 | goto Do_Conic; 186 | } 187 | 188 | FT_TRACE5(( " conic to (%.2f, %.2f)" 189 | " with control (%.2f, %.2f)\n", 190 | v_start.x / 64.0, v_start.y / 64.0, 191 | v_control.x / 64.0, v_control.y / 64.0 )); 192 | error = func_interface->conic_to( &v_control, &v_start, user ); 193 | goto Close; 194 | 195 | default: /* FT_CURVE_TAG_CUBIC */ 196 | { 197 | FT_Vector vec1, vec2; 198 | 199 | 200 | if ( point + 1 > limit || 201 | FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) 202 | goto Invalid_Outline; 203 | 204 | point += 2; 205 | tags += 2; 206 | 207 | vec1.x = SCALED( point[-2].x ); 208 | vec1.y = SCALED( point[-2].y ); 209 | 210 | vec2.x = SCALED( point[-1].x ); 211 | vec2.y = SCALED( point[-1].y ); 212 | 213 | if ( point <= limit ) 214 | { 215 | FT_Vector vec; 216 | 217 | 218 | vec.x = SCALED( point->x ); 219 | vec.y = SCALED( point->y ); 220 | 221 | FT_TRACE5(( " cubic to (%.2f, %.2f)" 222 | " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", 223 | vec.x / 64.0, vec.y / 64.0, 224 | vec1.x / 64.0, vec1.y / 64.0, 225 | vec2.x / 64.0, vec2.y / 64.0 )); 226 | error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); 227 | if ( error ) 228 | goto Exit; 229 | continue; 230 | } 231 | 232 | FT_TRACE5(( " cubic to (%.2f, %.2f)" 233 | " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", 234 | v_start.x / 64.0, v_start.y / 64.0, 235 | vec1.x / 64.0, vec1.y / 64.0, 236 | vec2.x / 64.0, vec2.y / 64.0 )); 237 | error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); 238 | goto Close; 239 | } 240 | } 241 | } 242 | 243 | /* close the contour */ 244 | FT_TRACE5(( " close\n" )); 245 | error = func_interface->close( user ); 246 | 247 | Close: 248 | if ( error ) 249 | goto Exit; 250 | 251 | first = last + 1; 252 | } 253 | 254 | FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); 255 | return FT_Err_Ok; 256 | 257 | Exit: 258 | FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error )); 259 | return error; 260 | 261 | Invalid_Outline: 262 | return FT_THROW( Invalid_Outline ); 263 | } 264 | 265 | struct decompose_data 266 | { 267 | kvec_t(unsigned char) commands; 268 | kvec_t(float) coords; 269 | }; 270 | 271 | static int moveto(const FT_Vector *to, void *user) 272 | { 273 | struct decompose_data *data = user; 274 | 275 | kv_push_back(data->commands, 'M'); 276 | kv_push_back(data->coords, to->x / 64.f); 277 | kv_push_back(data->coords, to->y / 64.f); 278 | 279 | return 0; 280 | } 281 | static int lineto(const FT_Vector *to, void *user) 282 | { 283 | struct decompose_data *data = user; 284 | 285 | kv_push_back(data->commands, 'L'); 286 | kv_push_back(data->coords, to->x / 64.f); 287 | kv_push_back(data->coords, to->y / 64.f); 288 | 289 | return 0; 290 | } 291 | 292 | static int conicto(const FT_Vector *control, const FT_Vector *to, void *user) 293 | { 294 | struct decompose_data *data = user; 295 | 296 | kv_push_back(data->commands, 'Q'); 297 | kv_push_back(data->coords, control->x / 64.f); 298 | kv_push_back(data->coords, control->y / 64.f); 299 | kv_push_back(data->coords, to->x / 64.f); 300 | kv_push_back(data->coords, to->y / 64.f); 301 | 302 | return 0; 303 | } 304 | 305 | static int cubicto(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) 306 | { 307 | struct decompose_data *data = user; 308 | 309 | kv_push_back(data->commands, 'C'); 310 | kv_push_back(data->coords, control1->x / 64.f); 311 | kv_push_back(data->coords, control1->y / 64.f); 312 | kv_push_back(data->coords, control2->x / 64.f); 313 | kv_push_back(data->coords, control2->y / 64.f); 314 | kv_push_back(data->coords, to->x / 64.f); 315 | kv_push_back(data->coords, to->y / 64.f); 316 | 317 | return 0; 318 | } 319 | 320 | static int close(void *user) 321 | { 322 | struct decompose_data *data = user; 323 | 324 | kv_push_back(data->commands, 'Z'); 325 | 326 | return 0; 327 | } 328 | 329 | struct path *path_from_glyph(FT_Outline *outline) 330 | { 331 | struct decompose_data data; 332 | kv_init(data.commands); 333 | kv_init(data.coords); 334 | 335 | const FT_Outline_Funcs_Ex funcs = {moveto, lineto, conicto, cubicto, close, 0, 0}; 336 | if (FT_Outline_Decompose_Ex(outline, &funcs, &data)) 337 | return NULL; 338 | 339 | struct path *p = malloc(sizeof(struct path)); 340 | 341 | p->num_commands = kv_size(data.commands); 342 | p->commands = kv_data(data.commands); 343 | p->num_coords = kv_size(data.coords); 344 | p->coords = kv_data(data.coords); 345 | 346 | return p; 347 | } 348 | 349 | void free_path(struct path *p) 350 | { 351 | if (p == NULL) 352 | return; 353 | 354 | free(p->coords); 355 | free(p->commands); 356 | free(p); 357 | } 358 | 359 | -------------------------------------------------------------------------------- /ft-path.h: -------------------------------------------------------------------------------- 1 | #ifndef FT_PATH_H 2 | #define FT_PATH_H 3 | 4 | #include 5 | #include FT_FREETYPE_H 6 | #include FT_GLYPH_H 7 | #include FT_OUTLINE_H 8 | 9 | struct path 10 | { 11 | int num_commands; 12 | unsigned char *commands; 13 | int num_coords; 14 | float *coords; 15 | }; 16 | 17 | struct path *path_from_glyph(FT_Outline *outline); 18 | void free_path(struct path *p); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /khash.h: -------------------------------------------------------------------------------- 1 | /* The MIT License 2 | 3 | Copyright (c) 2008, 2009, 2011 by Attractive Chaos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | */ 25 | 26 | /* 27 | An example: 28 | 29 | #include "khash.h" 30 | KHASH_MAP_INIT_INT(32, char) 31 | int main() { 32 | int ret, is_missing; 33 | khiter_t k; 34 | khash_t(32) *h = kh_init(32); 35 | k = kh_put(32, h, 5, &ret); 36 | kh_value(h, k) = 10; 37 | k = kh_get(32, h, 10); 38 | is_missing = (k == kh_end(h)); 39 | k = kh_get(32, h, 5); 40 | kh_del(32, h, k); 41 | for (k = kh_begin(h); k != kh_end(h); ++k) 42 | if (kh_exist(h, k)) kh_value(h, k) = 1; 43 | kh_destroy(32, h); 44 | return 0; 45 | } 46 | */ 47 | 48 | /* 49 | 2013-05-02 (0.2.8): 50 | 51 | * Use quadratic probing. When the capacity is power of 2, stepping function 52 | i*(i+1)/2 guarantees to traverse each bucket. It is better than double 53 | hashing on cache performance and is more robust than linear probing. 54 | 55 | In theory, double hashing should be more robust than quadratic probing. 56 | However, my implementation is probably not for large hash tables, because 57 | the second hash function is closely tied to the first hash function, 58 | which reduce the effectiveness of double hashing. 59 | 60 | Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php 61 | 62 | 2011-12-29 (0.2.7): 63 | 64 | * Minor code clean up; no actual effect. 65 | 66 | 2011-09-16 (0.2.6): 67 | 68 | * The capacity is a power of 2. This seems to dramatically improve the 69 | speed for simple keys. Thank Zilong Tan for the suggestion. Reference: 70 | 71 | - http://code.google.com/p/ulib/ 72 | - http://nothings.org/computer/judy/ 73 | 74 | * Allow to optionally use linear probing which usually has better 75 | performance for random input. Double hashing is still the default as it 76 | is more robust to certain non-random input. 77 | 78 | * Added Wang's integer hash function (not used by default). This hash 79 | function is more robust to certain non-random input. 80 | 81 | 2011-02-14 (0.2.5): 82 | 83 | * Allow to declare global functions. 84 | 85 | 2009-09-26 (0.2.4): 86 | 87 | * Improve portability 88 | 89 | 2008-09-19 (0.2.3): 90 | 91 | * Corrected the example 92 | * Improved interfaces 93 | 94 | 2008-09-11 (0.2.2): 95 | 96 | * Improved speed a little in kh_put() 97 | 98 | 2008-09-10 (0.2.1): 99 | 100 | * Added kh_clear() 101 | * Fixed a compiling error 102 | 103 | 2008-09-02 (0.2.0): 104 | 105 | * Changed to token concatenation which increases flexibility. 106 | 107 | 2008-08-31 (0.1.2): 108 | 109 | * Fixed a bug in kh_get(), which has not been tested previously. 110 | 111 | 2008-08-31 (0.1.1): 112 | 113 | * Added destructor 114 | */ 115 | 116 | 117 | #ifndef __AC_KHASH_H 118 | #define __AC_KHASH_H 119 | 120 | /*! 121 | @header 122 | 123 | Generic hash table library. 124 | */ 125 | 126 | #define AC_VERSION_KHASH_H "0.2.8" 127 | 128 | #include 129 | #include 130 | #include 131 | 132 | /* compiler specific configuration */ 133 | 134 | #if UINT_MAX == 0xffffffffu 135 | typedef unsigned int khint32_t; 136 | #elif ULONG_MAX == 0xffffffffu 137 | typedef unsigned long khint32_t; 138 | #endif 139 | 140 | #if ULONG_MAX == ULLONG_MAX 141 | typedef unsigned long khint64_t; 142 | #else 143 | typedef unsigned long long khint64_t; 144 | #endif 145 | 146 | #ifdef _MSC_VER 147 | #define kh_inline __inline 148 | #else 149 | #define kh_inline inline 150 | #endif 151 | 152 | typedef khint32_t khint_t; 153 | typedef khint_t khiter_t; 154 | 155 | #define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2) 156 | #define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1) 157 | #define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3) 158 | #define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1))) 159 | #define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1))) 160 | #define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1))) 161 | #define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1)) 162 | 163 | #define __ac_fsize(m) ((m) < 16? 1 : (m)>>4) 164 | 165 | #ifndef kroundup32 166 | #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) 167 | #endif 168 | 169 | #ifndef kcalloc 170 | #define kcalloc(N,Z) calloc(N,Z) 171 | #endif 172 | #ifndef kmalloc 173 | #define kmalloc(Z) malloc(Z) 174 | #endif 175 | #ifndef krealloc 176 | #define krealloc(P,Z) realloc(P,Z) 177 | #endif 178 | #ifndef kfree 179 | #define kfree(P) free(P) 180 | #endif 181 | 182 | static const double __ac_HASH_UPPER = 0.77; 183 | 184 | #define __KHASH_TYPE(name, khkey_t, khval_t) \ 185 | typedef struct { \ 186 | khint_t n_buckets, size, n_occupied, upper_bound; \ 187 | khint32_t *flags; \ 188 | khkey_t *keys; \ 189 | khval_t *vals; \ 190 | } kh_##name##_t; 191 | 192 | #define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ 193 | extern kh_##name##_t *kh_init_##name(void); \ 194 | extern void kh_destroy_##name(kh_##name##_t *h); \ 195 | extern void kh_clear_##name(kh_##name##_t *h); \ 196 | extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ 197 | extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ 198 | extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ 199 | extern void kh_del_##name(kh_##name##_t *h, khint_t x); 200 | 201 | #define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ 202 | SCOPE kh_##name##_t *kh_init_##name(void) { \ 203 | return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \ 204 | } \ 205 | SCOPE void kh_destroy_##name(kh_##name##_t *h) \ 206 | { \ 207 | if (h) { \ 208 | kfree((void *)h->keys); kfree(h->flags); \ 209 | kfree((void *)h->vals); \ 210 | kfree(h); \ 211 | } \ 212 | } \ 213 | SCOPE void kh_clear_##name(kh_##name##_t *h) \ 214 | { \ 215 | if (h && h->flags) { \ 216 | memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \ 217 | h->size = h->n_occupied = 0; \ 218 | } \ 219 | } \ 220 | SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \ 221 | { \ 222 | if (h->n_buckets) { \ 223 | khint_t k, i, last, mask, step = 0; \ 224 | mask = h->n_buckets - 1; \ 225 | k = __hash_func(key); i = k & mask; \ 226 | last = i; \ 227 | while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ 228 | i = (i + (++step)) & mask; \ 229 | if (i == last) return h->n_buckets; \ 230 | } \ 231 | return __ac_iseither(h->flags, i)? h->n_buckets : i; \ 232 | } else return 0; \ 233 | } \ 234 | SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \ 235 | { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \ 236 | khint32_t *new_flags = 0; \ 237 | khint_t j = 1; \ 238 | { \ 239 | kroundup32(new_n_buckets); \ 240 | if (new_n_buckets < 4) new_n_buckets = 4; \ 241 | if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \ 242 | else { /* hash table size to be changed (shrink or expand); rehash */ \ 243 | new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ 244 | if (!new_flags) return -1; \ 245 | memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ 246 | if (h->n_buckets < new_n_buckets) { /* expand */ \ 247 | khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ 248 | if (!new_keys) return -1; \ 249 | h->keys = new_keys; \ 250 | if (kh_is_map) { \ 251 | khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ 252 | if (!new_vals) return -1; \ 253 | h->vals = new_vals; \ 254 | } \ 255 | } /* otherwise shrink */ \ 256 | } \ 257 | } \ 258 | if (j) { /* rehashing is needed */ \ 259 | for (j = 0; j != h->n_buckets; ++j) { \ 260 | if (__ac_iseither(h->flags, j) == 0) { \ 261 | khkey_t key = h->keys[j]; \ 262 | khval_t val; \ 263 | khint_t new_mask; \ 264 | new_mask = new_n_buckets - 1; \ 265 | if (kh_is_map) val = h->vals[j]; \ 266 | __ac_set_isdel_true(h->flags, j); \ 267 | while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ 268 | khint_t k, i, step = 0; \ 269 | k = __hash_func(key); \ 270 | i = k & new_mask; \ 271 | while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \ 272 | __ac_set_isempty_false(new_flags, i); \ 273 | if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \ 274 | { khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \ 275 | if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \ 276 | __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \ 277 | } else { /* write the element and jump out of the loop */ \ 278 | h->keys[i] = key; \ 279 | if (kh_is_map) h->vals[i] = val; \ 280 | break; \ 281 | } \ 282 | } \ 283 | } \ 284 | } \ 285 | if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ 286 | h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ 287 | if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ 288 | } \ 289 | kfree(h->flags); /* free the working space */ \ 290 | h->flags = new_flags; \ 291 | h->n_buckets = new_n_buckets; \ 292 | h->n_occupied = h->size; \ 293 | h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \ 294 | } \ 295 | return 0; \ 296 | } \ 297 | SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \ 298 | { \ 299 | khint_t x; \ 300 | if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \ 301 | if (h->n_buckets > (h->size<<1)) { \ 302 | if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \ 303 | *ret = -1; return h->n_buckets; \ 304 | } \ 305 | } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \ 306 | *ret = -1; return h->n_buckets; \ 307 | } \ 308 | } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ 309 | { \ 310 | khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ 311 | x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \ 312 | if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \ 313 | else { \ 314 | last = i; \ 315 | while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ 316 | if (__ac_isdel(h->flags, i)) site = i; \ 317 | i = (i + (++step)) & mask; \ 318 | if (i == last) { x = site; break; } \ 319 | } \ 320 | if (x == h->n_buckets) { \ 321 | if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \ 322 | else x = i; \ 323 | } \ 324 | } \ 325 | } \ 326 | if (__ac_isempty(h->flags, x)) { /* not present at all */ \ 327 | h->keys[x] = key; \ 328 | __ac_set_isboth_false(h->flags, x); \ 329 | ++h->size; ++h->n_occupied; \ 330 | *ret = 1; \ 331 | } else if (__ac_isdel(h->flags, x)) { /* deleted */ \ 332 | h->keys[x] = key; \ 333 | __ac_set_isboth_false(h->flags, x); \ 334 | ++h->size; \ 335 | *ret = 2; \ 336 | } else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ 337 | return x; \ 338 | } \ 339 | SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \ 340 | { \ 341 | if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \ 342 | __ac_set_isdel_true(h->flags, x); \ 343 | --h->size; \ 344 | } \ 345 | } 346 | 347 | #define KHASH_DECLARE(name, khkey_t, khval_t) \ 348 | __KHASH_TYPE(name, khkey_t, khval_t) \ 349 | __KHASH_PROTOTYPES(name, khkey_t, khval_t) 350 | 351 | #define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ 352 | __KHASH_TYPE(name, khkey_t, khval_t) \ 353 | __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) 354 | 355 | #define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ 356 | KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) 357 | 358 | /* --- BEGIN OF HASH FUNCTIONS --- */ 359 | 360 | /*! @function 361 | @abstract Integer hash function 362 | @param key The integer [khint32_t] 363 | @return The hash value [khint_t] 364 | */ 365 | #define kh_int_hash_func(key) (khint32_t)(key) 366 | /*! @function 367 | @abstract Integer comparison function 368 | */ 369 | #define kh_int_hash_equal(a, b) ((a) == (b)) 370 | /*! @function 371 | @abstract 64-bit integer hash function 372 | @param key The integer [khint64_t] 373 | @return The hash value [khint_t] 374 | */ 375 | #define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11) 376 | /*! @function 377 | @abstract 64-bit integer comparison function 378 | */ 379 | #define kh_int64_hash_equal(a, b) ((a) == (b)) 380 | /*! @function 381 | @abstract const char* hash function 382 | @param s Pointer to a null terminated string 383 | @return The hash value 384 | */ 385 | static kh_inline khint_t __ac_X31_hash_string(const char *s) 386 | { 387 | khint_t h = (khint_t)*s; 388 | if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s; 389 | return h; 390 | } 391 | /*! @function 392 | @abstract Another interface to const char* hash function 393 | @param key Pointer to a null terminated string [const char*] 394 | @return The hash value [khint_t] 395 | */ 396 | #define kh_str_hash_func(key) __ac_X31_hash_string(key) 397 | /*! @function 398 | @abstract Const char* comparison function 399 | */ 400 | #define kh_str_hash_equal(a, b) (strcmp(a, b) == 0) 401 | 402 | static kh_inline khint_t __ac_Wang_hash(khint_t key) 403 | { 404 | key += ~(key << 15); 405 | key ^= (key >> 10); 406 | key += (key << 3); 407 | key ^= (key >> 6); 408 | key += ~(key << 11); 409 | key ^= (key >> 16); 410 | return key; 411 | } 412 | #define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key) 413 | 414 | /* --- END OF HASH FUNCTIONS --- */ 415 | 416 | /* Other convenient macros... */ 417 | 418 | /*! 419 | @abstract Type of the hash table. 420 | @param name Name of the hash table [symbol] 421 | */ 422 | #define khash_t(name) kh_##name##_t 423 | 424 | /*! @function 425 | @abstract Initiate a hash table. 426 | @param name Name of the hash table [symbol] 427 | @return Pointer to the hash table [khash_t(name)*] 428 | */ 429 | #define kh_init(name) kh_init_##name() 430 | 431 | /*! @function 432 | @abstract Destroy a hash table. 433 | @param name Name of the hash table [symbol] 434 | @param h Pointer to the hash table [khash_t(name)*] 435 | */ 436 | #define kh_destroy(name, h) kh_destroy_##name(h) 437 | 438 | /*! @function 439 | @abstract Reset a hash table without deallocating memory. 440 | @param name Name of the hash table [symbol] 441 | @param h Pointer to the hash table [khash_t(name)*] 442 | */ 443 | #define kh_clear(name, h) kh_clear_##name(h) 444 | 445 | /*! @function 446 | @abstract Resize a hash table. 447 | @param name Name of the hash table [symbol] 448 | @param h Pointer to the hash table [khash_t(name)*] 449 | @param s New size [khint_t] 450 | */ 451 | #define kh_resize(name, h, s) kh_resize_##name(h, s) 452 | 453 | /*! @function 454 | @abstract Insert a key to the hash table. 455 | @param name Name of the hash table [symbol] 456 | @param h Pointer to the hash table [khash_t(name)*] 457 | @param k Key [type of keys] 458 | @param r Extra return code: -1 if the operation failed; 459 | 0 if the key is present in the hash table; 460 | 1 if the bucket is empty (never used); 2 if the element in 461 | the bucket has been deleted [int*] 462 | @return Iterator to the inserted element [khint_t] 463 | */ 464 | #define kh_put(name, h, k, r) kh_put_##name(h, k, r) 465 | 466 | /*! @function 467 | @abstract Retrieve a key from the hash table. 468 | @param name Name of the hash table [symbol] 469 | @param h Pointer to the hash table [khash_t(name)*] 470 | @param k Key [type of keys] 471 | @return Iterator to the found element, or kh_end(h) if the element is absent [khint_t] 472 | */ 473 | #define kh_get(name, h, k) kh_get_##name(h, k) 474 | 475 | /*! @function 476 | @abstract Remove a key from the hash table. 477 | @param name Name of the hash table [symbol] 478 | @param h Pointer to the hash table [khash_t(name)*] 479 | @param k Iterator to the element to be deleted [khint_t] 480 | */ 481 | #define kh_del(name, h, k) kh_del_##name(h, k) 482 | 483 | /*! @function 484 | @abstract Test whether a bucket contains data. 485 | @param h Pointer to the hash table [khash_t(name)*] 486 | @param x Iterator to the bucket [khint_t] 487 | @return 1 if containing data; 0 otherwise [int] 488 | */ 489 | #define kh_exist(h, x) (!__ac_iseither((h)->flags, (x))) 490 | 491 | /*! @function 492 | @abstract Get key given an iterator 493 | @param h Pointer to the hash table [khash_t(name)*] 494 | @param x Iterator to the bucket [khint_t] 495 | @return Key [type of keys] 496 | */ 497 | #define kh_key(h, x) ((h)->keys[x]) 498 | 499 | /*! @function 500 | @abstract Get value given an iterator 501 | @param h Pointer to the hash table [khash_t(name)*] 502 | @param x Iterator to the bucket [khint_t] 503 | @return Value [type of values] 504 | @discussion For hash sets, calling this results in segfault. 505 | */ 506 | #define kh_val(h, x) ((h)->vals[x]) 507 | 508 | /*! @function 509 | @abstract Alias of kh_val() 510 | */ 511 | #define kh_value(h, x) ((h)->vals[x]) 512 | 513 | /*! @function 514 | @abstract Get the start iterator 515 | @param h Pointer to the hash table [khash_t(name)*] 516 | @return The start iterator [khint_t] 517 | */ 518 | #define kh_begin(h) (khint_t)(0) 519 | 520 | /*! @function 521 | @abstract Get the end iterator 522 | @param h Pointer to the hash table [khash_t(name)*] 523 | @return The end iterator [khint_t] 524 | */ 525 | #define kh_end(h) ((h)->n_buckets) 526 | 527 | /*! @function 528 | @abstract Get the number of elements in the hash table 529 | @param h Pointer to the hash table [khash_t(name)*] 530 | @return Number of elements in the hash table [khint_t] 531 | */ 532 | #define kh_size(h) ((h)->size) 533 | 534 | /*! @function 535 | @abstract Get the number of buckets in the hash table 536 | @param h Pointer to the hash table [khash_t(name)*] 537 | @return Number of buckets in the hash table [khint_t] 538 | */ 539 | #define kh_n_buckets(h) ((h)->n_buckets) 540 | 541 | /*! @function 542 | @abstract Iterate over the entries in the hash table 543 | @param h Pointer to the hash table [khash_t(name)*] 544 | @param kvar Variable to which key will be assigned 545 | @param vvar Variable to which value will be assigned 546 | @param code Block of code to execute 547 | */ 548 | #define kh_foreach(h, kvar, vvar, code) { khint_t __i; \ 549 | for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ 550 | if (!kh_exist(h,__i)) continue; \ 551 | (kvar) = kh_key(h,__i); \ 552 | (vvar) = kh_val(h,__i); \ 553 | code; \ 554 | } } 555 | 556 | /*! @function 557 | @abstract Iterate over the values in the hash table 558 | @param h Pointer to the hash table [khash_t(name)*] 559 | @param vvar Variable to which value will be assigned 560 | @param code Block of code to execute 561 | */ 562 | #define kh_foreach_value(h, vvar, code) { khint_t __i; \ 563 | for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ 564 | if (!kh_exist(h,__i)) continue; \ 565 | (vvar) = kh_val(h,__i); \ 566 | code; \ 567 | } } 568 | 569 | /* More conenient interfaces */ 570 | 571 | /*! @function 572 | @abstract Instantiate a hash set containing integer keys 573 | @param name Name of the hash table [symbol] 574 | */ 575 | #define KHASH_SET_INIT_INT(name) \ 576 | KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal) 577 | 578 | /*! @function 579 | @abstract Instantiate a hash map containing integer keys 580 | @param name Name of the hash table [symbol] 581 | @param khval_t Type of values [type] 582 | */ 583 | #define KHASH_MAP_INIT_INT(name, khval_t) \ 584 | KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal) 585 | 586 | /*! @function 587 | @abstract Instantiate a hash map containing 64-bit integer keys 588 | @param name Name of the hash table [symbol] 589 | */ 590 | #define KHASH_SET_INIT_INT64(name) \ 591 | KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal) 592 | 593 | /*! @function 594 | @abstract Instantiate a hash map containing 64-bit integer keys 595 | @param name Name of the hash table [symbol] 596 | @param khval_t Type of values [type] 597 | */ 598 | #define KHASH_MAP_INIT_INT64(name, khval_t) \ 599 | KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal) 600 | 601 | typedef const char *kh_cstr_t; 602 | /*! @function 603 | @abstract Instantiate a hash map containing const char* keys 604 | @param name Name of the hash table [symbol] 605 | */ 606 | #define KHASH_SET_INIT_STR(name) \ 607 | KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal) 608 | 609 | /*! @function 610 | @abstract Instantiate a hash map containing const char* keys 611 | @param name Name of the hash table [symbol] 612 | @param khval_t Type of values [type] 613 | */ 614 | #define KHASH_MAP_INIT_STR(name, khval_t) \ 615 | KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) 616 | 617 | #endif /* __AC_KHASH_H */ 618 | -------------------------------------------------------------------------------- /kvec.h: -------------------------------------------------------------------------------- 1 | #ifndef KVEC_H 2 | #define KVEC_H 3 | 4 | #include 5 | #include 6 | 7 | #define kvec_t(type) struct { size_t n, m; type *a; } 8 | #define kv_init(v) ((v).n = 0, (v).m = 0, (v).a = NULL) 9 | #define kv_free(v) free((v).a) 10 | #define kv_a(v, i) ((v).a[(i)]) 11 | #define kv_size(v) ((v).n) 12 | #define kv_clear(v) ((v).n = 0) 13 | #define kv_data(v) ((v).a) 14 | #define kv_back(v) ((v).a[(v).n - 1]) 15 | #define kv_pop_back(v) ((v).n--) 16 | #define kv_empty(v) ((v).n == 0) 17 | #define kv_erase(v, i) \ 18 | do \ 19 | { \ 20 | size_t i2 = (i); \ 21 | memcpy((v).a + i2, (v).a + i2 + 1, ((v).n - i2 - 1) * sizeof(*(v).a)); \ 22 | (v).n--; \ 23 | } while (0) 24 | 25 | #define kv_insert(v, i, x) \ 26 | do \ 27 | { \ 28 | size_t i2 = (i); \ 29 | if ((v).n == (v).m) \ 30 | { \ 31 | (v).m = (v).m * 2 + 8; \ 32 | *(void**)&(v).a = realloc((v).a, sizeof(*(v).a) * (v).m); \ 33 | } \ 34 | memcpy((v).a + i2 + 1, (v).a + i2, ((v).n - i2) * sizeof(*(v).a)); \ 35 | (v).n++; \ 36 | (v).a[i2] = (x); \ 37 | } while (0) 38 | 39 | #define kv_resize(v, s) \ 40 | do \ 41 | { \ 42 | size_t s2 = (s); \ 43 | if (s2 > (v).m) \ 44 | { \ 45 | (v).m = s2; \ 46 | *(void**)&(v).a = realloc((v).a, sizeof(*(v).a) * (v).m); \ 47 | } \ 48 | (v).n = s2; \ 49 | } while(0) 50 | 51 | #define kv_push_back(v, x) \ 52 | do \ 53 | { \ 54 | if ((v).n == (v).m) \ 55 | { \ 56 | (v).m = (v).m * 2 + 8; \ 57 | *(void**)&(v).a = realloc((v).a, sizeof(*(v).a) * (v).m); \ 58 | } \ 59 | (v).a[(v).n++] = (x); \ 60 | } while(0) 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /pr.c: -------------------------------------------------------------------------------- 1 | #define _USE_MATH_DEFINES 2 | #include 3 | 4 | #include "pr.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "kvec.h" 11 | #include "khash.h" 12 | #include "svg-path.h" 13 | 14 | #pragma comment(lib, "glew32.lib") 15 | 16 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) 17 | #define MAX(x, y) ((x) > (y) ? (x) : (y)) 18 | 19 | /* begin of mesh merger */ 20 | 21 | struct vector2f 22 | { 23 | float x, y; 24 | }; 25 | 26 | struct vector4f 27 | { 28 | float x, y, z, w; 29 | }; 30 | 31 | #define kh_vector2f_hash_equal(a, b) ((a.x) == (b.x) && (a.y) == (b.y)) 32 | #define kh_vector4f_hash_equal(a, b) ((a.x) == (b.x) && (a.y) == (b.y) && (a.z) == (b.z) && (a.w) == (b.w)) 33 | #define kh_vector2f_hash_func(a) ((khint_t)((a.x) * 1e6f) ^ (khint_t)((a.y) * 1e6f)) 34 | #define kh_vector4f_hash_func(a) ((khint_t)((a.x) * 1e6f) ^ (khint_t)((a.y) * 1e6f) ^ (khint_t)((a.z) * 1e6f) ^ (khint_t)((a.w) * 1e6f)) 35 | 36 | KHASH_INIT(vector2f, struct vector2f, unsigned short, 1, kh_vector2f_hash_func, kh_vector2f_hash_equal) 37 | KHASH_INIT(vector4f, struct vector4f, unsigned short, 1, kh_vector4f_hash_func, kh_vector4f_hash_equal) 38 | 39 | /* TODO: better hash functions */ 40 | 41 | struct merger4f 42 | { 43 | khash_t(vector4f) *h; 44 | kvec_t(struct vector4f) vertices; 45 | kvec_t(unsigned short) indices; 46 | }; 47 | 48 | void init_merger4f(struct merger4f *m) 49 | { 50 | m->h = kh_init(vector4f); 51 | kv_init(m->vertices); 52 | kv_init(m->indices); 53 | } 54 | 55 | void free_merger4f(struct merger4f *m) 56 | { 57 | kh_destroy(vector4f, m->h); 58 | kv_free(m->vertices); 59 | kv_free(m->indices); 60 | } 61 | 62 | static void merge4f(struct merger4f *m, const struct vector4f *vertices, unsigned short *indices, int count) 63 | { 64 | int i; 65 | 66 | for (i = 0; i < count; ++i) 67 | { 68 | struct vector4f v; 69 | khiter_t k; 70 | 71 | v = vertices[indices[i]]; 72 | 73 | k = kh_get(vector4f, m->h, v); 74 | 75 | if (k == kh_end(m->h)) 76 | { 77 | int tmp; 78 | 79 | kv_push_back(m->indices, kv_size(m->vertices)); 80 | 81 | k = kh_put(vector4f, m->h, v, &tmp); 82 | kh_value(m->h, k) = kv_size(m->vertices); 83 | 84 | kv_push_back(m->vertices, v); 85 | } 86 | else 87 | { 88 | kv_push_back(m->indices, kh_value(m->h, k)); 89 | } 90 | } 91 | } 92 | 93 | /* end of mesh merger*/ 94 | 95 | 96 | #define BUFFER_OFFSET(i) ((char *)NULL + (i)) 97 | 98 | /* begin of path name management */ 99 | 100 | struct segment 101 | { 102 | unsigned int start; 103 | int length; 104 | struct segment *next; 105 | }; 106 | 107 | static struct segment *segments = NULL; 108 | 109 | static void init_segments(void) 110 | { 111 | segments = (struct segment*)malloc(sizeof(struct segment)); 112 | segments->next = NULL; 113 | } 114 | 115 | static unsigned int gen_paths(int range) 116 | { 117 | unsigned int start = 1; 118 | 119 | struct segment *prev = segments; 120 | struct segment *curr = segments->next; 121 | 122 | while (curr) 123 | { 124 | int length = curr->start - start; 125 | if (length >= range) 126 | { 127 | struct segment *s = (struct segment*)malloc(sizeof(struct segment)); 128 | 129 | s->start = start; 130 | s->length = range; 131 | 132 | s->next = curr; 133 | prev->next = s; 134 | 135 | return start; 136 | } 137 | 138 | start = curr->start + curr->length; 139 | 140 | prev = curr; 141 | curr = curr->next; 142 | } 143 | 144 | { 145 | struct segment *s = (struct segment*)malloc(sizeof(struct segment)); 146 | 147 | s->start = start; 148 | s->length = range; 149 | 150 | prev->next = s; 151 | s->next = NULL; 152 | 153 | return start; 154 | } 155 | } 156 | 157 | static void delete_path_helper(unsigned int min, unsigned int max); 158 | 159 | static void delete_paths(unsigned int path, int range) 160 | { 161 | struct segment *prev = segments; 162 | struct segment *curr = segments->next; 163 | 164 | unsigned int min1 = path; 165 | unsigned int max1 = path + range - 1; 166 | 167 | while (curr) 168 | { 169 | unsigned int min2 = curr->start; 170 | unsigned int max2 = curr->start + curr->length - 1; 171 | 172 | if (min1 > min2 && max1 < max2) 173 | { 174 | struct segment *s = (struct segment*)malloc(sizeof(struct segment)); 175 | 176 | s->start = max1 + 1; 177 | s->length = max2 - max1; 178 | 179 | curr->length = min1 - min2; 180 | 181 | s->next = curr->next; 182 | curr->next = s; 183 | 184 | delete_path_helper(min1, max1); 185 | } 186 | else if (min1 <= min2 && max1 >= max2) 187 | { 188 | prev->next = curr->next; 189 | free(curr); 190 | curr = prev; 191 | 192 | delete_path_helper(min2, max2); 193 | } 194 | else if (min1 > min2 && min1 <= max2) 195 | { 196 | curr->length = min1 - min2; 197 | 198 | delete_path_helper(min1, max2); 199 | } 200 | else if (max1 >= min2 && max1 < max2) 201 | { 202 | curr->start = max1 + 1; 203 | curr->length = max2 - max1; 204 | 205 | delete_path_helper(min2, max1); 206 | } 207 | 208 | prev = curr; 209 | curr = curr->next; 210 | } 211 | } 212 | 213 | static void set_path(unsigned int path) 214 | { 215 | struct segment *prev = segments; 216 | struct segment *curr = segments->next; 217 | 218 | while (curr) 219 | { 220 | unsigned int min = curr->start; 221 | unsigned int max = curr->start + curr->length - 1; 222 | 223 | if (min <= path && path <= max) 224 | return; 225 | 226 | if (path < min) 227 | { 228 | struct segment *s = (struct segment*)malloc(sizeof(struct segment)); 229 | 230 | s->start = path; 231 | s->length = 1; 232 | 233 | s->next = curr; 234 | prev->next = s; 235 | 236 | return; 237 | } 238 | 239 | prev = curr; 240 | curr = curr->next; 241 | } 242 | 243 | { 244 | struct segment *s = (struct segment*)malloc(sizeof(struct segment)); 245 | 246 | s->start = path; 247 | s->length = 1; 248 | 249 | prev->next = s; 250 | s->next = NULL; 251 | } 252 | } 253 | 254 | static void cleanup_segments(void) 255 | { 256 | struct segment *curr = segments; 257 | 258 | while (curr) 259 | { 260 | struct segment *temp = curr; 261 | delete_path_helper(curr->start, curr->start + curr->length - 1); 262 | curr = curr->next; 263 | free(temp); 264 | } 265 | 266 | segments = NULL; 267 | } 268 | 269 | /* end of path name management */ 270 | 271 | 272 | static const char *vs_code0 = 273 | "uniform mat4 matrix; \n" 274 | " \n" 275 | #ifdef OPENGL_ES 276 | "uniform mat4 mvp; \n" 277 | #else 278 | "#define mvp gl_ModelViewProjectionMatrix \n" 279 | #endif 280 | " \n" 281 | "attribute vec2 data0; \n" 282 | " \n" 283 | "void main(void) \n" 284 | "{ \n" 285 | " gl_Position = mvp * (matrix * vec4(data0, 0, 1)); \n" 286 | "} \n"; 287 | 288 | static const char *fs_code0 = 289 | "void main(void) \n" 290 | "{ \n" 291 | " gl_FragColor = vec4(1, 1, 1, 1); \n" 292 | "} \n"; 293 | 294 | static const char *vs_code1 = 295 | "uniform mat4 matrix; \n" 296 | " \n" 297 | #ifdef OPENGL_ES 298 | "uniform mat4 mvp; \n" 299 | #else 300 | "#define mvp gl_ModelViewProjectionMatrix \n" 301 | #endif 302 | " \n" 303 | "attribute vec4 data0; \n" 304 | " \n" 305 | "varying vec2 uv; \n" 306 | " \n" 307 | "void main(void) \n" 308 | "{ \n" 309 | " gl_Position = mvp * (matrix * vec4(data0.xy, 0, 1)); \n" 310 | " uv = data0.zw; \n" 311 | "} \n"; 312 | 313 | static const char *fs_code1 = 314 | "varying vec2 uv; \n" 315 | " \n" 316 | "void main(void) \n" 317 | "{ \n" 318 | " float u = uv.x; \n" 319 | " float v = uv.y; \n" 320 | " if (u * u > v) \n" 321 | " discard; \n" 322 | " gl_FragColor = vec4(1, 1, 1, 1); \n" 323 | "} \n"; 324 | 325 | static const char *vs_code2 = 326 | "uniform mat4 matrix; \n" 327 | " \n" 328 | #ifdef OPENGL_ES 329 | "uniform mat4 mvp; \n" 330 | #else 331 | "#define mvp gl_ModelViewProjectionMatrix \n" 332 | #endif 333 | " \n" 334 | "attribute vec4 data0; \n" 335 | "attribute vec4 data1; \n" 336 | "attribute vec4 data2; \n" 337 | " \n" 338 | "varying vec2 pos; \n" 339 | "varying float p, q; \n" 340 | "varying vec2 a, b, c; \n" 341 | "varying float offset, strokeWidth; \n" 342 | " \n" 343 | "void main() \n" 344 | "{ \n" 345 | " gl_Position = mvp * (matrix * vec4(data0.xy, 0, 1)); \n" 346 | " pos = data0.xy; \n" 347 | " p = data0.z; \n" 348 | " q = data0.w; \n" 349 | " a = data1.xy; \n" 350 | " b = data1.zw; \n" 351 | " c = data2.xy; \n" 352 | " offset = data2.z; \n" 353 | " strokeWidth = data2.w; \n" 354 | "} \n"; 355 | 356 | static const char *fs_code2 = 357 | "varying vec2 pos; \n" 358 | "varying float p, q; \n" 359 | "varying vec2 a, b, c; \n" 360 | "varying float offset, strokeWidth; \n" 361 | " \n" 362 | "#define M_PI 3.1415926535897932384626433832795 \n" 363 | " \n" 364 | "vec2 evaluateQuadratic(float t) \n" 365 | "{ \n" 366 | " return a * t * t + b * t + c; \n" 367 | "} \n" 368 | " \n" 369 | "bool check(float t) \n" 370 | "{ \n" 371 | " if (0.0 <= t && t <= 1.0) \n" 372 | " { \n" 373 | " vec2 q = evaluateQuadratic(t) - pos; \n" 374 | " if (dot(q, q) <= strokeWidth) \n" 375 | " return false; \n" 376 | " } \n" 377 | " \n" 378 | " return true; \n" 379 | "} \n" 380 | " \n" 381 | "float cbrt(float x) \n" 382 | "{ \n" 383 | " return sign(x) * pow(abs(x), 1.0 / 3.0); \n" 384 | "} \n" 385 | " \n" 386 | "void main() \n" 387 | "{ \n" 388 | " float d = q * q / 4.0 + p * p * p / 27.0; \n" 389 | " \n" 390 | " if (d >= 0.0) \n" 391 | " { \n" 392 | " float c1 = -q / 2.0; \n" 393 | " float c2 = sqrt(d); \n" 394 | " if (check(cbrt(c1 + c2) + cbrt(c1 - c2) + offset)) discard; \n" 395 | " } \n" 396 | " else \n" 397 | " { \n" 398 | " float cos_3_theta = 3.0 * q * sqrt(-3.0 / p) / (2.0 * p); \n" 399 | " float theta = acos(cos_3_theta) / 3.0; \n" 400 | " float r = 2.0 * sqrt(-p / 3.0); \n" 401 | " \n" 402 | " if (check(r * cos(theta) + offset) && \n" 403 | " check(r * cos(theta + 2.0 * M_PI / 3.0) + offset) && \n" 404 | " check(r * cos(theta + 4.0 * M_PI / 3.0) + offset)) discard; \n" 405 | " } \n" 406 | " gl_FragColor = vec4(1, 1, 1, 1); \n" 407 | "} \n"; 408 | 409 | 410 | 411 | static const char *vs_code3 = 412 | "attribute vec2 data0; \n" 413 | " \n" 414 | "varying vec2 uv; \n" 415 | " \n" 416 | "void main(void) \n" 417 | "{ \n" 418 | " gl_Position = ftransform(); \n" 419 | " uv = data0; \n" 420 | "} \n"; 421 | 422 | static const char *fs_code3 = 423 | "varying vec2 uv; \n" 424 | " \n" 425 | "void main(void) \n" 426 | "{ \n" 427 | " float u = uv.x; \n" 428 | " float v = uv.y; \n" 429 | " if (u * u + v * v > 1) \n" 430 | " discard; \n" 431 | " gl_FragColor = vec4(1, 1, 1, 1); \n" 432 | "} \n"; 433 | 434 | 435 | static GLuint program0, program1, program2, program3; 436 | static GLint matrix0, matrix1, matrix2, matrix3; 437 | static GLfloat identity_matrix[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; 438 | #ifdef OPENGL_ES 439 | static GLint mvp0, mvp1, mvp2, mvp3; 440 | static GLfloat g_mvp[16]; 441 | #endif 442 | 443 | #define DATA0_POS 0 444 | #define DATA1_POS 1 445 | #define DATA2_POS 2 446 | 447 | static void subdivide_cubic(const double c[8], double c1[8], double c2[8]) 448 | { 449 | double p1x = (c[0] + c[2]) / 2; 450 | double p1y = (c[1] + c[3]) / 2; 451 | double p2x = (c[2] + c[4]) / 2; 452 | double p2y = (c[3] + c[5]) / 2; 453 | double p3x = (c[4] + c[6]) / 2; 454 | double p3y = (c[5] + c[7]) / 2; 455 | double p4x = (p1x + p2x) / 2; 456 | double p4y = (p1y + p2y) / 2; 457 | double p5x = (p2x + p3x) / 2; 458 | double p5y = (p2y + p3y) / 2; 459 | double p6x = (p4x + p5x) / 2; 460 | double p6y = (p4y + p5y) / 2; 461 | 462 | double p0x = c[0]; 463 | double p0y = c[1]; 464 | double p7x = c[6]; 465 | double p7y = c[7]; 466 | 467 | c1[0] = p0x; 468 | c1[1] = p0y; 469 | c1[2] = p1x; 470 | c1[3] = p1y; 471 | c1[4] = p4x; 472 | c1[5] = p4y; 473 | c1[6] = p6x; 474 | c1[7] = p6y; 475 | 476 | c2[0] = p6x; 477 | c2[1] = p6y; 478 | c2[2] = p5x; 479 | c2[3] = p5y; 480 | c2[4] = p3x; 481 | c2[5] = p3y; 482 | c2[6] = p7x; 483 | c2[7] = p7y; 484 | } 485 | 486 | static void subdivide_cubic2(const double cin[8], double cout[16]) 487 | { 488 | subdivide_cubic(cin, cout, cout + 8); 489 | } 490 | 491 | static void subdivide_cubic4(const double cin[8], double cout[32]) 492 | { 493 | subdivide_cubic(cin, cout, cout + 16); 494 | subdivide_cubic2(cout, cout); 495 | subdivide_cubic2(cout + 16, cout + 16); 496 | } 497 | 498 | static void subdivide_cubic8(const double cin[8], double cout[64]) 499 | { 500 | subdivide_cubic(cin, cout, cout + 32); 501 | subdivide_cubic4(cout, cout); 502 | subdivide_cubic4(cout + 32, cout + 32); 503 | } 504 | 505 | static void cubic_to_quadratic(const double c[8], double q[6]) 506 | { 507 | q[0] = c[0]; 508 | q[1] = c[1]; 509 | q[2] = (3 * (c[2] + c[4]) - (c[0] + c[6])) / 4; 510 | q[3] = (3 * (c[3] + c[5]) - (c[1] + c[7])) / 4; 511 | q[4] = c[6]; 512 | q[5] = c[7]; 513 | } 514 | 515 | /* 516 | M: 0 517 | L: 1 518 | Z: 2 519 | 520 | M -> M no 521 | M -> L no 522 | M -> Z no 523 | L -> M yes 524 | L -> L no 525 | L -> Z no 526 | Z -> M yes 527 | Z -> L yes 528 | Z -> Z no 529 | */ 530 | static const int new_path_table[3][3] = {{0, 0, 0}, {1, 0, 0}, {1, 1, 0}}; 531 | 532 | // always starts with 'M' 533 | // after 'M', only contains 'L' and 'Q' 534 | // optionally finishes with 'Z' 535 | struct reduced_path 536 | { 537 | kvec_t(unsigned char) commands; 538 | kvec_t(float) coords; 539 | }; 540 | 541 | typedef kvec_t(struct reduced_path) reduced_path_vec; 542 | 543 | struct geometry 544 | { 545 | kvec_t(float) vertices; 546 | kvec_t(unsigned short) indices; 547 | 548 | GLuint vertex_buffer; 549 | GLuint index_buffer; 550 | GLsizei count; 551 | }; 552 | 553 | struct path 554 | { 555 | int num_commands; 556 | unsigned char *commands; 557 | 558 | int num_coords; 559 | float *coords; 560 | 561 | reduced_path_vec reduced_paths; 562 | 563 | float stroke_width; 564 | int join_style; 565 | int initial_end_cap; 566 | int terminal_end_cap; 567 | float miter_limit; 568 | 569 | int num_dashes; 570 | float *dashes; 571 | float dash_length; 572 | 573 | struct geometry fill_geoms[4]; /* 0: front-solid, 1:back-solid 2:front-quad 3:back-quad */ 574 | struct geometry stroke_geoms[2]; /* 1: solid 2: quad */ 575 | 576 | GLuint fill_vertex_buffer; 577 | GLuint fill_index_buffer; 578 | GLsizei fill_counts[2]; 579 | GLint fill_starts[2]; 580 | 581 | float fill_bounds[4]; 582 | float stroke_bounds[4]; 583 | 584 | int is_stroke_dirty; 585 | int is_fill_dirty; 586 | int is_reduced_paths_dirty; 587 | }; 588 | 589 | KHASH_MAP_INIT_INT(path, struct path *) 590 | 591 | static khash_t(path) *paths = NULL; 592 | 593 | static void delete_path(struct path *p) 594 | { 595 | size_t i; 596 | 597 | free(p->commands); 598 | free(p->coords); 599 | 600 | free(p->dashes); 601 | 602 | for (i = 0; i < kv_size(p->reduced_paths); ++i) 603 | { 604 | kv_free(kv_a(p->reduced_paths, i).commands); 605 | kv_free(kv_a(p->reduced_paths, i).coords); 606 | } 607 | kv_free(p->reduced_paths); 608 | 609 | #if 0 610 | for (i = 0; i < 4; ++i) 611 | { 612 | glDeleteBuffers(1, &p->fill_geoms[i].vertex_buffer); 613 | glDeleteBuffers(1, &p->fill_geoms[i].index_buffer); 614 | } 615 | #endif 616 | 617 | for (i = 0; i < 2; ++i) 618 | { 619 | glDeleteBuffers(1, &p->stroke_geoms[i].vertex_buffer); 620 | glDeleteBuffers(1, &p->stroke_geoms[i].index_buffer); 621 | } 622 | 623 | glDeleteBuffers(1, &p->fill_vertex_buffer); 624 | glDeleteBuffers(1, &p->fill_index_buffer); 625 | 626 | free(p); 627 | } 628 | 629 | static void delete_path_helper(unsigned int min, unsigned int max) 630 | { 631 | unsigned int i; 632 | for (i = min; i <= max; ++i) 633 | { 634 | khiter_t iter = kh_get(path, paths, i); 635 | if (iter != kh_end(paths)) 636 | { 637 | struct path *p = kh_value(paths, iter); 638 | delete_path(p); 639 | kh_del(path, paths, iter); 640 | } 641 | } 642 | } 643 | 644 | static void new_path(reduced_path_vec *paths) 645 | { 646 | struct reduced_path rp = {0}; 647 | kv_push_back(*paths, rp); 648 | } 649 | 650 | static void move_to(struct reduced_path *path, float x, float y) 651 | { 652 | if (kv_empty(path->commands)) 653 | { 654 | kv_push_back(path->commands, GL_MOVE_TO_AC); 655 | kv_push_back(path->coords, x); 656 | kv_push_back(path->coords, y); 657 | } 658 | else 659 | { 660 | kv_a(path->coords, 0) = x; 661 | kv_a(path->coords, 1) = y; 662 | } 663 | } 664 | 665 | static void line_to(struct reduced_path *path, float x1, float y1, float x2, float y2) 666 | { 667 | if (kv_empty(path->commands)) 668 | { 669 | kv_push_back(path->commands, GL_MOVE_TO_AC); 670 | kv_push_back(path->coords, x1); 671 | kv_push_back(path->coords, y1); 672 | } 673 | 674 | kv_push_back(path->commands, GL_LINE_TO_AC); 675 | kv_push_back(path->coords, x2); 676 | kv_push_back(path->coords, y2); 677 | } 678 | 679 | static void quad_to(struct reduced_path *path, float x1, float y1, float x2, float y2, float x3, float y3) 680 | { 681 | if (kv_empty(path->commands)) 682 | { 683 | kv_push_back(path->commands, GL_MOVE_TO_AC); 684 | kv_push_back(path->coords, x1); 685 | kv_push_back(path->coords, y1); 686 | } 687 | 688 | kv_push_back(path->commands, GL_QUADRATIC_CURVE_TO_AC); 689 | kv_push_back(path->coords, x2); 690 | kv_push_back(path->coords, y2); 691 | kv_push_back(path->coords, x3); 692 | kv_push_back(path->coords, y3); 693 | } 694 | 695 | static void cubic_to(struct reduced_path *path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) 696 | { 697 | int i; 698 | 699 | double cin[8] = { x1, y1, x2, y2, x3, y3, x4, y4 }; 700 | double cout[64]; 701 | subdivide_cubic8(cin, cout); 702 | 703 | if (kv_empty(path->commands)) 704 | { 705 | kv_push_back(path->commands, GL_MOVE_TO_AC); 706 | kv_push_back(path->coords, x1); 707 | kv_push_back(path->coords, y1); 708 | } 709 | 710 | for (i = 0; i < 8; ++i) 711 | { 712 | double q[6]; 713 | cubic_to_quadratic(cout + i * 8, q); 714 | kv_push_back(path->commands, GL_QUADRATIC_CURVE_TO_AC); 715 | kv_push_back(path->coords, q[2]); 716 | kv_push_back(path->coords, q[3]); 717 | kv_push_back(path->coords, q[4]); 718 | kv_push_back(path->coords, q[5]); 719 | } 720 | } 721 | 722 | static double angle(double ux, double uy, double vx, double vy) 723 | { 724 | return atan2(ux * vy - uy * vx, ux * vx + uy * vy); 725 | } 726 | 727 | /* http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter */ 728 | static void endpoint_to_center(double x1, double y1, double x2, double y2, 729 | int fA, int fS, double *prx, double *pry, double phi, 730 | double *cx, double *cy, double *theta1, double *dtheta) 731 | { 732 | double x1p, y1p, rx, ry, lambda, fsgn, c1, cxp, cyp; 733 | 734 | x1p = cos(phi) * (x1 - x2) / 2 + sin(phi) * (y1 - y2) / 2; 735 | y1p = -sin(phi) * (x1 - x2) / 2 + cos(phi) * (y1 - y2) / 2; 736 | 737 | rx = *prx; 738 | ry = *pry; 739 | 740 | lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry); 741 | if (lambda > 1) 742 | { 743 | lambda = sqrt(lambda); 744 | rx *= lambda; 745 | ry *= lambda; 746 | *prx = rx; 747 | *pry = ry; 748 | } 749 | 750 | fA = !!fA; 751 | fS = !!fS; 752 | 753 | fsgn = (fA != fS) ? 1 : -1; 754 | 755 | c1 = (rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p) / (rx*rx*y1p*y1p + ry*ry*x1p*x1p); 756 | 757 | if (c1 < 0) // because of floating point inaccuracies, c1 can be -epsilon. 758 | c1 = 0; 759 | else 760 | c1 = sqrt(c1); 761 | 762 | cxp = fsgn * c1 * (rx * y1p / ry); 763 | cyp = fsgn * c1 * (-ry * x1p / rx); 764 | 765 | *cx = cos(phi) * cxp - sin(phi) * cyp + (x1 + x2) / 2; 766 | *cy = sin(phi) * cxp + cos(phi) * cyp + (y1 + y2) / 2; 767 | 768 | *theta1 = angle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry); 769 | 770 | *dtheta = angle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry); 771 | 772 | if (!fS && *dtheta > 0) 773 | *dtheta -= 2 * M_PI; 774 | else if (fS && *dtheta < 0) 775 | *dtheta += 2 * M_PI; 776 | } 777 | 778 | static void arc_tod(struct reduced_path *path, double x1, double y1, double rh, double rv, double phi, int fA, int fS, double x2, double y2) 779 | { 780 | double cx, cy, theta1, dtheta; 781 | 782 | int i, nquads; 783 | 784 | phi *= M_PI / 180; 785 | 786 | endpoint_to_center(x1, y1, x2, y2, fA, fS, &rh, &rv, phi, &cx, &cy, &theta1, &dtheta); 787 | 788 | nquads = ceil(fabs(dtheta) * 4 / M_PI); 789 | 790 | for (i = 0; i < nquads; ++i) 791 | { 792 | double t1 = theta1 + (i / (double)nquads) * dtheta; 793 | double t2 = theta1 + ((i + 1) / (double)nquads) * dtheta; 794 | double tm = (t1 + t2) / 2; 795 | 796 | double x1 = cos(phi)*rh*cos(t1) - sin(phi)*rv*sin(t1) + cx; 797 | double y1 = sin(phi)*rh*cos(t1) + cos(phi)*rv*sin(t1) + cy; 798 | 799 | double x2 = cos(phi)*rh*cos(t2) - sin(phi)*rv*sin(t2) + cx; 800 | double y2 = sin(phi)*rh*cos(t2) + cos(phi)*rv*sin(t2) + cy; 801 | 802 | double xm = cos(phi)*rh*cos(tm) - sin(phi)*rv*sin(tm) + cx; 803 | double ym = sin(phi)*rh*cos(tm) + cos(phi)*rv*sin(tm) + cy; 804 | 805 | double xc = (xm * 4 - (x1 + x2)) / 2; 806 | double yc = (ym * 4 - (y1 + y2)) / 2; 807 | 808 | kv_push_back(path->commands, GL_QUADRATIC_CURVE_TO_AC); 809 | kv_push_back(path->coords, xc); 810 | kv_push_back(path->coords, yc); 811 | kv_push_back(path->coords, x2); 812 | kv_push_back(path->coords, y2); 813 | } 814 | } 815 | 816 | static void arc_to(struct reduced_path *path, float x1, float y1, float rh, float rv, float phi, int fA, int fS, float x2, float y2) 817 | { 818 | if (kv_empty(path->commands)) 819 | { 820 | kv_push_back(path->commands, GL_MOVE_TO_AC); 821 | kv_push_back(path->coords, x1); 822 | kv_push_back(path->coords, y1); 823 | } 824 | 825 | arc_tod(path, x1, y1, rh, rv, phi, fA, fS, x2, y2); 826 | } 827 | 828 | static void close_path(struct reduced_path *path) 829 | { 830 | if (kv_back(path->commands) != GL_CLOSE_PATH_AC) 831 | kv_push_back(path->commands, GL_CLOSE_PATH_AC); 832 | } 833 | 834 | static void reduce_path(int num_commands, const unsigned char *commands, int num_coords, const float *coords, reduced_path_vec *reduced_paths) 835 | { 836 | #define c0 coords[icoord] 837 | #define c1 coords[icoord + 1] 838 | #define c2 coords[icoord + 2] 839 | #define c3 coords[icoord + 3] 840 | #define c4 coords[icoord + 4] 841 | #define c5 coords[icoord + 5] 842 | #define c6 coords[icoord + 6] 843 | 844 | #define set(x1, y1, x2, y2) ncpx = x1; ncpy = y1; npepx = x2; npepy = y2; 845 | 846 | #define last_path &kv_back(*reduced_paths) 847 | 848 | 849 | int icoord = 0; 850 | 851 | float spx = 0, spy = 0; 852 | float cpx = 0, cpy = 0; 853 | float pepx = 0, pepy = 0; 854 | float ncpx = 0, ncpy = 0; 855 | float npepx = 0, npepy = 0; 856 | 857 | unsigned char prev_command = 2; 858 | 859 | int i; 860 | 861 | for (i = 0; i < num_commands; ++i) 862 | { 863 | switch(commands[i]) 864 | { 865 | case GL_MOVE_TO_AC: 866 | case 'M': 867 | if (new_path_table[prev_command][0]) 868 | new_path(reduced_paths); 869 | prev_command = 0; 870 | move_to(last_path, c0, c1); 871 | set(c0, c1, c0, c1); 872 | spx = ncpx; 873 | spy = ncpy; 874 | icoord += 2; 875 | break; 876 | 877 | case GL_RELATIVE_MOVE_TO_AC: 878 | case 'm': 879 | if (new_path_table[prev_command][0]) 880 | new_path(reduced_paths); 881 | prev_command = 0; 882 | move_to(last_path, cpx + c0, cpy + c1); 883 | set(cpx + c0, cpy + c1, cpx + c0, cpy + c1); 884 | spx = ncpx; 885 | spy = ncpy; 886 | icoord += 2; 887 | break; 888 | 889 | case GL_CLOSE_PATH_AC: 890 | case 'z': 891 | case 'Z': 892 | if (new_path_table[prev_command][2]) 893 | new_path(reduced_paths); 894 | prev_command = 2; 895 | close_path(last_path); 896 | set(spx, spy, spx, spy); 897 | break; 898 | 899 | case GL_RESTART_PATH_AC: 900 | if (new_path_table[prev_command][0]) 901 | new_path(reduced_paths); 902 | prev_command = 0; 903 | move_to(last_path, 0, 0); 904 | set(0, 0, 0, 0); 905 | spx = ncpx; 906 | spy = ncpy; 907 | break; 908 | 909 | case GL_LINE_TO_AC: 910 | case 'L': 911 | if (new_path_table[prev_command][1]) 912 | new_path(reduced_paths); 913 | prev_command = 1; 914 | line_to(last_path, cpx, cpy, c0, c1); 915 | set(c0, c1, c0, c1); 916 | icoord += 2; 917 | break; 918 | 919 | case GL_RELATIVE_LINE_TO_AC: 920 | case 'l': 921 | if (new_path_table[prev_command][1]) 922 | new_path(reduced_paths); 923 | prev_command = 1; 924 | line_to(last_path, cpx, cpy, cpx + c0, cpy + c1); 925 | set(cpx + c0, cpy + c1, cpx + c0, cpy + c1); 926 | icoord += 2; 927 | break; 928 | 929 | case GL_HORIZONTAL_LINE_TO_AC: 930 | case 'H': 931 | if (new_path_table[prev_command][1]) 932 | new_path(reduced_paths); 933 | prev_command = 1; 934 | line_to(last_path, cpx, cpy, c0, cpy); 935 | set(c0, cpy, c0, cpy); 936 | icoord += 1; 937 | break; 938 | 939 | case GL_RELATIVE_HORIZONTAL_LINE_TO_AC: 940 | case 'h': 941 | if (new_path_table[prev_command][1]) 942 | new_path(reduced_paths); 943 | prev_command = 1; 944 | line_to(last_path, cpx, cpy, cpx + c0, cpy); 945 | set(cpx + c0, cpy, cpx + c0, cpy); 946 | icoord += 1; 947 | break; 948 | 949 | case GL_VERTICAL_LINE_TO_AC: 950 | case 'V': 951 | if (new_path_table[prev_command][1]) 952 | new_path(reduced_paths); 953 | prev_command = 1; 954 | line_to(last_path, cpx, cpy, cpx, c0); 955 | set(cpx, c0, cpx, c0); 956 | icoord += 1; 957 | break; 958 | 959 | case GL_RELATIVE_VERTICAL_LINE_TO_AC: 960 | case 'v': 961 | if (new_path_table[prev_command][1]) 962 | new_path(reduced_paths); 963 | prev_command = 1; 964 | line_to(last_path, cpx, cpy, cpx, cpy + c0); 965 | set(cpx, cpy + c0, cpx, cpy + c0); 966 | icoord += 1; 967 | break; 968 | 969 | case GL_QUADRATIC_CURVE_TO_AC: 970 | case 'Q': 971 | if (new_path_table[prev_command][1]) 972 | new_path(reduced_paths); 973 | prev_command = 1; 974 | quad_to(last_path, cpx, cpy, c0, c1, c2, c3); 975 | set(c2, c3, c0, c1); 976 | icoord += 4; 977 | break; 978 | 979 | case GL_RELATIVE_QUADRATIC_CURVE_TO_AC: 980 | case 'q': 981 | if (new_path_table[prev_command][1]) 982 | new_path(reduced_paths); 983 | prev_command = 1; 984 | quad_to(last_path, cpx, cpy, cpx + c0, cpy + c1, cpx + c2, cpy + c3); 985 | set(cpx + c2, cpy + c3, cpx + c0, cpy + c1); 986 | icoord += 4; 987 | break; 988 | 989 | case GL_CUBIC_CURVE_TO_AC: 990 | case 'C': 991 | if (new_path_table[prev_command][1]) 992 | new_path(reduced_paths); 993 | prev_command = 1; 994 | cubic_to(last_path, cpx, cpy, c0, c1, c2, c3, c4, c5); 995 | set(c4, c5, c2, c3); 996 | icoord += 6; 997 | break; 998 | 999 | case GL_RELATIVE_CUBIC_CURVE_TO_AC: 1000 | case 'c': 1001 | if (new_path_table[prev_command][1]) 1002 | new_path(reduced_paths); 1003 | prev_command = 1; 1004 | cubic_to(last_path, cpx, cpy, cpx + c0, cpy + c1, cpx + c2, cpy + c3, cpx + c4, cpy + c5); 1005 | set(cpx + c4, cpy + c5, cpx + c2, cpy + c3); 1006 | icoord += 6; 1007 | break; 1008 | 1009 | case GL_SMOOTH_QUADRATIC_CURVE_TO_AC: 1010 | case 'T': 1011 | if (new_path_table[prev_command][1]) 1012 | new_path(reduced_paths); 1013 | prev_command = 1; 1014 | quad_to(last_path, cpx, cpy, 2 * cpx - pepx, 2 * cpy - pepy, c0, c1); 1015 | set(c0, c1, 2 * cpx - pepx, 2 * cpy - pepy); 1016 | icoord += 2; 1017 | break; 1018 | 1019 | case GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_AC: 1020 | case 't': 1021 | if (new_path_table[prev_command][1]) 1022 | new_path(reduced_paths); 1023 | prev_command = 1; 1024 | quad_to(last_path, cpx, cpy, 2 * cpx - pepx, 2 * cpy - pepy, cpx + c0, cpy + c1); 1025 | set(cpx + c0, cpy + c1, 2 * cpx - pepx, 2 * cpy - pepy); 1026 | icoord += 2; 1027 | break; 1028 | 1029 | case GL_SMOOTH_CUBIC_CURVE_TO_AC: 1030 | case 'S': 1031 | if (new_path_table[prev_command][1]) 1032 | new_path(reduced_paths); 1033 | prev_command = 1; 1034 | cubic_to(last_path, cpx, cpy, 2 * cpx - pepx, 2 * cpy - pepy, c0, c1, c2, c3); 1035 | set(c2, c3, c0, c1); 1036 | icoord += 4; 1037 | break; 1038 | 1039 | case GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_AC: 1040 | case 's': 1041 | if (new_path_table[prev_command][1]) 1042 | new_path(reduced_paths); 1043 | prev_command = 1; 1044 | cubic_to(last_path, cpx, cpy, 2 * cpx - pepx, 2 * cpy - pepy, cpx + c0, cpy + c1, cpx + c2, cpy + c3); 1045 | set(cpx + c2, cpy + c3, cpx + c0, cpy + c1); 1046 | icoord += 4; 1047 | break; 1048 | 1049 | case GL_SMALL_CCW_ARC_TO_AC: 1050 | if (new_path_table[prev_command][1]) 1051 | new_path(reduced_paths); 1052 | prev_command = 1; 1053 | arc_to(last_path, cpx, cpy, c0, c1, c2, 0, 1, c3, c4); 1054 | set(c3, c4, c3, c4); 1055 | icoord += 5; 1056 | break; 1057 | 1058 | case GL_RELATIVE_SMALL_CCW_ARC_TO_AC: 1059 | if (new_path_table[prev_command][1]) 1060 | new_path(reduced_paths); 1061 | prev_command = 1; 1062 | arc_to(last_path, cpx, cpy, c0, c1, c2, 0, 1, cpx + c3, cpy + c4); 1063 | set(cpx + c3, cpy + c4, cpx + c3, cpy + c4); 1064 | icoord += 5; 1065 | break; 1066 | 1067 | case GL_SMALL_CW_ARC_TO_AC: 1068 | if (new_path_table[prev_command][1]) 1069 | new_path(reduced_paths); 1070 | prev_command = 1; 1071 | arc_to(last_path, cpx, cpy, c0, c1, c2, 0, 0, c3, c4); 1072 | set(c3, c4, c3, c4); 1073 | icoord += 5; 1074 | break; 1075 | 1076 | case GL_RELATIVE_SMALL_CW_ARC_TO_AC: 1077 | if (new_path_table[prev_command][1]) 1078 | new_path(reduced_paths); 1079 | prev_command = 1; 1080 | arc_to(last_path, cpx, cpy, c0, c1, c2, 0, 0, cpx + c3, cpy + c4); 1081 | set(cpx + c3, cpy + c4, cpx + c3, cpy + c4); 1082 | icoord += 5; 1083 | break; 1084 | 1085 | case GL_LARGE_CCW_ARC_TO_AC: 1086 | if (new_path_table[prev_command][1]) 1087 | new_path(reduced_paths); 1088 | prev_command = 1; 1089 | arc_to(last_path, cpx, cpy, c0, c1, c2, 1, 1, c3, c4); 1090 | set(c3, c4, c3, c4); 1091 | icoord += 5; 1092 | break; 1093 | 1094 | case GL_RELATIVE_LARGE_CCW_ARC_TO_AC: 1095 | if (new_path_table[prev_command][1]) 1096 | new_path(reduced_paths); 1097 | prev_command = 1; 1098 | arc_to(last_path, cpx, cpy, c0, c1, c2, 1, 1, cpx + c3, cpy + c4); 1099 | set(cpx + c3, cpy + c4, cpx + c3, cpy + c4); 1100 | icoord += 5; 1101 | break; 1102 | 1103 | case GL_LARGE_CW_ARC_TO_AC: 1104 | if (new_path_table[prev_command][1]) 1105 | new_path(reduced_paths); 1106 | prev_command = 1; 1107 | arc_to(last_path, cpx, cpy, c0, c1, c2, 1, 0, c3, c4); 1108 | set(c3, c4, c3, c4); 1109 | icoord += 5; 1110 | break; 1111 | 1112 | case GL_RELATIVE_LARGE_CW_ARC_TO_AC: 1113 | if (new_path_table[prev_command][1]) 1114 | new_path(reduced_paths); 1115 | prev_command = 1; 1116 | arc_to(last_path, cpx, cpy, c0, c1, c2, 1, 0, cpx + c3, cpy + c4); 1117 | set(cpx + c3, cpy + c4, cpx + c3, cpy + c4); 1118 | icoord += 5; 1119 | break; 1120 | 1121 | case GL_ARC_TO_AC: 1122 | case 'A': 1123 | if (new_path_table[prev_command][1]) 1124 | new_path(reduced_paths); 1125 | prev_command = 1; 1126 | arc_to(last_path, cpx, cpy, c0, c1, c2, c3, c4, c5, c6); 1127 | set(c5, c6, c5, c6); 1128 | icoord += 7; 1129 | break; 1130 | 1131 | case GL_RELATIVE_ARC_TO_AC: 1132 | case 'a': 1133 | if (new_path_table[prev_command][1]) 1134 | new_path(reduced_paths); 1135 | prev_command = 1; 1136 | arc_to(last_path, cpx, cpy, c0, c1, c2, c3, c4, cpx + c5, cpy + c6); 1137 | set(cpx + c5, cpy + c6, cpx + c5, cpy + c6); 1138 | icoord += 7; 1139 | break; 1140 | 1141 | case GL_RECT_AC: 1142 | if (new_path_table[prev_command][0]) 1143 | new_path(reduced_paths); 1144 | prev_command = 2; 1145 | move_to(last_path, c0, c1); 1146 | line_to(last_path, c0, c1, c0 + c2, c1); 1147 | line_to(last_path, c0 + c2, c1, c0 + c2, c1 + c3); 1148 | line_to(last_path, c0 + c2, c1 + c3, c0, c1 + c3); 1149 | close_path(last_path); 1150 | set(c0, c1, c0, c1 + c3); 1151 | icoord += 4; 1152 | break; 1153 | 1154 | case GL_DUP_FIRST_CUBIC_CURVE_TO_AC: 1155 | if (new_path_table[prev_command][1]) 1156 | new_path(reduced_paths); 1157 | prev_command = 1; 1158 | cubic_to(last_path, cpx, cpy, cpx, cpy, c0, c1, c2, c3); 1159 | set(c2, c3, c0, c1); 1160 | icoord += 4; 1161 | break; 1162 | 1163 | case GL_DUP_LAST_CUBIC_CURVE_TO_AC: 1164 | if (new_path_table[prev_command][1]) 1165 | new_path(reduced_paths); 1166 | prev_command = 1; 1167 | cubic_to(last_path, cpx, cpy, c0, c1, c2, c3, c2, c3); 1168 | set(c2, c3, c2, c3); 1169 | icoord += 4; 1170 | break; 1171 | 1172 | case GL_CIRCULAR_CCW_ARC_TO_AC: 1173 | case GL_CIRCULAR_CW_ARC_TO_AC: 1174 | case GL_CIRCULAR_TANGENT_ARC_TO_AC: 1175 | // todo 1176 | break; 1177 | } 1178 | 1179 | cpx = ncpx; 1180 | cpy = ncpy; 1181 | pepx = npepx; 1182 | pepy = npepy; 1183 | } 1184 | 1185 | #undef c0 1186 | #undef c1 1187 | #undef c2 1188 | #undef c3 1189 | #undef c4 1190 | #undef c5 1191 | #undef c6 1192 | 1193 | #undef set 1194 | 1195 | #undef last_path 1196 | } 1197 | 1198 | static int command_coords[256]; 1199 | 1200 | static void path_commands(unsigned int path, int num_commands, const unsigned char *commands, int num_coords, const float *coords) 1201 | { 1202 | int i; 1203 | int num_coords2; 1204 | khiter_t iter; 1205 | struct path *p; 1206 | int tmp; 1207 | 1208 | num_coords2 = 0; 1209 | for (i = 0; i < num_commands; ++i) 1210 | { 1211 | int num = command_coords[commands[i]]; 1212 | if (num == -1) 1213 | { 1214 | // TODO: set error 1215 | return; 1216 | } 1217 | num_coords2 += num; 1218 | } 1219 | 1220 | if (num_coords != num_coords2) 1221 | { 1222 | // TODO: set error 1223 | return; 1224 | } 1225 | 1226 | iter = kh_get(path, paths, path); 1227 | if (iter == kh_end(paths)) 1228 | { 1229 | iter = kh_put(path, paths, path, &tmp); 1230 | p = (struct path*)malloc(sizeof(struct path)); 1231 | kh_value(paths, iter) = p; 1232 | 1233 | p->stroke_width = 1; 1234 | p->join_style = GL_MITER_REVERT_AC; 1235 | p->initial_end_cap = GL_FLAT; 1236 | p->terminal_end_cap = GL_FLAT; 1237 | p->miter_limit = 4; 1238 | p->num_dashes = 0; 1239 | p->dashes = NULL; 1240 | p->dash_length = 0; 1241 | 1242 | #if 0 1243 | for (i = 0; i < 4; ++i) 1244 | { 1245 | glGenBuffers(1, &p->fill_geoms[i].vertex_buffer); 1246 | glGenBuffers(1, &p->fill_geoms[i].index_buffer); 1247 | p->fill_geoms[i].count = 0; 1248 | } 1249 | #endif 1250 | 1251 | for (i = 0; i < 2; ++i) 1252 | { 1253 | glGenBuffers(1, &p->stroke_geoms[i].vertex_buffer); 1254 | glGenBuffers(1, &p->stroke_geoms[i].index_buffer); 1255 | p->stroke_geoms[i].count = 0; 1256 | } 1257 | 1258 | glGenBuffers(1, &p->fill_vertex_buffer); 1259 | glGenBuffers(1, &p->fill_index_buffer); 1260 | 1261 | set_path(path); 1262 | } 1263 | else 1264 | { 1265 | size_t i; 1266 | 1267 | p = kh_value(paths, iter); 1268 | 1269 | free(p->commands); 1270 | free(p->coords); 1271 | for (i = 0; i < kv_size(p->reduced_paths); ++i) 1272 | { 1273 | kv_free(kv_a(p->reduced_paths, i).commands); 1274 | kv_free(kv_a(p->reduced_paths, i).coords); 1275 | } 1276 | kv_free(p->reduced_paths); 1277 | } 1278 | 1279 | p->num_commands = num_commands; 1280 | p->commands = (unsigned char*)malloc(num_commands * sizeof(unsigned char)); 1281 | memcpy(p->commands, commands, num_commands * sizeof(unsigned char)); 1282 | 1283 | p->num_coords = num_coords; 1284 | p->coords = (float *)malloc(num_coords * sizeof(float)); 1285 | memcpy(p->coords, coords, num_coords * sizeof(float)); 1286 | 1287 | kv_init(p->reduced_paths); 1288 | 1289 | reduce_path(num_commands, commands, num_coords, coords, &p->reduced_paths); 1290 | 1291 | p->is_fill_dirty = 1; 1292 | p->is_stroke_dirty = 1; 1293 | p->is_reduced_paths_dirty = 0; 1294 | } 1295 | 1296 | static void add_stroke_line(struct path *p, double x0, double y0, double x1, double y1) 1297 | { 1298 | struct geometry *g = &p->stroke_geoms[0]; 1299 | 1300 | double width = p->stroke_width; 1301 | 1302 | int index = kv_size(g->vertices) / 2; 1303 | 1304 | double dx = x1 - x0; 1305 | double dy = y1 - y0; 1306 | double len = sqrt(dx * dx + dy * dy); 1307 | if (len == 0) 1308 | return; 1309 | 1310 | dx /= len; 1311 | dy /= len; 1312 | 1313 | kv_push_back(g->vertices, x0 + (dy * width * 0.5)); 1314 | kv_push_back(g->vertices, y0 - (dx * width * 0.5)); 1315 | 1316 | kv_push_back(g->vertices, x1 + (dy * width * 0.5)); 1317 | kv_push_back(g->vertices, y1 - (dx * width * 0.5)); 1318 | 1319 | kv_push_back(g->vertices, x1 - (dy * width * 0.5)); 1320 | kv_push_back(g->vertices, y1 + (dx * width * 0.5)); 1321 | 1322 | kv_push_back(g->vertices, x0 - (dy * width * 0.5)); 1323 | kv_push_back(g->vertices, y0 + (dx * width * 0.5)); 1324 | 1325 | kv_push_back(g->indices, index); 1326 | kv_push_back(g->indices, index + 1); 1327 | kv_push_back(g->indices, index + 2); 1328 | 1329 | kv_push_back(g->indices, index); 1330 | kv_push_back(g->indices, index + 2); 1331 | kv_push_back(g->indices, index + 3); 1332 | } 1333 | 1334 | static void add_stroke_line_dashed(struct path *path, double x0, double y0, double x1, double y1, double *dash_offset) 1335 | { 1336 | if (path->num_dashes == 0) 1337 | { 1338 | add_stroke_line(path, x0, y0, x1, y1); 1339 | return; 1340 | } 1341 | 1342 | double length = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); 1343 | 1344 | /* TODO: remove this check and make sure that 0 length lines are not passed to this function (while creaating reduced path and while closing the path) */ 1345 | if (length == 0) 1346 | return; 1347 | 1348 | double offset = -fmod(*dash_offset, path->dash_length); 1349 | 1350 | int i = 0; 1351 | while (offset < length) 1352 | { 1353 | double o0 = MAX(offset, 0); 1354 | double o1 = MIN(offset + path->dashes[i], length); 1355 | 1356 | if (o1 >= 0) 1357 | { 1358 | double t0 = o0 / length; 1359 | double t1 = o1 / length; 1360 | 1361 | add_stroke_line(path, (1 - t0) * x0 + t0 * x1, (1 - t0) * y0 + t0 * y1, (1 - t1) * x0 + t1 * x1, (1 - t1) * y0 + t1 * y1); 1362 | } 1363 | 1364 | offset += path->dashes[i] + path->dashes[i + 1]; 1365 | i = (i + 2) % path->num_dashes; 1366 | } 1367 | 1368 | *dash_offset = fmod(length + *dash_offset, path->dash_length); 1369 | } 1370 | 1371 | static void evaluate_quadratic(double x0, double y0, double x1, double y1, double x2, double y2, double t, double *x, double *y) 1372 | { 1373 | double Ax = x0 - 2 * x1 + x2; 1374 | double Ay = y0 - 2 * y1 + y2; 1375 | double Bx = 2 * (x1 - x0); 1376 | double By = 2 * (y1 - y0); 1377 | double Cx = x0; 1378 | double Cy = y0; 1379 | 1380 | *x = Ax * t * t + Bx * t + Cx; 1381 | *y = Ay * t * t + By * t + Cy; 1382 | } 1383 | 1384 | static void get_quadratic_bounds(double x0, double y0, double x1, double y1, double x2, double y2, 1385 | double stroke_width, 1386 | double *minx, double *miny, double *maxx, double *maxy) 1387 | { 1388 | // TODO: if control point is exactly between start and end, division by zero occurs 1389 | double tx = (x0 - x1) / (x0 - 2 * x1 + x2); 1390 | double ty = (y0 - y1) / (y0 - 2 * y1 + y2); 1391 | 1392 | *minx = MIN(x0, x2); 1393 | *miny = MIN(y0, y2); 1394 | *maxx = MAX(x0, x2); 1395 | *maxy = MAX(y0, y2); 1396 | 1397 | if (0 < tx && tx < 1) 1398 | { 1399 | double x, y; 1400 | evaluate_quadratic(x0, y0, x1, y1, x2, y2, tx, &x, &y); 1401 | 1402 | *minx = MIN(*minx, x); 1403 | *miny = MIN(*miny, y); 1404 | *maxx = MAX(*maxx, x); 1405 | *maxy = MAX(*maxy, y); 1406 | } 1407 | 1408 | if (0 < ty && ty < 1) 1409 | { 1410 | double x, y; 1411 | evaluate_quadratic(x0, y0, x1, y1, x2, y2, ty, &x, &y); 1412 | 1413 | *minx = MIN(*minx, x); 1414 | *miny = MIN(*miny, y); 1415 | *maxx = MAX(*maxx, x); 1416 | *maxy = MAX(*maxy, y); 1417 | } 1418 | 1419 | *minx -= stroke_width * 0.5; 1420 | *miny -= stroke_width * 0.5; 1421 | *maxx += stroke_width * 0.5; 1422 | *maxy += stroke_width * 0.5; 1423 | } 1424 | 1425 | static double dot(double x0, double y0, double x1, double y1) 1426 | { 1427 | return x0 * x1 + y0 * y1; 1428 | } 1429 | 1430 | static void get_quadratic_bounds_oriented(double x0, double y0, double x1, double y1, double x2, double y2, 1431 | double stroke_width, 1432 | double *pcx, double *pcy, double *pux, double *puy, double *pvx, double *pvy) 1433 | { 1434 | double minx, miny, maxx, maxy; 1435 | double cx, cy; 1436 | double ex, ey; 1437 | 1438 | double ux = x2 - x0; 1439 | double uy = y2 - y0; 1440 | 1441 | double len = sqrt(ux * ux + uy * uy); 1442 | if (len < 1e-6) 1443 | { 1444 | ux = 1; 1445 | uy = 0; 1446 | } 1447 | else 1448 | { 1449 | ux /= len; 1450 | uy /= len; 1451 | } 1452 | 1453 | get_quadratic_bounds(0, 0, 1454 | dot(ux, uy, x1 - x0, y1 - y0), dot(-uy, ux, x1 - x0, y1 - y0), 1455 | dot(ux, uy, x2 - x0, y2 - y0), dot(-uy, ux, x2 - x0, y2 - y0), 1456 | stroke_width, 1457 | &minx, &miny, &maxx, &maxy); 1458 | 1459 | cx = (minx + maxx) / 2; 1460 | cy = (miny + maxy) / 2; 1461 | ex = (maxx - minx) / 2; 1462 | ey = (maxy - miny) / 2; 1463 | 1464 | *pcx = x0 + ux * cx + -uy * cy; 1465 | *pcy = y0 + uy * cx + ux * cy; 1466 | *pux = ux * ex; 1467 | *puy = uy * ex; 1468 | *pvx = -uy * ey; 1469 | *pvy = ux * ey; 1470 | } 1471 | 1472 | static void calculatepq(double Ax, double Ay, double Bx, double By, double Cx, double Cy, 1473 | double px, double py, 1474 | double *p, double *q) 1475 | { 1476 | double a = -2 * dot(Ax, Ay, Ax, Ay); 1477 | double b = -3 * dot(Ax, Ay, Bx, By); 1478 | double c = 2 * dot(px, py, Ax, Ay) - 2 * dot(Cx, Cy, Ax, Ay) - dot(Bx, By, Bx, By); 1479 | double d = dot(px, py, Bx, By) - dot(Cx, Cy, Bx, By); 1480 | 1481 | *p = (3 * a * c - b * b) / (3 * a * a); 1482 | *q = (2 * b * b * b - 9 * a * b * c + 27 * a * a * d) / (27 * a * a * a); 1483 | } 1484 | 1485 | 1486 | static double arc_length_helper(double A, double B, double C, double t) 1487 | { 1488 | /* Integrate[Sqrt[A t^2 + B t + C], t] */ 1489 | return (2 * sqrt(A) * (B + 2 * A * t) * sqrt(C + t * (B + A * t)) - (B * B - 4 * A * C) * log(B + 2 * A * t + 2 * sqrt(A) * sqrt(C + t * (B + A * t)))) / (8 * sqrt(A * A * A)); 1490 | } 1491 | 1492 | static double arc_length(double Ax, double Ay, double Bx, double By, double Cx, double Cy, double t) 1493 | { 1494 | double A = 4 * (Ax * Ax + Ay * Ay); 1495 | double B = 4 * (Ax * Bx + Ay * By); 1496 | double C = Bx * Bx + By * By; 1497 | 1498 | return arc_length_helper(A, B, C, t) - arc_length_helper(A, B, C, 0); 1499 | } 1500 | 1501 | static double inverse_arc_length(double Ax, double Ay, double Bx, double By, double Cx, double Cy, double u) 1502 | { 1503 | int i; 1504 | 1505 | double A = 4 * (Ax * Ax + Ay * Ay); 1506 | double B = 4 * (Ax * Bx + Ay * By); 1507 | double C = Bx * Bx + By * By; 1508 | 1509 | if (u <= 0) 1510 | return 0; 1511 | 1512 | double length = arc_length_helper(A, B, C, 1) - arc_length_helper(A, B, C, 0); 1513 | 1514 | if (u >= length) 1515 | return 1; 1516 | 1517 | double u0 = arc_length_helper(A, B, C, 0) + u; 1518 | 1519 | double a = 0; 1520 | double b = 1; 1521 | double fa = arc_length_helper(A, B, C, a) - u0; 1522 | double fb = arc_length_helper(A, B, C, b) - u0; 1523 | 1524 | for (i = 0; i < 20; ++i) 1525 | { 1526 | double c = (a + b) / 2; 1527 | double fc = arc_length_helper(A, B, C, c) - u0; 1528 | 1529 | if (fc < 0) 1530 | { 1531 | a = c; 1532 | fa = fc; 1533 | } 1534 | else if (fc > 0) 1535 | { 1536 | b = c; 1537 | fb = fc; 1538 | } 1539 | else 1540 | break; 1541 | } 1542 | 1543 | return a - fa * (b - a) / (fb - fa); 1544 | } 1545 | 1546 | static void quad_segment(const double qin[6], double t0, double t1, double qout[6]) 1547 | { 1548 | double u0 = 1 - t0; 1549 | double u1 = 1 - t1; 1550 | 1551 | double x0 = qin[0]; 1552 | double y0 = qin[1]; 1553 | double x1 = qin[2]; 1554 | double y1 = qin[3]; 1555 | double x2 = qin[4]; 1556 | double y2 = qin[5]; 1557 | 1558 | qout[0] = (u0 * u0) * x0 + (u0 * t0 + u0 * t0) * x1 + (t0 * t0) * x2; 1559 | qout[1] = (u0 * u0) * y0 + (u0 * t0 + u0 * t0) * y1 + (t0 * t0) * y2; 1560 | qout[2] = (u0 * u1) * x0 + (u0 * t1 + u1 * t0) * x1 + (t0 * t1) * x2; 1561 | qout[3] = (u0 * u1) * y0 + (u0 * t1 + u1 * t0) * y1 + (t0 * t1) * y2; 1562 | qout[4] = (u1 * u1) * x0 + (u1 * t1 + u1 * t1) * x1 + (t1 * t1) * x2; 1563 | qout[5] = (u1 * u1) * y0 + (u1 * t1 + u1 * t1) * y1 + (t1 * t1) * y2; 1564 | } 1565 | 1566 | 1567 | static void add_stroke_quad(struct path *path, double x0, double y0, double x1, double y1, double x2, double y2) 1568 | { 1569 | int i; 1570 | 1571 | double Ax = x0 - 2 * x1 + x2; 1572 | double Ay = y0 - 2 * y1 + y2; 1573 | double Bx = 2 * (x1 - x0); 1574 | double By = 2 * (y1 - y0); 1575 | double Cx = x0; 1576 | double Cy = y0; 1577 | 1578 | double cx, cy, ux, uy, vx, vy; 1579 | get_quadratic_bounds_oriented(x0, y0, x1, y1, x2, y2, path->stroke_width + 1, &cx, &cy, &ux, &uy, &vx, &vy); 1580 | 1581 | double a = -2 * dot(Ax, Ay, Ax, Ay); 1582 | double b = -3 * dot(Ax, Ay, Bx, By); 1583 | 1584 | double px[4], py[4]; 1585 | 1586 | px[0] = cx - ux - vx; 1587 | py[0] = cy - uy - vy; 1588 | px[1] = cx + ux - vx; 1589 | py[1] = cy + uy - vy; 1590 | px[2] = cx + ux + vx; 1591 | py[2] = cy + uy + vy; 1592 | px[3] = cx - ux + vx; 1593 | py[3] = cy - uy + vy; 1594 | 1595 | double p[4], q[4]; 1596 | for (i = 0; i < 4; ++i) 1597 | calculatepq(Ax, Ay, Bx, By, Cx, Cy, px[i], py[i], &p[i], &q[i]); 1598 | 1599 | struct geometry *g = &path->stroke_geoms[1]; 1600 | 1601 | int index = kv_size(g->vertices) / 12; 1602 | 1603 | for (i = 0; i < 4; ++i) 1604 | { 1605 | kv_push_back(g->vertices, px[i]); 1606 | kv_push_back(g->vertices, py[i]); 1607 | kv_push_back(g->vertices, p[i]); 1608 | kv_push_back(g->vertices, q[i]); 1609 | kv_push_back(g->vertices, Ax); 1610 | kv_push_back(g->vertices, Ay); 1611 | kv_push_back(g->vertices, Bx); 1612 | kv_push_back(g->vertices, By); 1613 | kv_push_back(g->vertices, Cx); 1614 | kv_push_back(g->vertices, Cy); 1615 | kv_push_back(g->vertices, -b / (3 * a)); 1616 | kv_push_back(g->vertices, path->stroke_width * path->stroke_width / 4); 1617 | } 1618 | 1619 | kv_push_back(g->indices, index); 1620 | kv_push_back(g->indices, index + 1); 1621 | kv_push_back(g->indices, index + 2); 1622 | 1623 | kv_push_back(g->indices, index); 1624 | kv_push_back(g->indices, index + 2); 1625 | kv_push_back(g->indices, index + 3); 1626 | } 1627 | 1628 | static void add_stroke_quad_dashed(struct path *path, double x0, double y0, double x1, double y1, double x2, double y2, double *dash_offset) 1629 | { 1630 | if (path->num_dashes == 0) 1631 | { 1632 | add_stroke_quad(path, x0, y0, x1, y1, x2, y2); 1633 | return; 1634 | } 1635 | 1636 | double Ax = x0 - 2 * x1 + x2; 1637 | double Ay = y0 - 2 * y1 + y2; 1638 | double Bx = 2 * (x1 - x0); 1639 | double By = 2 * (y1 - y0); 1640 | double Cx = x0; 1641 | double Cy = y0; 1642 | 1643 | double q[6] = { x0, y0, x1, y1, x2, y2 }; 1644 | 1645 | double length = arc_length(Ax, Ay, Bx, By, Cx, Cy, 1); 1646 | 1647 | double offset = -fmod(*dash_offset, path->dash_length); 1648 | 1649 | int i = 0; 1650 | while (offset < length) 1651 | { 1652 | double o0 = MAX(offset, 0); 1653 | double o1 = MIN(offset + path->dashes[i], length); 1654 | 1655 | if (o1 >= 0) 1656 | { 1657 | double t0 = inverse_arc_length(Ax, Ay, Bx, By, Cx, Cy, o0); 1658 | double t1 = inverse_arc_length(Ax, Ay, Bx, By, Cx, Cy, o1); 1659 | 1660 | double qout[6]; 1661 | quad_segment(q, t0, t1, qout); 1662 | add_stroke_quad(path, qout[0], qout[1], qout[2], qout[3], qout[4], qout[5]); 1663 | } 1664 | 1665 | offset += path->dashes[i] + path->dashes[i + 1]; 1666 | i = (i + 2) % path->num_dashes; 1667 | } 1668 | 1669 | *dash_offset = fmod(length + *dash_offset, path->dash_length); 1670 | } 1671 | 1672 | 1673 | static void add_join_miter_revert(struct path *path, float x0, float y0, float x1, float y1, float x2, float y2) 1674 | { 1675 | 1676 | } 1677 | 1678 | static void add_join_miter_truncate(struct path *path, float x0, float y0, float x1, float y1, float x2, float y2) 1679 | { 1680 | 1681 | } 1682 | 1683 | static void add_join_bevel(struct path *path, float x0, float y0, float x1, float y1, float x2, float y2) 1684 | { 1685 | float v0x = x0 - x1; 1686 | float v0y = y0 - y1; 1687 | float v1x = x2 - x1; 1688 | float v1y = y2 - y1; 1689 | 1690 | float len0 = sqrtf(v0x * v0x + v0y * v0y); 1691 | float len1 = sqrtf(v1x * v1x + v1y * v1y); 1692 | 1693 | if (len0 == 0 || len1 == 0) 1694 | return; 1695 | 1696 | struct geometry *g = &path->stroke_geoms[0]; 1697 | 1698 | float width = path->stroke_width; 1699 | 1700 | int index = kv_size(g->vertices) / 2; 1701 | 1702 | float w0 = width / (2 * len0); 1703 | float w1 = width / (2 * len1); 1704 | 1705 | if (v0x * v1y - v0y * v1x < 0) 1706 | { 1707 | kv_push_back(g->vertices, x1 + v1y * w1); 1708 | kv_push_back(g->vertices, y1 + -v1x * w1); 1709 | kv_push_back(g->vertices, x1); 1710 | kv_push_back(g->vertices, y1); 1711 | kv_push_back(g->vertices, x1 + -v0y * w0); 1712 | kv_push_back(g->vertices, y1 + v0x * w0); 1713 | } 1714 | else 1715 | { 1716 | kv_push_back(g->vertices, x1 + v0y * w0); 1717 | kv_push_back(g->vertices, y1 + -v0x * w0); 1718 | kv_push_back(g->vertices, x1); 1719 | kv_push_back(g->vertices, y1); 1720 | kv_push_back(g->vertices, x1 + -v1y * w1); 1721 | kv_push_back(g->vertices, y1 + v1x * w1); 1722 | } 1723 | 1724 | kv_push_back(g->indices, index); 1725 | kv_push_back(g->indices, index + 1); 1726 | kv_push_back(g->indices, index + 2); 1727 | } 1728 | 1729 | static void add_join_round(struct path *path, float x0, float y0, float x1, float y1, float x2, float y2) 1730 | { 1731 | 1732 | } 1733 | 1734 | static int check_offset(struct path *path, float of) 1735 | { 1736 | int i; 1737 | 1738 | if (path->num_dashes == 0) 1739 | return 1; 1740 | 1741 | float offset = 0; 1742 | for (i = 0; i < path->num_dashes; i += 2) 1743 | { 1744 | float o0 = offset; 1745 | float o1 = offset + path->dashes[i]; 1746 | 1747 | if (o0 <= of && of <= o1) 1748 | return 1; 1749 | 1750 | offset += path->dashes[i] + path->dashes[i + 1]; 1751 | } 1752 | 1753 | return 0; 1754 | } 1755 | 1756 | static void add_join(struct path *path, float x0, float y0, float x1, float y1, float x2, float y2) 1757 | { 1758 | switch (path->join_style) 1759 | { 1760 | case GL_MITER_REVERT_AC: 1761 | add_join_miter_revert(path, x0, y0, x1, y1, x2, y2); 1762 | break; 1763 | case GL_MITER_TRUNCATE_AC: 1764 | add_join_miter_truncate(path, x0, y0, x1, y1, x2, y2); 1765 | break; 1766 | case GL_BEVEL_AC: 1767 | add_join_bevel(path, x0, y0, x1, y1, x2, y2); 1768 | break; 1769 | case GL_ROUND_AC: 1770 | add_join_round(path, x0, y0, x1, y1, x2, y2); 1771 | break; 1772 | case GL_NONE: 1773 | break; 1774 | } 1775 | } 1776 | 1777 | typedef kvec_t(float) kvec_float_t; 1778 | 1779 | static void corner_start(kvec_float_t *v, float x, float y, float offset) 1780 | { 1781 | kv_push_back(*v, x); 1782 | kv_push_back(*v, y); 1783 | kv_push_back(*v, offset); 1784 | } 1785 | 1786 | static void corner_continue(kvec_float_t *v, float x0, float y0, float x1, float y1, float offset) 1787 | { 1788 | float x = kv_a(*v, kv_size(*v) - 3); 1789 | float y = kv_a(*v, kv_size(*v) - 2); 1790 | 1791 | // TODO: check equality with epsilon 1792 | if (x != x0 || x != x1 || x0 != x1 || y != y0 || y != y1 || y0 != y1) 1793 | { 1794 | kv_push_back(*v, x0); 1795 | kv_push_back(*v, y0); 1796 | kv_push_back(*v, x1); 1797 | kv_push_back(*v, y1); 1798 | kv_push_back(*v, offset); 1799 | } 1800 | } 1801 | 1802 | static void corner_end(kvec_float_t *v, float x, float y) 1803 | { 1804 | float x0 = kv_a(*v, 0); 1805 | float y0 = kv_a(*v, 1); 1806 | 1807 | float x1 = kv_a(*v, kv_size(*v) - 3); 1808 | float y1 = kv_a(*v, kv_size(*v) - 2); 1809 | 1810 | // TODO: check equality with epsilon 1811 | if (x != x0 || x != x1 || x0 != x1 || y != y0 || y != y1 || y0 != y1) 1812 | { 1813 | kv_push_back(*v, x); 1814 | kv_push_back(*v, y); 1815 | } 1816 | else 1817 | { 1818 | kv_pop_back(*v); 1819 | kv_pop_back(*v); 1820 | kv_pop_back(*v); 1821 | } 1822 | } 1823 | 1824 | static void update_bounds(float bounds[4], size_t num_vertices, const float *vertices, int stride) 1825 | { 1826 | size_t i; 1827 | 1828 | for (i = 0; i < num_vertices; i += stride) 1829 | { 1830 | float x = vertices[i]; 1831 | float y = vertices[i + 1]; 1832 | 1833 | bounds[0] = MIN(bounds[0], x); 1834 | bounds[1] = MIN(bounds[1], y); 1835 | bounds[2] = MAX(bounds[2], x); 1836 | bounds[3] = MAX(bounds[3], y); 1837 | } 1838 | } 1839 | 1840 | static void create_stroke_geometry(struct path *path) 1841 | { 1842 | #define c0 coords[icoord] 1843 | #define c1 coords[icoord + 1] 1844 | #define c2 coords[icoord + 2] 1845 | #define c3 coords[icoord + 3] 1846 | 1847 | #define set(x1, y1, x2, y2) ncpx = x1; ncpy = y1; npepx = x2; npepy = y2; 1848 | 1849 | reduced_path_vec *reduced_paths = &path->reduced_paths; 1850 | 1851 | size_t i, j; 1852 | 1853 | for (i = 0; i < 2; ++i) 1854 | { 1855 | kv_init(path->stroke_geoms[i].vertices); 1856 | kv_init(path->stroke_geoms[i].indices); 1857 | } 1858 | 1859 | double offset = 0; 1860 | 1861 | for (i = 0; i < kv_size(*reduced_paths); ++i) 1862 | { 1863 | struct reduced_path *p = &kv_a(*reduced_paths, i); 1864 | 1865 | kvec_float_t corners; 1866 | kv_init(corners); 1867 | 1868 | size_t num_commands = kv_size(p->commands); 1869 | unsigned char *commands = kv_data(p->commands); 1870 | float *coords = kv_data(p->coords); 1871 | 1872 | int closed = 0; 1873 | 1874 | int icoord = 0; 1875 | 1876 | float spx = 0, spy = 0; 1877 | float cpx = 0, cpy = 0; 1878 | float pepx = 0, pepy = 0; 1879 | float ncpx = 0, ncpy = 0; 1880 | float npepx = 0, npepy = 0; 1881 | 1882 | for (j = 0; j < num_commands; ++j) 1883 | { 1884 | switch (commands[j]) 1885 | { 1886 | case GL_MOVE_TO_AC: 1887 | corner_start(&corners, c0, c1, offset); 1888 | set(c0, c1, c0, c1); 1889 | spx = ncpx; 1890 | spy = ncpy; 1891 | icoord += 2; 1892 | break; 1893 | case GL_LINE_TO_AC: 1894 | add_stroke_line_dashed(path, cpx, cpy, c0, c1, &offset); 1895 | corner_continue(&corners, (cpx + c0) / 2, (cpy + c1) / 2, c0, c1, offset); 1896 | set(c0, c1, c0, c1); 1897 | icoord += 2; 1898 | break; 1899 | case GL_QUADRATIC_CURVE_TO_AC: 1900 | add_stroke_quad_dashed(path, cpx, cpy, c0, c1, c2, c3, &offset); 1901 | corner_continue(&corners, c0, c1, c2, c3, offset); 1902 | set(c2, c3, c0, c1); 1903 | icoord += 4; 1904 | break; 1905 | case GL_CLOSE_PATH_AC: 1906 | add_stroke_line_dashed(path, cpx, cpy, spx, spy, &offset); 1907 | corner_end(&corners, (cpx + spx) / 2, (cpy + spy) / 2); 1908 | set(spx, spy, spx, spy); 1909 | closed = 1; 1910 | break; 1911 | } 1912 | 1913 | cpx = ncpx; 1914 | cpy = ncpy; 1915 | pepx = npepx; 1916 | pepy = npepy; 1917 | } 1918 | 1919 | size_t ncorners = (kv_size(corners) - (closed ? 0 : 7)) / 5; 1920 | 1921 | for (j = 0; j < ncorners; j++) 1922 | { 1923 | int j0 = j; 1924 | int j1 = (j + 1) % ncorners; 1925 | 1926 | float x0 = kv_a(corners, j0 * 5 + 3); 1927 | float y0 = kv_a(corners, j0 * 5 + 4); 1928 | float x1 = kv_a(corners, j1 * 5 + 0); 1929 | float y1 = kv_a(corners, j1 * 5 + 1); 1930 | float of = kv_a(corners, j1 * 5 + 2); 1931 | float x2 = kv_a(corners, j1 * 5 + 3); 1932 | float y2 = kv_a(corners, j1 * 5 + 4); 1933 | 1934 | if (check_offset(path, of)) 1935 | add_join(path, x0, y0, x1, y1, x2, y2); 1936 | } 1937 | 1938 | kv_free(corners); 1939 | } 1940 | 1941 | #undef c0 1942 | #undef c1 1943 | #undef c2 1944 | #undef c3 1945 | 1946 | #undef set 1947 | 1948 | path->stroke_bounds[0] = 1e30f; 1949 | path->stroke_bounds[1] = 1e30f; 1950 | path->stroke_bounds[2] = -1e30f; 1951 | path->stroke_bounds[3] = -1e30f; 1952 | 1953 | update_bounds(path->stroke_bounds, kv_size(path->stroke_geoms[0].vertices), kv_data(path->stroke_geoms[0].vertices), 2); 1954 | update_bounds(path->stroke_bounds, kv_size(path->stroke_geoms[1].vertices), kv_data(path->stroke_geoms[1].vertices), 12); 1955 | 1956 | for (i = 0; i < 2; ++i) 1957 | { 1958 | glBindBuffer(GL_ARRAY_BUFFER, path->stroke_geoms[i].vertex_buffer); 1959 | glBufferData(GL_ARRAY_BUFFER, kv_size(path->stroke_geoms[i].vertices) * sizeof(float), kv_data(path->stroke_geoms[i].vertices), GL_STATIC_DRAW); 1960 | 1961 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, path->stroke_geoms[i].index_buffer); 1962 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, kv_size(path->stroke_geoms[i].indices) * sizeof(unsigned short), kv_data(path->stroke_geoms[i].indices), GL_STATIC_DRAW); 1963 | 1964 | path->stroke_geoms[i].count = kv_size(path->stroke_geoms[i].indices); 1965 | 1966 | kv_free(path->stroke_geoms[i].vertices); 1967 | kv_free(path->stroke_geoms[i].indices); 1968 | } 1969 | 1970 | /* TODO: save/restore */ 1971 | glBindBuffer(GL_ARRAY_BUFFER, 0); 1972 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 1973 | } 1974 | 1975 | static void add_fill_line(struct path *p, float xc, float yc, float x0, float y0, float x1, float y1) 1976 | { 1977 | float v0x = x0 - xc; 1978 | float v0y = y0 - yc; 1979 | float v1x = x1 - xc; 1980 | float v1y = y1 - yc; 1981 | 1982 | struct geometry *g = NULL; 1983 | int index; 1984 | 1985 | if (v0x * v1y - v0y * v1x < 0) 1986 | { 1987 | g = &p->fill_geoms[1]; 1988 | 1989 | index = kv_size(g->vertices) / 4; 1990 | 1991 | kv_push_back(g->vertices, xc); 1992 | kv_push_back(g->vertices, yc); 1993 | kv_push_back(g->vertices, 0); 1994 | kv_push_back(g->vertices, 0); 1995 | 1996 | kv_push_back(g->vertices, x1); 1997 | kv_push_back(g->vertices, y1); 1998 | kv_push_back(g->vertices, 0); 1999 | kv_push_back(g->vertices, 0); 2000 | 2001 | kv_push_back(g->vertices, x0); 2002 | kv_push_back(g->vertices, y0); 2003 | kv_push_back(g->vertices, 0); 2004 | kv_push_back(g->vertices, 0); 2005 | } 2006 | else 2007 | { 2008 | g = &p->fill_geoms[0]; 2009 | 2010 | index = kv_size(g->vertices) / 4; 2011 | 2012 | kv_push_back(g->vertices, xc); 2013 | kv_push_back(g->vertices, yc); 2014 | kv_push_back(g->vertices, 0); 2015 | kv_push_back(g->vertices, 0); 2016 | 2017 | kv_push_back(g->vertices, x0); 2018 | kv_push_back(g->vertices, y0); 2019 | kv_push_back(g->vertices, 0); 2020 | kv_push_back(g->vertices, 0); 2021 | 2022 | kv_push_back(g->vertices, x1); 2023 | kv_push_back(g->vertices, y1); 2024 | kv_push_back(g->vertices, 0); 2025 | kv_push_back(g->vertices, 0); 2026 | } 2027 | 2028 | kv_push_back(g->indices, index); 2029 | kv_push_back(g->indices, index + 1); 2030 | kv_push_back(g->indices, index + 2); 2031 | } 2032 | 2033 | static void add_fill_quad(struct path *p, float xc, float yc, float x0, float y0, float x1, float y1, float x2, float y2) 2034 | { 2035 | float v0x, v0y, v1x, v1y; 2036 | 2037 | v0x = x0 - xc; 2038 | v0y = y0 - yc; 2039 | v1x = x2 - xc; 2040 | v1y = y2 - yc; 2041 | 2042 | if (v0x * v1y - v0y * v1x < 0) 2043 | { 2044 | struct geometry *g = &p->fill_geoms[1]; 2045 | 2046 | int index = kv_size(g->vertices) / 4; 2047 | 2048 | kv_push_back(g->vertices, xc); 2049 | kv_push_back(g->vertices, yc); 2050 | kv_push_back(g->vertices, 0); 2051 | kv_push_back(g->vertices, 0); 2052 | 2053 | kv_push_back(g->vertices, x2); 2054 | kv_push_back(g->vertices, y2); 2055 | kv_push_back(g->vertices, 0); 2056 | kv_push_back(g->vertices, 0); 2057 | 2058 | kv_push_back(g->vertices, x0); 2059 | kv_push_back(g->vertices, y0); 2060 | kv_push_back(g->vertices, 0); 2061 | kv_push_back(g->vertices, 0); 2062 | 2063 | kv_push_back(g->indices, index); 2064 | kv_push_back(g->indices, index + 1); 2065 | kv_push_back(g->indices, index + 2); 2066 | } 2067 | else 2068 | { 2069 | struct geometry *g = &p->fill_geoms[0]; 2070 | 2071 | int index = kv_size(g->vertices) / 4; 2072 | 2073 | kv_push_back(g->vertices, xc); 2074 | kv_push_back(g->vertices, yc); 2075 | kv_push_back(g->vertices, 0); 2076 | kv_push_back(g->vertices, 0); 2077 | 2078 | kv_push_back(g->vertices, x0); 2079 | kv_push_back(g->vertices, y0); 2080 | kv_push_back(g->vertices, 0); 2081 | kv_push_back(g->vertices, 0); 2082 | 2083 | kv_push_back(g->vertices, x2); 2084 | kv_push_back(g->vertices, y2); 2085 | kv_push_back(g->vertices, 0); 2086 | kv_push_back(g->vertices, 0); 2087 | 2088 | kv_push_back(g->indices, index); 2089 | kv_push_back(g->indices, index + 1); 2090 | kv_push_back(g->indices, index + 2); 2091 | } 2092 | 2093 | v0x = x1 - x0; 2094 | v0y = y1 - y0; 2095 | v1x = x2 - x0; 2096 | v1y = y2 - y0; 2097 | 2098 | if (v0x * v1y - v0y * v1x < 0) 2099 | { 2100 | struct geometry *g = &p->fill_geoms[3]; 2101 | 2102 | int index = kv_size(g->vertices) / 4; 2103 | 2104 | kv_push_back(g->vertices, x0); 2105 | kv_push_back(g->vertices, y0); 2106 | kv_push_back(g->vertices, 0); 2107 | kv_push_back(g->vertices, 0); 2108 | 2109 | kv_push_back(g->vertices, x2); 2110 | kv_push_back(g->vertices, y2); 2111 | kv_push_back(g->vertices, 1); 2112 | kv_push_back(g->vertices, 1); 2113 | 2114 | kv_push_back(g->vertices, x1); 2115 | kv_push_back(g->vertices, y1); 2116 | kv_push_back(g->vertices, 0.5f); 2117 | kv_push_back(g->vertices, 0); 2118 | 2119 | kv_push_back(g->indices, index); 2120 | kv_push_back(g->indices, index + 1); 2121 | kv_push_back(g->indices, index + 2); 2122 | } 2123 | else 2124 | { 2125 | struct geometry *g = &p->fill_geoms[2]; 2126 | 2127 | int index = kv_size(g->vertices) / 4; 2128 | 2129 | kv_push_back(g->vertices, x2); 2130 | kv_push_back(g->vertices, y2); 2131 | kv_push_back(g->vertices, 1); 2132 | kv_push_back(g->vertices, 1); 2133 | 2134 | kv_push_back(g->vertices, x0); 2135 | kv_push_back(g->vertices, y0); 2136 | kv_push_back(g->vertices, 0); 2137 | kv_push_back(g->vertices, 0); 2138 | 2139 | kv_push_back(g->vertices, x1); 2140 | kv_push_back(g->vertices, y1); 2141 | kv_push_back(g->vertices, 0.5f); 2142 | kv_push_back(g->vertices, 0); 2143 | 2144 | kv_push_back(g->indices, index); 2145 | kv_push_back(g->indices, index + 1); 2146 | kv_push_back(g->indices, index + 2); 2147 | } 2148 | } 2149 | 2150 | static void create_fill_geometry(struct path *path) 2151 | { 2152 | #define c0 coords[icoord] 2153 | #define c1 coords[icoord + 1] 2154 | #define c2 coords[icoord + 2] 2155 | #define c3 coords[icoord + 3] 2156 | 2157 | #define set(x1, y1, x2, y2) ncpx = x1; ncpy = y1; npepx = x2; npepy = y2; 2158 | 2159 | reduced_path_vec *reduced_paths = &path->reduced_paths; 2160 | 2161 | size_t i, j; 2162 | 2163 | for (i = 0; i < 4; ++i) 2164 | { 2165 | kv_init(path->fill_geoms[i].vertices); 2166 | kv_init(path->fill_geoms[i].indices); 2167 | } 2168 | 2169 | for (i = 0; i < kv_size(*reduced_paths); ++i) 2170 | { 2171 | struct reduced_path *p = &kv_a(*reduced_paths, i); 2172 | 2173 | size_t num_commands = kv_size(p->commands); 2174 | unsigned char *commands = kv_data(p->commands); 2175 | float *coords = kv_data(p->coords); 2176 | 2177 | int closed = 0; 2178 | 2179 | int icoord = 0; 2180 | 2181 | float spx = 0, spy = 0; 2182 | float cpx = 0, cpy = 0; 2183 | float pepx = 0, pepy = 0; 2184 | float ncpx = 0, ncpy = 0; 2185 | float npepx = 0, npepy = 0; 2186 | 2187 | float xc, yc; 2188 | 2189 | for (j = 0; j < num_commands; ++j) 2190 | { 2191 | switch (commands[j]) 2192 | { 2193 | case GL_MOVE_TO_AC: 2194 | set(c0, c1, c0, c1); 2195 | spx = ncpx; 2196 | spy = ncpy; 2197 | xc = spx; 2198 | yc = spy; 2199 | icoord += 2; 2200 | break; 2201 | case GL_LINE_TO_AC: 2202 | add_fill_line(path, xc, yc, cpx, cpy, c0, c1); 2203 | set(c0, c1, c0, c1); 2204 | icoord += 2; 2205 | break; 2206 | case GL_QUADRATIC_CURVE_TO_AC: 2207 | add_fill_quad(path, xc, yc, cpx, cpy, c0, c1, c2, c3); 2208 | set(c2, c3, c0, c1); 2209 | icoord += 4; 2210 | break; 2211 | case GL_CLOSE_PATH_AC: 2212 | add_fill_line(path, xc, yc, cpx, cpy, spx, spy); 2213 | set(spx, spy, spx, spy); 2214 | closed = 1; 2215 | break; 2216 | } 2217 | 2218 | cpx = ncpx; 2219 | cpy = ncpy; 2220 | pepx = npepx; 2221 | pepy = npepy; 2222 | } 2223 | 2224 | if (closed == 0) 2225 | { 2226 | // TODO: close the fill geometry 2227 | } 2228 | } 2229 | 2230 | #undef c0 2231 | #undef c1 2232 | #undef c2 2233 | #undef c3 2234 | 2235 | #undef set 2236 | 2237 | path->fill_bounds[0] = 1e30f; 2238 | path->fill_bounds[1] = 1e30f; 2239 | path->fill_bounds[2] = -1e30f; 2240 | path->fill_bounds[3] = -1e30f; 2241 | 2242 | update_bounds(path->fill_bounds, kv_size(path->fill_geoms[0].vertices), kv_data(path->fill_geoms[0].vertices), 4); 2243 | update_bounds(path->fill_bounds, kv_size(path->fill_geoms[1].vertices), kv_data(path->fill_geoms[1].vertices), 4); 2244 | update_bounds(path->fill_bounds, kv_size(path->fill_geoms[2].vertices), kv_data(path->fill_geoms[2].vertices), 4); 2245 | update_bounds(path->fill_bounds, kv_size(path->fill_geoms[3].vertices), kv_data(path->fill_geoms[3].vertices), 4); 2246 | 2247 | struct merger4f m; 2248 | init_merger4f(&m); 2249 | 2250 | path->fill_starts[0] = kv_size(m.indices); 2251 | merge4f(&m, kv_data(path->fill_geoms[0].vertices), kv_data(path->fill_geoms[0].indices), kv_size(path->fill_geoms[0].indices)); 2252 | merge4f(&m, kv_data(path->fill_geoms[2].vertices), kv_data(path->fill_geoms[2].indices), kv_size(path->fill_geoms[2].indices)); 2253 | path->fill_counts[0] = kv_size(m.indices) - path->fill_starts[0]; 2254 | path->fill_starts[1] = kv_size(m.indices); 2255 | merge4f(&m, kv_data(path->fill_geoms[1].vertices), kv_data(path->fill_geoms[1].indices), kv_size(path->fill_geoms[1].indices)); 2256 | merge4f(&m, kv_data(path->fill_geoms[3].vertices), kv_data(path->fill_geoms[3].indices), kv_size(path->fill_geoms[3].indices)); 2257 | path->fill_counts[1] = kv_size(m.indices) - path->fill_starts[1]; 2258 | 2259 | glBindBuffer(GL_ARRAY_BUFFER, path->fill_vertex_buffer); 2260 | glBufferData(GL_ARRAY_BUFFER, kv_size(m.vertices) * 4 * sizeof(float), kv_data(m.vertices), GL_STATIC_DRAW); 2261 | 2262 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, path->fill_index_buffer); 2263 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, kv_size(m.indices) * sizeof(unsigned short), kv_data(m.indices), GL_STATIC_DRAW); 2264 | 2265 | free_merger4f(&m); 2266 | 2267 | for (i = 0; i < 4; ++i) 2268 | { 2269 | #if 0 2270 | glBindBuffer(GL_ARRAY_BUFFER, path->fill_geoms[i].vertex_buffer); 2271 | glBufferData(GL_ARRAY_BUFFER, kv_size(path->fill_geoms[i].vertices) * sizeof(float), kv_data(path->fill_geoms[i].vertices), GL_STATIC_DRAW); 2272 | 2273 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, path->fill_geoms[i].index_buffer); 2274 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, kv_size(path->fill_geoms[i].indices) * sizeof(unsigned short), kv_data(path->fill_geoms[i].indices), GL_STATIC_DRAW); 2275 | 2276 | path->fill_geoms[i].count = kv_size(path->fill_geoms[i].indices); 2277 | #endif 2278 | 2279 | kv_free(path->fill_geoms[i].vertices); 2280 | kv_free(path->fill_geoms[i].indices); 2281 | } 2282 | 2283 | /* TODO: save/restore */ 2284 | glBindBuffer(GL_ARRAY_BUFFER, 0); 2285 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 2286 | } 2287 | 2288 | void init_path_rendering() 2289 | { 2290 | int i; 2291 | 2292 | paths = kh_init(path); 2293 | 2294 | init_segments(); 2295 | 2296 | for (i = 0; i < 256; ++i) 2297 | command_coords[i] = -1; 2298 | 2299 | command_coords[GL_CLOSE_PATH_AC] = 0; 2300 | command_coords['Z'] = 0; 2301 | command_coords['z'] = 0; 2302 | command_coords[GL_MOVE_TO_AC] = 2; 2303 | command_coords['M'] = 2; 2304 | command_coords[GL_RELATIVE_MOVE_TO_AC] = 2; 2305 | command_coords['m'] = 2; 2306 | command_coords[GL_LINE_TO_AC] = 2; 2307 | command_coords['L'] = 2; 2308 | command_coords[GL_RELATIVE_LINE_TO_AC] = 2; 2309 | command_coords['l'] = 2; 2310 | command_coords[GL_HORIZONTAL_LINE_TO_AC] = 1; 2311 | command_coords['H'] = 1; 2312 | command_coords[GL_RELATIVE_HORIZONTAL_LINE_TO_AC] = 1; 2313 | command_coords['h'] = 1; 2314 | command_coords[GL_VERTICAL_LINE_TO_AC] = 1; 2315 | command_coords['V'] = 1; 2316 | command_coords[GL_RELATIVE_VERTICAL_LINE_TO_AC] = 1; 2317 | command_coords['v'] = 1; 2318 | command_coords[GL_QUADRATIC_CURVE_TO_AC] = 4; 2319 | command_coords['Q'] = 4; 2320 | command_coords[GL_RELATIVE_QUADRATIC_CURVE_TO_AC] = 4; 2321 | command_coords['q'] = 4; 2322 | command_coords[GL_CUBIC_CURVE_TO_AC] = 6; 2323 | command_coords['C'] = 6; 2324 | command_coords[GL_RELATIVE_CUBIC_CURVE_TO_AC] = 6; 2325 | command_coords['c'] = 6; 2326 | command_coords[GL_SMOOTH_QUADRATIC_CURVE_TO_AC] = 2; 2327 | command_coords['T'] = 2; 2328 | command_coords[GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_AC] = 2; 2329 | command_coords['t'] = 2; 2330 | command_coords[GL_SMOOTH_CUBIC_CURVE_TO_AC] = 4; 2331 | command_coords['S'] = 4; 2332 | command_coords[GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_AC] = 4; 2333 | command_coords['s'] = 4; 2334 | command_coords[GL_SMALL_CCW_ARC_TO_AC] = 5; 2335 | command_coords[GL_RELATIVE_SMALL_CCW_ARC_TO_AC] = 5; 2336 | command_coords[GL_SMALL_CW_ARC_TO_AC] = 5; 2337 | command_coords[GL_RELATIVE_SMALL_CW_ARC_TO_AC] = 5; 2338 | command_coords[GL_LARGE_CCW_ARC_TO_AC] = 5; 2339 | command_coords[GL_RELATIVE_LARGE_CCW_ARC_TO_AC] = 5; 2340 | command_coords[GL_LARGE_CW_ARC_TO_AC] = 5; 2341 | command_coords[GL_RELATIVE_LARGE_CW_ARC_TO_AC] = 5; 2342 | command_coords[GL_RESTART_PATH_AC] = 0; 2343 | command_coords[GL_DUP_FIRST_CUBIC_CURVE_TO_AC] = 4; 2344 | command_coords[GL_DUP_LAST_CUBIC_CURVE_TO_AC] = 4; 2345 | command_coords[GL_RECT_AC] = 4; 2346 | command_coords[GL_CIRCULAR_CCW_ARC_TO_AC] = 5; 2347 | command_coords[GL_CIRCULAR_CW_ARC_TO_AC] = 5; 2348 | command_coords[GL_CIRCULAR_TANGENT_ARC_TO_AC] = 5; 2349 | command_coords[GL_ARC_TO_AC] = 7; 2350 | command_coords['A'] = 7; 2351 | command_coords[GL_RELATIVE_ARC_TO_AC] = 7; 2352 | command_coords['a'] = 7; 2353 | 2354 | { 2355 | GLuint vs = glCreateShader(GL_VERTEX_SHADER); 2356 | glShaderSource(vs, 1, &vs_code0, NULL); 2357 | glCompileShader(vs); 2358 | 2359 | GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); 2360 | glShaderSource(fs, 1, &fs_code0, NULL); 2361 | glCompileShader(fs); 2362 | 2363 | program0 = glCreateProgram(); 2364 | glAttachShader(program0, vs); 2365 | glAttachShader(program0, fs); 2366 | glBindAttribLocation(program0, DATA0_POS, "data0"); 2367 | glDeleteShader(vs); 2368 | glDeleteShader(fs); 2369 | glLinkProgram(program0); 2370 | 2371 | matrix0 = glGetUniformLocation(program0, "matrix"); 2372 | #ifdef OPENGL_ES 2373 | mvp0 = glGetUniformLocation(program0, "mvp"); 2374 | #endif 2375 | } 2376 | 2377 | { 2378 | GLuint vs = glCreateShader(GL_VERTEX_SHADER); 2379 | glShaderSource(vs, 1, &vs_code1, NULL); 2380 | glCompileShader(vs); 2381 | 2382 | GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); 2383 | glShaderSource(fs, 1, &fs_code1, NULL); 2384 | glCompileShader(fs); 2385 | 2386 | program1 = glCreateProgram(); 2387 | glAttachShader(program1, vs); 2388 | glAttachShader(program1, fs); 2389 | glBindAttribLocation(program1, DATA0_POS, "data0"); 2390 | glDeleteShader(vs); 2391 | glDeleteShader(fs); 2392 | glLinkProgram(program1); 2393 | 2394 | matrix1 = glGetUniformLocation(program1, "matrix"); 2395 | #ifdef OPENGL_ES 2396 | mvp1 = glGetUniformLocation(program0, "mvp"); 2397 | #endif 2398 | } 2399 | 2400 | { 2401 | GLuint vs = glCreateShader(GL_VERTEX_SHADER); 2402 | glShaderSource(vs, 1, &vs_code2, NULL); 2403 | glCompileShader(vs); 2404 | 2405 | GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); 2406 | glShaderSource(fs, 1, &fs_code2, NULL); 2407 | glCompileShader(fs); 2408 | 2409 | program2 = glCreateProgram(); 2410 | glAttachShader(program2, vs); 2411 | glAttachShader(program2, fs); 2412 | glBindAttribLocation(program2, DATA0_POS, "data0"); 2413 | glBindAttribLocation(program2, DATA1_POS, "data1"); 2414 | glBindAttribLocation(program2, DATA2_POS, "data2"); 2415 | glDeleteShader(vs); 2416 | glDeleteShader(fs); 2417 | glLinkProgram(program2); 2418 | 2419 | matrix2 = glGetUniformLocation(program2, "matrix"); 2420 | #ifdef OPENGL_ES 2421 | mvp2 = glGetUniformLocation(program0, "mvp"); 2422 | #endif 2423 | } 2424 | 2425 | { 2426 | GLuint vs = glCreateShader(GL_VERTEX_SHADER); 2427 | glShaderSource(vs, 1, &vs_code3, NULL); 2428 | glCompileShader(vs); 2429 | 2430 | GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); 2431 | glShaderSource(fs, 1, &fs_code3, NULL); 2432 | glCompileShader(fs); 2433 | 2434 | program3 = glCreateProgram(); 2435 | glAttachShader(program3, vs); 2436 | glAttachShader(program3, fs); 2437 | glBindAttribLocation(program3, DATA0_POS, "data0"); 2438 | glDeleteShader(vs); 2439 | glDeleteShader(fs); 2440 | glLinkProgram(program3); 2441 | 2442 | matrix3 = glGetUniformLocation(program3, "matrix"); 2443 | #ifdef OPENGL_ES 2444 | mvp3 = glGetUniformLocation(program0, "mvp"); 2445 | #endif 2446 | } 2447 | 2448 | #ifdef OPENGL_ES 2449 | memcpy(g_mvp, identity_matrix, 16 * sizeof(float)); 2450 | #endif 2451 | } 2452 | 2453 | void cleanup_path_rendering() 2454 | { 2455 | cleanup_segments(); 2456 | kh_destroy(path, paths); 2457 | } 2458 | 2459 | GLuint glGenPathsAC(GLsizei range) 2460 | { 2461 | return gen_paths(range); 2462 | } 2463 | 2464 | void glDeletePathsAC(GLuint path, GLsizei range) 2465 | { 2466 | delete_paths(path, range); 2467 | } 2468 | 2469 | GLboolean glIsPathAC(GLuint path) 2470 | { 2471 | return kh_get(path, paths, path) != kh_end(paths); 2472 | } 2473 | 2474 | void glPathCommandsAC(GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords) 2475 | { 2476 | float *coords2; 2477 | if (coordType != GL_BYTE && 2478 | coordType != GL_UNSIGNED_BYTE && 2479 | coordType != GL_SHORT && 2480 | coordType != GL_UNSIGNED_SHORT && 2481 | coordType != GL_FLOAT) 2482 | { 2483 | // TODO: set error 2484 | return; 2485 | } 2486 | 2487 | coords2 = (float*)malloc(numCoords * sizeof(float)); 2488 | 2489 | if (coordType == GL_BYTE) 2490 | { 2491 | GLbyte *coords3 = (GLbyte*)coords; 2492 | int i; 2493 | for (i = 0; i < numCoords; ++i) 2494 | coords2[i] = coords3[i]; 2495 | } 2496 | else if (coordType == GL_UNSIGNED_BYTE) 2497 | { 2498 | GLubyte *coords3 = (GLubyte*)coords; 2499 | int i; 2500 | for (i = 0; i < numCoords; ++i) 2501 | coords2[i] = coords3[i]; 2502 | } 2503 | else if (coordType == GL_SHORT) 2504 | { 2505 | GLshort *coords3 = (GLshort*)coords; 2506 | int i; 2507 | for (i = 0; i < numCoords; ++i) 2508 | coords2[i] = coords3[i]; 2509 | } 2510 | else if (coordType == GL_UNSIGNED_SHORT) 2511 | { 2512 | GLushort *coords3 = (GLushort*)coords; 2513 | int i; 2514 | for (i = 0; i < numCoords; ++i) 2515 | coords2[i] = coords3[i]; 2516 | } 2517 | else if (coordType == GL_FLOAT) 2518 | { 2519 | GLfloat *coords3 = (GLfloat*)coords; 2520 | int i; 2521 | for (i = 0; i < numCoords; ++i) 2522 | coords2[i] = coords3[i]; 2523 | } 2524 | 2525 | path_commands(path, numCommands, commands, numCoords, coords2); 2526 | 2527 | free(coords2); 2528 | } 2529 | 2530 | static void stencil_stroke_path(GLuint path, GLint reference, GLuint mask, const float matrix[16]) 2531 | { 2532 | khiter_t iter = kh_get(path, paths, path); 2533 | if (iter == kh_end(paths)) 2534 | return; 2535 | 2536 | struct path *p = kh_val(paths, iter); 2537 | 2538 | if (p->is_stroke_dirty) 2539 | { 2540 | create_stroke_geometry(p); 2541 | p->is_stroke_dirty = 0; 2542 | } 2543 | 2544 | // save 2545 | GLboolean cmask[4], dmask; 2546 | GLint smask; 2547 | glGetBooleanv(GL_COLOR_WRITEMASK, cmask); 2548 | glGetBooleanv(GL_DEPTH_WRITEMASK, &dmask); 2549 | glGetIntegerv(GL_STENCIL_WRITEMASK, &smask); 2550 | 2551 | GLint sfunc, sref, svmask; 2552 | glGetIntegerv(GL_STENCIL_FUNC, &sfunc); 2553 | glGetIntegerv(GL_STENCIL_REF, &sref); 2554 | glGetIntegerv(GL_STENCIL_VALUE_MASK, &svmask); 2555 | 2556 | GLenum fail, zfail, zpass; 2557 | glGetIntegerv(GL_STENCIL_FAIL, &fail); 2558 | glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail); 2559 | glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass); 2560 | 2561 | GLint currentProgram; 2562 | glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); 2563 | 2564 | GLint data0Enabled, data1Enabled, data2Enabled; 2565 | glGetVertexAttribiv(DATA0_POS, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &data0Enabled); 2566 | glGetVertexAttribiv(DATA1_POS, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &data1Enabled); 2567 | glGetVertexAttribiv(DATA2_POS, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &data2Enabled); 2568 | 2569 | glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 2570 | glDepthMask(GL_FALSE); 2571 | glStencilMask(mask); 2572 | glStencilFunc(GL_ALWAYS, reference, ~0); // TODO: this should be configured with glPathStencilFuncAC 2573 | glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); 2574 | 2575 | if (p->stroke_geoms[0].count > 0) 2576 | { 2577 | glUseProgram(program0); 2578 | glUniformMatrix4fv(matrix0, 1, GL_FALSE, matrix); 2579 | #ifdef OPENGL_ES 2580 | glUniformMatrix4fv(mvp0, 1, GL_FALSE, g_mvp); 2581 | #endif 2582 | 2583 | glEnableVertexAttribArray(DATA0_POS); 2584 | 2585 | glBindBuffer(GL_ARRAY_BUFFER, p->stroke_geoms[0].vertex_buffer); 2586 | glVertexAttribPointer(DATA0_POS, 2, GL_FLOAT, GL_FALSE, 8, BUFFER_OFFSET(0)); 2587 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p->stroke_geoms[0].index_buffer); 2588 | glDrawElements(GL_TRIANGLES, p->stroke_geoms[0].count, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); 2589 | } 2590 | 2591 | if (p->stroke_geoms[1].count > 0) 2592 | { 2593 | glUseProgram(program2); 2594 | glUniformMatrix4fv(matrix2, 1, GL_FALSE, matrix); 2595 | #ifdef OPENGL_ES 2596 | glUniformMatrix4fv(mvp2, 1, GL_FALSE, g_mvp); 2597 | #endif 2598 | 2599 | glEnableVertexAttribArray(DATA0_POS); 2600 | glEnableVertexAttribArray(DATA1_POS); 2601 | glEnableVertexAttribArray(DATA2_POS); 2602 | 2603 | glBindBuffer(GL_ARRAY_BUFFER, p->stroke_geoms[1].vertex_buffer); 2604 | glVertexAttribPointer(DATA0_POS, 4, GL_FLOAT, GL_FALSE, 48, BUFFER_OFFSET(0 * 4)); 2605 | glVertexAttribPointer(DATA1_POS, 4, GL_FLOAT, GL_FALSE, 48, BUFFER_OFFSET(4 * 4)); 2606 | glVertexAttribPointer(DATA2_POS, 4, GL_FLOAT, GL_FALSE, 48, BUFFER_OFFSET(8 * 4)); 2607 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p->stroke_geoms[1].index_buffer); 2608 | glDrawElements(GL_TRIANGLES, p->stroke_geoms[1].count, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); 2609 | } 2610 | 2611 | // restore 2612 | if (!data0Enabled) 2613 | glDisableVertexAttribArray(DATA0_POS); 2614 | if (!data1Enabled) 2615 | glDisableVertexAttribArray(DATA1_POS); 2616 | if (!data2Enabled) 2617 | glDisableVertexAttribArray(DATA2_POS); 2618 | 2619 | glUseProgram(currentProgram); 2620 | 2621 | glColorMask(cmask[0], cmask[1], cmask[2], cmask[3]); 2622 | glDepthMask(dmask); 2623 | glStencilMask(smask); 2624 | glStencilFunc(sfunc, sref, svmask); 2625 | glStencilOp(fail, zfail, zpass); 2626 | 2627 | /* TODO: save/restore */ 2628 | glBindBuffer(GL_ARRAY_BUFFER, 0); 2629 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 2630 | } 2631 | 2632 | void glStencilStrokePathAC(GLuint path, GLint reference, GLuint mask) 2633 | { 2634 | stencil_stroke_path(path, reference, mask, identity_matrix); 2635 | } 2636 | 2637 | static void stencil_fill_path(GLuint path, GLenum fill_mode, GLuint mask, const GLfloat matrix[16]) 2638 | { 2639 | struct path *p = NULL; 2640 | 2641 | khiter_t iter = kh_get(path, paths, path); 2642 | if (iter == kh_end(paths)) 2643 | { 2644 | // TODO: check if we should set error here 2645 | return; 2646 | } 2647 | 2648 | GLenum front, back; 2649 | switch (fill_mode) 2650 | { 2651 | case GL_COUNT_UP_AC: 2652 | front = GL_INCR_WRAP; 2653 | back = GL_DECR_WRAP; 2654 | break; 2655 | case GL_COUNT_DOWN_AC: 2656 | front = GL_DECR_WRAP; 2657 | back = GL_INCR_WRAP; 2658 | break; 2659 | case GL_INVERT: 2660 | front = GL_INVERT; 2661 | back = GL_INVERT; 2662 | break; 2663 | default: 2664 | // TODO: check if we should set error here 2665 | return; 2666 | } 2667 | 2668 | p = kh_val(paths, iter); 2669 | 2670 | if (p->is_fill_dirty) 2671 | { 2672 | create_fill_geometry(p); 2673 | p->is_fill_dirty = 0; 2674 | } 2675 | 2676 | // save 2677 | GLboolean cmask[4], dmask; 2678 | GLint smask; 2679 | glGetBooleanv(GL_COLOR_WRITEMASK, cmask); 2680 | glGetBooleanv(GL_DEPTH_WRITEMASK, &dmask); 2681 | glGetIntegerv(GL_STENCIL_WRITEMASK, &smask); 2682 | 2683 | GLint sfunc, sref, svmask; 2684 | glGetIntegerv(GL_STENCIL_FUNC, &sfunc); 2685 | glGetIntegerv(GL_STENCIL_REF, &sref); 2686 | glGetIntegerv(GL_STENCIL_VALUE_MASK, &svmask); 2687 | 2688 | GLenum fail, zfail, zpass; 2689 | glGetIntegerv(GL_STENCIL_FAIL, &fail); 2690 | glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail); 2691 | glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass); 2692 | 2693 | GLint currentProgram; 2694 | glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); 2695 | 2696 | GLint data0Enabled; 2697 | glGetVertexAttribiv(DATA0_POS, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &data0Enabled); 2698 | 2699 | glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 2700 | glDepthMask(GL_FALSE); 2701 | glStencilMask(mask); 2702 | glStencilFunc(GL_ALWAYS, 0, ~0); // TODO: this should be configured with glPathStencilFuncAC 2703 | 2704 | glEnableVertexAttribArray(DATA0_POS); 2705 | 2706 | glBindBuffer(GL_ARRAY_BUFFER, p->fill_vertex_buffer); 2707 | glVertexAttribPointer(DATA0_POS, 4, GL_FLOAT, GL_FALSE, 16, BUFFER_OFFSET(0)); 2708 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p->fill_index_buffer); 2709 | 2710 | glUseProgram(program1); 2711 | glUniformMatrix4fv(matrix1, 1, GL_FALSE, matrix); 2712 | #ifdef OPENGL_ES 2713 | glUniformMatrix4fv(mvp1, 1, GL_FALSE, g_mvp); 2714 | #endif 2715 | 2716 | if (p->fill_counts[0] > 0) 2717 | { 2718 | glStencilOp(GL_KEEP, GL_KEEP, front); 2719 | glDrawElements(GL_TRIANGLES, p->fill_counts[0], GL_UNSIGNED_SHORT, BUFFER_OFFSET(p->fill_starts[0] * 2)); 2720 | } 2721 | 2722 | if (p->fill_counts[1] > 0) 2723 | { 2724 | glStencilOp(GL_KEEP, GL_KEEP, back); 2725 | glDrawElements(GL_TRIANGLES, p->fill_counts[1], GL_UNSIGNED_SHORT, BUFFER_OFFSET(p->fill_starts[1] * 2)); 2726 | } 2727 | 2728 | // restore 2729 | if (!data0Enabled) 2730 | glDisableVertexAttribArray(DATA0_POS); 2731 | 2732 | glUseProgram(currentProgram); 2733 | 2734 | glColorMask(cmask[0], cmask[1], cmask[2], cmask[3]); 2735 | glDepthMask(dmask); 2736 | glStencilMask(smask); 2737 | glStencilFunc(sfunc, sref, svmask); 2738 | glStencilOp(fail, zfail, zpass); 2739 | 2740 | /* TODO: save/restore */ 2741 | glBindBuffer(GL_ARRAY_BUFFER, 0); 2742 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 2743 | } 2744 | 2745 | void glStencilFillPathAC(GLuint path, GLenum fillMode, GLuint mask) 2746 | { 2747 | stencil_fill_path(path, fillMode, mask, identity_matrix); 2748 | } 2749 | 2750 | void glPathParameterfAC(GLuint path, GLenum pname, GLfloat value) 2751 | { 2752 | struct path *p = NULL; 2753 | 2754 | khiter_t iter = kh_get(path, paths, path); 2755 | if (iter == kh_end(paths)) 2756 | { 2757 | // TODO: check if we should set error here 2758 | return; 2759 | } 2760 | 2761 | p = kh_val(paths, iter); 2762 | 2763 | switch (pname) 2764 | { 2765 | case GL_PATH_STROKE_WIDTH_AC: 2766 | p->stroke_width = value; 2767 | p->is_stroke_dirty = 1; 2768 | break; 2769 | case GL_PATH_MITER_LIMIT_AC: 2770 | p->miter_limit = value; 2771 | p->is_stroke_dirty = 1; 2772 | break; 2773 | default: 2774 | // TODO: check if we should set error here 2775 | break; 2776 | } 2777 | 2778 | 2779 | } 2780 | 2781 | void glPathParameteriAC(GLuint path, GLenum pname, GLint value) 2782 | { 2783 | khiter_t iter; 2784 | struct path *p; 2785 | 2786 | iter = kh_get(path, paths, path); 2787 | if (iter == kh_end(paths)) 2788 | { 2789 | // TODO: check if we should set error here 2790 | return; 2791 | } 2792 | 2793 | p = kh_val(paths, iter); 2794 | 2795 | switch (pname) 2796 | { 2797 | case GL_PATH_JOIN_STYLE_AC: 2798 | if (value != GL_MITER_REVERT_AC && value != GL_MITER_TRUNCATE_AC && value != GL_BEVEL_AC && value != GL_ROUND_AC && value != GL_NONE) 2799 | { 2800 | /* TODO: check if we should set error here */ 2801 | return; 2802 | } 2803 | p->join_style = value; 2804 | p->is_stroke_dirty = 1; 2805 | break; 2806 | case GL_PATH_INITIAL_END_CAP_AC: 2807 | if (value != GL_FLAT && value != GL_SQUARE_AC && value != GL_ROUND_AC && value != GL_TRIANGULAR_AC) 2808 | { 2809 | /* TODO: check if we should set error here */ 2810 | return; 2811 | } 2812 | p->initial_end_cap = value; 2813 | p->is_stroke_dirty = 1; 2814 | break; 2815 | break; 2816 | case GL_PATH_TERMINAL_END_CAP_AC: 2817 | if (value != GL_FLAT && value != GL_SQUARE_AC && value != GL_ROUND_AC && value != GL_TRIANGULAR_AC) 2818 | { 2819 | /* TODO: check if we should set error here */ 2820 | return; 2821 | } 2822 | p->terminal_end_cap = value; 2823 | p->is_stroke_dirty = 1; 2824 | break; 2825 | break; 2826 | default: 2827 | /* TODO: check if we should set error here */ 2828 | break; 2829 | } 2830 | } 2831 | 2832 | 2833 | static int get_path_name(int pathNameType, const void **paths, unsigned int pathBase, unsigned int *pathName) 2834 | { 2835 | typedef signed char byte; 2836 | typedef unsigned char ubyte; 2837 | typedef unsigned short ushort; 2838 | typedef unsigned int uint; 2839 | 2840 | switch (pathNameType) 2841 | { 2842 | case GL_BYTE: 2843 | { 2844 | const byte *p = *paths; 2845 | *pathName = pathBase + p[0]; 2846 | *paths = p + 1; 2847 | return 1; 2848 | } 2849 | case GL_UNSIGNED_BYTE: 2850 | { 2851 | const ubyte *p = *paths; 2852 | *pathName = pathBase + p[0]; 2853 | *paths = p + 1; 2854 | return 1; 2855 | } 2856 | case GL_SHORT: 2857 | { 2858 | const short *p = *paths; 2859 | *pathName = pathBase + p[0]; 2860 | *paths = p + 1; 2861 | return 1; 2862 | } 2863 | case GL_UNSIGNED_SHORT: 2864 | { 2865 | const ushort *p = *paths; 2866 | *pathName = pathBase + p[0]; 2867 | *paths = p + 1; 2868 | return 1; 2869 | } 2870 | case GL_INT: 2871 | { 2872 | const int *p = *paths; 2873 | *pathName = pathBase + p[0]; 2874 | *paths = p + 1; 2875 | return 1; 2876 | } 2877 | case GL_UNSIGNED_INT: 2878 | { 2879 | const uint *p = *paths; 2880 | *pathName = pathBase + p[0]; 2881 | *paths = p + 1; 2882 | return 1; 2883 | } 2884 | case GL_FLOAT: 2885 | { 2886 | const float *p = *paths; 2887 | *pathName = pathBase + p[0]; 2888 | *paths = p + 1; 2889 | return 1; 2890 | } 2891 | case GL_2_BYTES: 2892 | { 2893 | const ubyte *p = *paths; 2894 | *pathName = pathBase + (p[0] << 8 | p[1]); 2895 | *paths = p + 2; 2896 | return 1; 2897 | } 2898 | case GL_3_BYTES: 2899 | { 2900 | const ubyte *p = *paths; 2901 | *pathName = pathBase + (p[0] << 16 | p[1] << 8 | p[0]); 2902 | *paths = p + 3; 2903 | return 1; 2904 | } 2905 | case GL_4_BYTES: 2906 | { 2907 | const ubyte *p = *paths; 2908 | *pathName = pathBase + (p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]); 2909 | *paths = p + 4; 2910 | return 1; 2911 | } 2912 | case GL_UTF8_AC: 2913 | { 2914 | const ubyte *p = *paths; 2915 | ubyte c0 = p[0]; 2916 | if ((c0 & 0x80) == 0x00) 2917 | { 2918 | /* Zero continuation (0 to 127) */ 2919 | *pathName = pathBase + c0; 2920 | p += 1; 2921 | } 2922 | else 2923 | { 2924 | ubyte c1 = p[1]; 2925 | if ((c1 & 0xC0) != 0x80) 2926 | { 2927 | /* Stop processing the UTF byte sequence early. */ 2928 | return 0; 2929 | } 2930 | if ((c0 & 0xE0) == 0xC0) 2931 | { 2932 | /* One contination (128 to 2047) */ 2933 | *pathName = pathBase + ((c1 & 0x3F) | (c0 & 0x1F) << 6); 2934 | if (*pathName < 128) 2935 | { 2936 | return 0; 2937 | } 2938 | p += 2; 2939 | } 2940 | else 2941 | { 2942 | ubyte c2 = p[2]; 2943 | if ((c2 & 0xC0) != 0x80) 2944 | { 2945 | /* Stop processing the UTF byte sequence early. */ 2946 | return 0; 2947 | } 2948 | if ((c0 & 0xF0) == 0xE0) 2949 | { 2950 | /* Two continuation (2048 to 55295 and 57344 to 65535) */ 2951 | *pathName = pathBase + ((c2 & 0x3F) | (c1 & 0x3F) << 6 | (c0 & 0xF) << 12); 2952 | if ((*pathName >= 55296) && (*pathName <= 57343)) 2953 | { 2954 | /* Stop processing the UTF byte sequence early. */ 2955 | return 0; 2956 | } 2957 | if (*pathName < 2048) 2958 | { 2959 | return 0; 2960 | } 2961 | p += 3; 2962 | } 2963 | else 2964 | { 2965 | ubyte c3 = p[3]; 2966 | if ((c3 & 0xC0) != 0x80) 2967 | { 2968 | /* Stop processing the UTF byte sequence early. */ 2969 | return 0; 2970 | } 2971 | if ((c0 & 0xF8) == 0xF0) 2972 | { 2973 | /* Three continuation (65536 to 1114111) */ 2974 | *pathName = pathBase + ((c3 & 0x3F) | (c2 & 0x3F) << 6 | (c1 & 0x3F) << 12 | (c0 & 0x7) << 18); 2975 | if (*pathName < 65536 && *pathName > 1114111) 2976 | { 2977 | return 0; 2978 | } 2979 | p += 4; 2980 | } 2981 | else 2982 | { 2983 | /* Skip invalid or restricted encodings. */ 2984 | /* Stop processing the UTF byte sequence early. */ 2985 | return 0; 2986 | } 2987 | } 2988 | } 2989 | } 2990 | *paths = p; 2991 | return 1; 2992 | } 2993 | case GL_UTF16_AC: 2994 | { 2995 | const ushort *p = *paths; 2996 | 2997 | ushort s0 = p[0]; 2998 | if ((s0 < 0xDB00) || (s0 > 0xDFFF)) 2999 | { 3000 | *pathName = pathBase + s0; 3001 | p += 1; 3002 | } 3003 | else 3004 | { 3005 | if ((s0 >= 0xDB00) && (s0 <= 0xDBFF)) 3006 | { 3007 | ushort s1 = p[1]; 3008 | if ((s1 >= 0xDC00) && (s1 <= 0xDFFF)) 3009 | { 3010 | *pathName = pathBase + (((s0 & 0x3FF) << 10 | (s1 & 0x3FF)) + 0x10000); 3011 | p += 2; 3012 | } 3013 | else 3014 | { 3015 | /* Stop processing the UTF byte sequence early. */ 3016 | return 0; 3017 | } 3018 | } 3019 | else 3020 | { 3021 | return 0; 3022 | } 3023 | } 3024 | *paths = p; 3025 | return 1; 3026 | } 3027 | default: /* TODO: generate INVALID_ENUM */ 3028 | return 0; 3029 | } 3030 | } 3031 | 3032 | static const float *apply_transform_type(int transform_type, const float *v, float m[16]) 3033 | { 3034 | switch (transform_type) 3035 | { 3036 | case GL_NONE: 3037 | m[0] = 1; m[4] = 0; m[8] = 0; m[12] = 0; 3038 | m[1] = 0; m[5] = 1; m[9] = 0; m[13] = 0; 3039 | m[2] = 0; m[6] = 0; m[10] = 1; m[14] = 0; 3040 | m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1; 3041 | break; 3042 | case GL_TRANSLATE_X_AC: 3043 | m[0] = 1; m[4] = 0; m[8] = 0; m[12] = v[0]; 3044 | m[1] = 0; m[5] = 1; m[9] = 0; m[13] = 0; 3045 | m[2] = 0; m[6] = 0; m[10] = 1; m[14] = 0; 3046 | m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1; 3047 | v += 1; 3048 | break; 3049 | case GL_TRANSLATE_Y_AC: 3050 | m[0] = 1; m[4] = 0; m[8] = 0; m[12] = 0; 3051 | m[1] = 0; m[5] = 1; m[9] = 0; m[13] = v[0]; 3052 | m[2] = 0; m[6] = 0; m[10] = 1; m[14] = 0; 3053 | m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1; 3054 | v += 1; 3055 | break; 3056 | case GL_TRANSLATE_2D_AC: 3057 | m[0] = 1; m[4] = 0; m[8] = 0; m[12] = v[0]; 3058 | m[1] = 0; m[5] = 1; m[9] = 0; m[13] = v[1]; 3059 | m[2] = 0; m[6] = 0; m[10] = 1; m[14] = 0; 3060 | m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1; 3061 | v += 2; 3062 | break; 3063 | case GL_TRANSLATE_3D_AC: 3064 | m[0] = 1; m[4] = 0; m[8] = 0; m[12] = v[0]; 3065 | m[1] = 0; m[5] = 1; m[9] = 0; m[13] = v[1]; 3066 | m[2] = 0; m[6] = 0; m[10] = 1; m[14] = v[2]; 3067 | m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1; 3068 | v += 3; 3069 | break; 3070 | case GL_AFFINE_2D_AC: 3071 | m[0] = v[0]; m[4] = v[2]; m[8] = 0; m[12] = v[4]; 3072 | m[1] = v[1]; m[5] = v[3]; m[9] = 0; m[13] = v[5]; 3073 | m[2] = 0; m[6] = 0; m[10] = 1; m[14] = 0; 3074 | m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1; 3075 | v += 6; 3076 | break; 3077 | case GL_TRANSPOSE_AFFINE_2D_AC: 3078 | m[0] = v[0]; m[4] = v[1]; m[8] = 0; m[12] = v[2]; 3079 | m[1] = v[3]; m[5] = v[4]; m[9] = 0; m[13] = v[5]; 3080 | m[2] = 0; m[6] = 0; m[10] = 1; m[14] = 0; 3081 | m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1; 3082 | v += 6; 3083 | break; 3084 | case GL_AFFINE_3D_AC: 3085 | m[0] = v[0]; m[4] = v[3]; m[8] = v[6]; m[12] = v[9]; 3086 | m[1] = v[1]; m[5] = v[4]; m[9] = v[7]; m[13] = v[10]; 3087 | m[2] = v[2]; m[6] = v[5]; m[10] = v[8]; m[14] = v[11]; 3088 | m[3] = 0; m[7] = 0; m[11] = 1; m[15] = 0; 3089 | v += 12; 3090 | break; 3091 | case GL_TRANSPOSE_AFFINE_3D_AC: 3092 | m[0] = v[0]; m[4] = v[1]; m[8] = v[2]; m[12] = v[3]; 3093 | m[1] = v[4]; m[5] = v[5]; m[9] = v[6]; m[13] = v[7]; 3094 | m[2] = v[8]; m[6] = v[9]; m[10] = v[10]; m[14] = v[11]; 3095 | m[3] = 0; m[7] = 0; m[11] = 1; m[15] = 0; 3096 | v += 12; 3097 | break; 3098 | default: /* TODO: generate INVALID_ENUM */ 3099 | break; 3100 | } 3101 | return v; 3102 | } 3103 | 3104 | void glStencilFillPathInstancedAC(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues) 3105 | { 3106 | int i; 3107 | const float *v; 3108 | 3109 | v = transformValues; 3110 | for (i = 0; i < numPaths; ++i) 3111 | { 3112 | float m[16]; 3113 | unsigned int pathName; 3114 | 3115 | v = apply_transform_type(transformType, v, m); 3116 | if (v == NULL) 3117 | return; 3118 | 3119 | if (!get_path_name(pathNameType, &paths, pathBase, &pathName)) 3120 | return; 3121 | 3122 | if (glIsPathAC(pathName)) 3123 | stencil_fill_path(pathName, fillMode, mask, m); 3124 | } 3125 | } 3126 | 3127 | void glStencilStrokePathInstancedAC(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues) 3128 | { 3129 | int i; 3130 | const float *v; 3131 | 3132 | v = transformValues; 3133 | for (i = 0; i < numPaths; ++i) 3134 | { 3135 | float m[16]; 3136 | unsigned int pathName; 3137 | 3138 | v = apply_transform_type(transformType, v, m); 3139 | if (v == NULL) 3140 | return; 3141 | 3142 | if (!get_path_name(pathNameType, &paths, pathBase, &pathName)) 3143 | return; 3144 | 3145 | if (glIsPathAC(pathName)) 3146 | stencil_stroke_path(pathName, reference, mask, m); 3147 | } 3148 | } 3149 | 3150 | void glGetPathBoundingBoxInstancedAC(GLenum boundingBoxType, GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLenum transformType, const GLfloat *transformValues, GLfloat *result) 3151 | { 3152 | int i; 3153 | int hasBounds = 0; 3154 | float boundsUnion[4], bounds[4]; 3155 | 3156 | const float *v = transformValues; 3157 | for (i = 0; i < numPaths; i++) 3158 | { 3159 | unsigned int pathName; 3160 | if (!get_path_name(pathNameType, &paths, pathBase, &pathName)) 3161 | return; 3162 | 3163 | if (glIsPathAC(pathName)) 3164 | { 3165 | glGetPathParameterfvAC(pathName, boundingBoxType, bounds); 3166 | switch (transformType) 3167 | { 3168 | case GL_NONE: 3169 | break; 3170 | case GL_TRANSLATE_X_AC: 3171 | bounds[0] += v[0]; 3172 | bounds[2] += v[0]; 3173 | v += 1; 3174 | break; 3175 | case GL_TRANSLATE_Y_AC: 3176 | bounds[1] += v[0]; 3177 | bounds[3] += v[0]; 3178 | v += 1; 3179 | break; 3180 | case GL_TRANSLATE_2D_AC: 3181 | bounds[0] += v[0]; 3182 | bounds[1] += v[1]; 3183 | bounds[2] += v[0]; 3184 | bounds[3] += v[1]; 3185 | v += 2; 3186 | break; 3187 | case GL_TRANSLATE_3D_AC: /* ignores v[2] */ 3188 | bounds[0] += v[0]; 3189 | bounds[1] += v[1]; 3190 | bounds[2] += v[0]; 3191 | bounds[3] += v[1]; 3192 | v += 3; 3193 | break; 3194 | case GL_AFFINE_2D_AC: 3195 | bounds[0] = bounds[0] * v[0] + bounds[0] * v[2] + v[4]; 3196 | bounds[1] = bounds[1] * v[1] + bounds[1] * v[3] + v[5]; 3197 | bounds[2] = bounds[2] * v[0] + bounds[2] * v[2] + v[4]; 3198 | bounds[3] = bounds[3] * v[1] + bounds[3] * v[3] + v[5]; 3199 | v += 6; 3200 | break; 3201 | case GL_TRANSPOSE_AFFINE_2D_AC: 3202 | bounds[0] = bounds[0] * v[0] + bounds[0] * v[1] + v[2]; 3203 | bounds[1] = bounds[1] * v[3] + bounds[1] * v[4] + v[5]; 3204 | bounds[2] = bounds[2] * v[0] + bounds[2] * v[1] + v[2]; 3205 | bounds[3] = bounds[3] * v[3] + bounds[3] * v[4] + v[5]; 3206 | v += 6; 3207 | break; 3208 | case GL_AFFINE_3D_AC: /* ignores v[2], v[5], v[6..8], v[11] */ 3209 | bounds[0] = bounds[0] * v[0] + bounds[0] * v[3] + v[9]; 3210 | bounds[1] = bounds[1] * v[1] + bounds[1] * v[4] + v[10]; 3211 | bounds[2] = bounds[2] * v[0] + bounds[2] * v[3] + v[9]; 3212 | bounds[3] = bounds[3] * v[1] + bounds[3] * v[4] + v[10]; 3213 | v += 12; 3214 | break; 3215 | case GL_TRANSPOSE_AFFINE_3D_AC: /* ignores v[2], v[6], v[8..11] */ 3216 | bounds[0] = bounds[0] * v[0] + bounds[0] * v[1] + v[3]; 3217 | bounds[1] = bounds[1] * v[4] + bounds[1] * v[5] + v[7]; 3218 | bounds[2] = bounds[2] * v[0] + bounds[2] * v[1] + v[3]; 3219 | bounds[3] = bounds[3] * v[4] + bounds[3] * v[5] + v[7]; 3220 | v += 12; 3221 | break; 3222 | default: /* TODO: generate INVALID_ENUM */ 3223 | break; 3224 | } 3225 | 3226 | if (bounds[0] > bounds[2]) 3227 | { 3228 | float t = bounds[2]; 3229 | bounds[2] = bounds[0]; 3230 | bounds[0] = t; 3231 | } 3232 | 3233 | if (bounds[1] > bounds[3]) 3234 | { 3235 | float t = bounds[3]; 3236 | bounds[3] = bounds[1]; 3237 | bounds[1] = t; 3238 | } 3239 | 3240 | if (hasBounds) 3241 | { 3242 | boundsUnion[0] = MIN(boundsUnion[0], bounds[0]); 3243 | boundsUnion[1] = MIN(boundsUnion[1], bounds[1]); 3244 | boundsUnion[2] = MAX(boundsUnion[2], bounds[2]); 3245 | boundsUnion[3] = MAX(boundsUnion[3], bounds[3]); 3246 | } 3247 | else 3248 | { 3249 | memcpy(boundsUnion, bounds, 4 * sizeof(float)); 3250 | hasBounds = 1; 3251 | } 3252 | } 3253 | } 3254 | 3255 | if (hasBounds) 3256 | memcpy(result, boundsUnion, 4 * sizeof(float)); 3257 | } 3258 | 3259 | 3260 | void glGetPathParameterfvAC(GLuint path, GLenum param, GLfloat *value) 3261 | { 3262 | khiter_t iter; 3263 | struct path *p; 3264 | 3265 | iter = kh_get(path, paths, path); 3266 | if (iter == kh_end(paths)) 3267 | { 3268 | /* TODO: check if we should set error here */ 3269 | return; 3270 | } 3271 | 3272 | p = kh_val(paths, iter); 3273 | 3274 | switch (param) 3275 | { 3276 | case GL_PATH_OBJECT_BOUNDING_BOX_AC: 3277 | break; 3278 | case GL_PATH_FILL_BOUNDING_BOX_AC: 3279 | if (p->is_fill_dirty) 3280 | { 3281 | create_fill_geometry(p); 3282 | p->is_fill_dirty = 0; 3283 | } 3284 | value[0] = p->fill_bounds[0]; 3285 | value[1] = p->fill_bounds[1]; 3286 | value[2] = p->fill_bounds[2]; 3287 | value[3] = p->fill_bounds[3]; 3288 | break; 3289 | case GL_PATH_STROKE_BOUNDING_BOX_AC: 3290 | if (p->is_stroke_dirty) 3291 | { 3292 | create_stroke_geometry(p); 3293 | p->is_stroke_dirty = 0; 3294 | } 3295 | value[0] = p->stroke_bounds[0]; 3296 | value[1] = p->stroke_bounds[1]; 3297 | value[2] = p->stroke_bounds[2]; 3298 | value[3] = p->stroke_bounds[3]; 3299 | break; 3300 | default: 3301 | /* TODO: check if we should set error here */ 3302 | break; 3303 | } 3304 | 3305 | } 3306 | 3307 | void glGetPathParameterivAC(GLuint path, GLenum param, GLint *value) 3308 | { 3309 | 3310 | 3311 | } 3312 | 3313 | 3314 | void glPathDashArrayAC(GLuint path, GLsizei dashCount, const GLfloat *dashArray) 3315 | { 3316 | GLsizei i; 3317 | 3318 | khiter_t iter; 3319 | struct path *p; 3320 | 3321 | iter = kh_get(path, paths, path); 3322 | if (iter == kh_end(paths)) 3323 | { 3324 | /* TODO: generate error INVALID_OPERATION */ 3325 | return; 3326 | } 3327 | 3328 | p = kh_val(paths, iter); 3329 | 3330 | if (dashCount < 0) 3331 | { 3332 | /* TODO: generate error INVALID_VALUE */ 3333 | return; 3334 | } 3335 | 3336 | for (i = 0; i < dashCount; ++i) 3337 | { 3338 | if (dashArray[i] < 0) 3339 | { 3340 | /* TODO: generate error INVALID_VALUE */ 3341 | return; 3342 | } 3343 | } 3344 | 3345 | if (dashCount == 0) 3346 | { 3347 | p->num_dashes = 0; 3348 | free(p->dashes); 3349 | p->dashes = NULL; 3350 | 3351 | p->dash_length = 0; 3352 | 3353 | p->is_stroke_dirty = 1; 3354 | } 3355 | else 3356 | { 3357 | p->num_dashes = dashCount; 3358 | free(p->dashes); 3359 | p->dashes = malloc(sizeof(float) * dashCount); 3360 | memcpy(p->dashes, dashArray, sizeof(float) * dashCount); 3361 | 3362 | p->dash_length = 0; 3363 | for (i = 0; i < dashCount; ++i) 3364 | p->dash_length += dashArray[i]; 3365 | 3366 | p->is_stroke_dirty = 1; 3367 | } 3368 | } 3369 | 3370 | #ifdef OPENGL_ES 3371 | void glLoadPathMatrix(const GLfloat *m) 3372 | { 3373 | memcpy(g_mvp, m, 16 * sizeof(GLfloat)); 3374 | } 3375 | void glGetPathMatrix(GLfloat *m) 3376 | { 3377 | memcpy(m, g_mvp, 16 * sizeof(GLfloat)); 3378 | } 3379 | #endif 3380 | 3381 | #if 0 3382 | 3383 | static float ccw(const float *p1, const float *p2, const float *p3) 3384 | { 3385 | return (p2[0] - p1[0])*(p3[1] - p1[1]) - (p2[1] - p1[1])*(p3[0] - p1[0]); 3386 | } 3387 | 3388 | static int compr(const void *ptr1, const void *ptr2) 3389 | { 3390 | const float *p1 = (const float*)ptr1; 3391 | const float *p2 = (const float*)ptr2; 3392 | 3393 | if (p1[0] < p2[0]) 3394 | return -1; 3395 | if (p1[0] > p2[0]) 3396 | return 1; 3397 | if (p1[1] < p2[1]) 3398 | return -1; 3399 | if (p1[1] > p2[1]) 3400 | return 1; 3401 | 3402 | return 0; 3403 | } 3404 | 3405 | void evaluate(float Ax, float Ay, float Bx, float By, float Cx, float Cy, float t, float *px, float *py) 3406 | { 3407 | *px = Ax * t * t + Bx * t + Cx; 3408 | *py = Ay * t * t + By * t + Cy; 3409 | } 3410 | 3411 | void tangent(float Ax, float Ay, float Bx, float By, float Cx, float Cy, float t, float *px, float *py) 3412 | { 3413 | float tx = 2 * Ax * t + Bx; 3414 | float ty = 2 * Ay * t + By; 3415 | 3416 | float l = sqrt(tx * tx + ty * ty); 3417 | 3418 | tx /= l; 3419 | ty /= l; 3420 | 3421 | *px = tx; 3422 | *py = ty; 3423 | } 3424 | 3425 | void offset(float Ax, float Ay, float Bx, float By, float Cx, float Cy, float t, float d, float *px, float *py) 3426 | { 3427 | float tx, ty; 3428 | tangent(Ax, Ay, Bx, By, Cx, Cy, t, &tx, &ty); 3429 | 3430 | float x, y; 3431 | evaluate(Ax, Ay, Bx, By, Cx, Cy, t, &x, &y); 3432 | 3433 | *px = x - d * ty; 3434 | *py = y + d * tx; 3435 | } 3436 | 3437 | float intersect(float x0, float y0, float tx0, float ty0, 3438 | float x1, float y1, float tx1, float ty1) 3439 | { 3440 | /* Solve[x0 + tx0 t0 == x1 + tx1 t1 && y0 + ty0 t0 == y1 + ty1 t1, {t0, t1}] */ 3441 | return -((-(ty1*x0) + ty1*x1 + tx1*y0 - tx1*y1) / (tx1*ty0 - tx0*ty1)); 3442 | } 3443 | 3444 | int convex_hull_quad(float x0, float y0, float x1, float y1, float x2, float y2, float d, float hull[8 * 2 * 2]) 3445 | { 3446 | int index = 0; 3447 | float vertices[8 * 2]; 3448 | 3449 | float Ax = x0 - 2 * x1 + x2; 3450 | float Ay = y0 - 2 * y1 + y2; 3451 | float Bx = 2 * (x1 - x0); 3452 | float By = 2 * (y1 - y0); 3453 | float Cx = x0; 3454 | float Cy = y0; 3455 | 3456 | if ((x2 - x0) * (y1 - y0) - (y2 - y0) * (x1 - x0) < 0) 3457 | d = -d; 3458 | 3459 | /* outer curve */ 3460 | float px0, py0, tx0, ty0, ox0, oy0; 3461 | float px1, py1, tx1, ty1, ox1, oy1; 3462 | 3463 | evaluate(Ax, Ay, Bx, By, Cx, Cy, 0, &px0, &py0); 3464 | tangent(Ax, Ay, Bx, By, Cx, Cy, 0, &tx0, &ty0); 3465 | offset(Ax, Ay, Bx, By, Cx, Cy, 0, d, &ox0, &oy0); 3466 | 3467 | evaluate(Ax, Ay, Bx, By, Cx, Cy, 1, &px1, &py1); 3468 | tangent(Ax, Ay, Bx, By, Cx, Cy, 1, &tx1, &ty1); 3469 | offset(Ax, Ay, Bx, By, Cx, Cy, 1, d, &ox1, &oy1); 3470 | 3471 | float m = tan((atan2(ty0, tx0) + atan2(ty1, tx1)) / 2); 3472 | float t = (-By + Bx * m) / (2 * (Ay - Ax * m)); /* Solve[(2 Ay t + By) / (2 Ax t + Bx) == m, {t}] */ 3473 | 3474 | float pxm, pym, txm, tym, oxm, oym; 3475 | evaluate(Ax, Ay, Bx, By, Cx, Cy, t, &pxm, &pym); 3476 | tangent(Ax, Ay, Bx, By, Cx, Cy, t, &txm, &tym); 3477 | offset(Ax, Ay, Bx, By, Cx, Cy, t, d, &oxm, &oym); 3478 | 3479 | vertices[index++] = ox0; 3480 | vertices[index++] = oy0; 3481 | 3482 | vertices[index++] = ox1; 3483 | vertices[index++] = oy1; 3484 | 3485 | float t0 = intersect(ox0, oy0, tx0, ty0, oxm, oym, txm, tym); 3486 | vertices[index++] = ox0 + tx0 * t0; 3487 | vertices[index++] = oy0 + ty0 * t0; 3488 | 3489 | float t1 = intersect(ox1, oy1, tx1, ty1, oxm, oym, txm, tym); 3490 | vertices[index++] = ox1 + tx1 * t1; 3491 | vertices[index++] = oy1 + ty1 * t1; 3492 | 3493 | /* inner curve */ 3494 | /* 3495 | px = Ax t^2 + Bx t + Cx 3496 | py = Ay t^2 + By t + Cy 3497 | nx = -D[py, t] 3498 | ny = D[px, t] 3499 | nnx = nx / (nx ^ 2 + ny ^ 2) ^ (1/2) 3500 | nny = ny / (nx ^ 2 + ny ^ 2) ^ (1/2) 3501 | ox = Simplify[px + d * nnx] 3502 | oy = Simplify[py + d * nny] 3503 | 3504 | Solve[D[ox, t] == 0, {t}] 3505 | */ 3506 | #define Power pow 3507 | #define Sqrt sqrt 3508 | 3509 | t0 = (4 * Ax*Bx + 4 * Ay*By - Sqrt(Power(-4 * Ax*Bx - 4 * Ay*By, 2) - 4 * (-4 * Power(Ax, 2) - 4 * Power(Ay, 2))*(-Power(Bx, 2) - Power(By, 2) + Power(2, 0.6666666666666666)*Power(Power(Ay*Bx - Ax*By, 2)*Power(d, 2), 0.3333333333333333)))) / (2.*(-4 * Power(Ax, 2) - 4 * Power(Ay, 2))); 3510 | t1 = (4 * Ax*Bx + 4 * Ay*By + Sqrt(Power(-4 * Ax*Bx - 4 * Ay*By, 2) - 4 * (-4 * Power(Ax, 2) - 4 * Power(Ay, 2))*(-Power(Bx, 2) - Power(By, 2) + Power(2, 0.6666666666666666)*Power(Power(Ay*Bx - Ax*By, 2)*Power(d, 2), 0.3333333333333333)))) / (2.*(-4 * Power(Ax, 2) - 4 * Power(Ay, 2))); 3511 | 3512 | if (0 <= t0 && t0 <= 1) 3513 | { 3514 | float x, y; 3515 | offset(Ax, Ay, Bx, By, Cx, Cy, t0, -d, &x, &y); 3516 | vertices[index++] = x; 3517 | vertices[index++] = y; 3518 | } 3519 | if (0 <= t1 && t1 <= 1) 3520 | { 3521 | float x, y; 3522 | offset(Ax, Ay, Bx, By, Cx, Cy, t1, -d, &x, &y); 3523 | vertices[index++] = x; 3524 | vertices[index++] = y; 3525 | } 3526 | 3527 | #undef Power 3528 | #undef Sqrt 3529 | 3530 | offset(Ax, Ay, Bx, By, Cx, Cy, 0, -d, &ox0, &oy0); 3531 | offset(Ax, Ay, Bx, By, Cx, Cy, 1, -d, &ox1, &oy1); 3532 | vertices[index++] = ox0; 3533 | vertices[index++] = oy0; 3534 | vertices[index++] = ox1; 3535 | vertices[index++] = oy1; 3536 | 3537 | int npoints = index / 2; 3538 | 3539 | int num_indices; 3540 | int indices[16]; 3541 | { 3542 | qsort(vertices, npoints, sizeof(float)* 2, compr); 3543 | int i, t, k = 0; 3544 | 3545 | /* lower hull */ 3546 | for (i = 0; i < npoints; ++i) 3547 | { 3548 | while (k >= 2 && ccw(&vertices[indices[k - 2] * 2], &vertices[indices[k - 1] * 2], &vertices[i * 2]) <= 0) --k; 3549 | indices[k++] = i; 3550 | } 3551 | 3552 | /* upper hull */ 3553 | for (i = npoints - 2, t = k + 1; i >= 0; --i) { 3554 | while (k >= t && ccw(&vertices[indices[k - 2] * 2], &vertices[indices[k - 1] * 2], &vertices[i * 2]) <= 0) --k; 3555 | indices[k++] = i; 3556 | } 3557 | 3558 | num_indices = k - 1; 3559 | } 3560 | 3561 | for (int i = 0; i < num_indices; ++i) 3562 | { 3563 | int index = indices[i]; 3564 | hull[i * 2] = vertices[index * 2]; 3565 | hull[i * 2 + 1] = vertices[index * 2 + 1]; 3566 | } 3567 | 3568 | return num_indices; 3569 | } 3570 | 3571 | /* axis of symmerty */ 3572 | /* 3573 | x = Ax t^2 + Bx t + Cx 3574 | y = Ay t^2 + By t + Cy 3575 | xp = D[x, t] 3576 | xpp = D[xp, t] 3577 | yp = D[y, t] 3578 | ypp = D[yp, t] 3579 | k = ((xp * ypp) - (yp * xpp)) / ((xp^2 + yp^2)^(3/2)) 3580 | Solve[D[k, t] == 0, {t}] 3581 | */ 3582 | 3583 | 3584 | static const char *fs_code = 3585 | "#define M_PI 3.1415926535897932384626433832795 \n" 3586 | " \n" 3587 | "uniform vec2 A, B, C; \n" 3588 | "uniform float strokeWidth; \n" 3589 | "uniform float t0, t1; \n" 3590 | " \n" 3591 | "varying float b, c, d; \n" 3592 | "varying vec2 pos; \n" 3593 | " \n" 3594 | "vec2 evaluateQuadratic(float t) \n" 3595 | "{ \n" 3596 | " return (A * t + B) * t + C; \n" 3597 | "} \n" 3598 | " \n" 3599 | "float f(float t) \n" 3600 | "{ \n" 3601 | " return ((t + b) * t + c) * t + d; \n" 3602 | "} \n" 3603 | " \n" 3604 | "bool check(float t) \n" 3605 | "{ \n" 3606 | " if (-1e-3 <= t && t <= 1 + 1e-3) \n" 3607 | " { \n" 3608 | " vec2 q = evaluateQuadratic(t) - pos; \n" 3609 | " if (dot(q, q) <= strokeWidth) \n" 3610 | " return false; \n" 3611 | " } \n" 3612 | " \n" 3613 | " return true; \n" 3614 | "} \n" 3615 | " \n" 3616 | "float estimate(vec4 v) \n" 3617 | "{ \n" 3618 | " float xm = (v.x + v.y) / 2; \n" 3619 | " float ym = f(xm); \n" 3620 | " float d = (v.y - v.x) / 2; \n" 3621 | " float a = (v.z + v.w - 2 * ym) / (2 * d * d); \n" 3622 | " float b = (v.w - v.z) / (2 * d); \n" 3623 | " return xm - (2 * ym) / (b * (1 + sqrt(1 - (4 * a * ym) / (b * b)))); \n" 3624 | "} \n" 3625 | " \n" 3626 | "vec4 update(vec4 v, float x) \n" 3627 | "{ \n" 3628 | " vec2 m = vec2(x, f(x)); \n" 3629 | " vec2 c; \n" 3630 | " c.x = (sign(v.z * m.y) + 1) / 2; \n" 3631 | " c.y = 1 - c.x; \n" 3632 | " return c.yxyx * v + c.xyxy * m.xxyy; \n" 3633 | "} \n" 3634 | " \n" 3635 | "float cbrt(float x) \n" 3636 | "{ \n" 3637 | " return sign(x) * pow(abs(x), 1.0 / 3.0); \n" 3638 | "} \n" 3639 | "// http://stackoverflow.com/questions/11854907/calculate-the-length-of-a-segment-of-a-quadratic-bezier \n" 3640 | "void dash(float t) \n" 3641 | "{ \n" 3642 | " \n" 3643 | "} \n" 3644 | " \n" 3645 | " \n" 3646 | " \n" 3647 | " \n" 3648 | " \n" 3649 | " \n" 3650 | "void main(void) \n" 3651 | "{ \n" 3652 | #if 1 3653 | " vec4 v = vec4(t0, t1, f(t0), f(t1)); \n" 3654 | " v = update(v, estimate(v)); \n" 3655 | " v = update(v, estimate(v)); \n" 3656 | " v = update(v, estimate(v)); \n" 3657 | " float t0 = estimate(v); \n" 3658 | " \n" 3659 | " float e = (t0 + b) / 2; \n" 3660 | " float f = 2 * e * t0 + c; \n" 3661 | " float disc = e * e - f; \n" 3662 | " if (disc < 0) \n" 3663 | " { \n" 3664 | " if (check(t0)) discard; \n" 3665 | " } \n" 3666 | " else \n" 3667 | " { \n" 3668 | " disc = sqrt(disc); \n" 3669 | " float t1 = -e - disc; \n" 3670 | " float t2 = -e + disc; \n" 3671 | " if (check(t0) && check(t1) && check(t2)) discard; \n" 3672 | " } \n" 3673 | #else 3674 | " float p = (3 * c - b * b) / 3; \n" 3675 | " float q = (2 * b * b * b - 9 * b * c + 27 * d) / 27; \n" 3676 | " float offset = -b / 3; \n" 3677 | " float disc = q * q / 4 + p * p * p / 27; \n" 3678 | " \n" 3679 | " if (disc >= 0.0) \n" 3680 | " { \n" 3681 | " float c1 = -q / 2.0; \n" 3682 | " float c2 = sqrt(disc); \n" 3683 | " float t0 = cbrt(c1 + c2) + cbrt(c1 - c2) + offset; \n" 3684 | " if (check(t0)) discard; \n" 3685 | " } \n" 3686 | " else \n" 3687 | " { \n" 3688 | " float cos_3_theta = 3.0 * q * sqrt(-3.0 / p) / (2.0 * p); \n" 3689 | " float theta = acos(cos_3_theta) / 3.0; \n" 3690 | " float r = 2.0 * sqrt(-p / 3.0); \n" 3691 | " float t0 = r * cos(theta) + offset; \n" 3692 | " float t1 = r * cos(theta + 2.0 * M_PI / 3.0) + offset; \n" 3693 | " float t2 = r * cos(theta + 4.0 * M_PI / 3.0) + offset; \n" 3694 | " if (check(t0) && check(t1) && check(t2)) discard; \n" 3695 | " } \n" 3696 | #endif 3697 | " gl_FragColor = vec4(1, 1, 1, 1); \n" 3698 | "} \n"; 3699 | 3700 | 3701 | static void clip_poly(const float *poly, int npoly, 3702 | float px, float py, float nx, float ny, 3703 | float *poly0, int *npoly0, 3704 | float *poly1, int *npoly1) 3705 | { 3706 | int index0 = 0; 3707 | int index1 = 0; 3708 | 3709 | for (int i = 0; i < npoly; ++i) 3710 | { 3711 | int i1 = (i + 1) % npoly; 3712 | 3713 | double x0 = poly[i * 2]; 3714 | double y0 = poly[i * 2 + 1]; 3715 | double x1 = poly[i1 * 2]; 3716 | double y1 = poly[i1 * 2 + 1]; 3717 | 3718 | bool b0 = ((x0 - px) * ny - (y0 - py) * nx) >= 0; 3719 | bool b1 = ((x1 - px) * ny - (y1 - py) * nx) >= 0; 3720 | 3721 | float xp, yp; 3722 | if (b0 != b1) 3723 | { 3724 | float t = intersect(x0, y0, x1 - x0, y1 - y0, px, py, nx, ny); 3725 | xp = (1 - t) * x0 + t * x1; 3726 | yp = (1 - t) * y0 + t * y1; 3727 | } 3728 | 3729 | if (!b0 && b1) 3730 | { 3731 | // out (xp, yp, x1, y1) 3732 | // out (xp, yp) 3733 | poly0[index0++] = xp; 3734 | poly0[index0++] = yp; 3735 | poly0[index0++] = x1; 3736 | poly0[index0++] = y1; 3737 | poly1[index1++] = xp; 3738 | poly1[index1++] = yp; 3739 | } 3740 | else if (b0 && b1) 3741 | { 3742 | // out (x1, y1) 3743 | // out none 3744 | poly0[index0++] = x1; 3745 | poly0[index0++] = y1; 3746 | } 3747 | else if (b0 && !b1) 3748 | { 3749 | // out (xp, yp) 3750 | // out (xp, yp, x1, y1) 3751 | poly0[index0++] = xp; 3752 | poly0[index0++] = yp; 3753 | poly1[index1++] = xp; 3754 | poly1[index1++] = yp; 3755 | poly1[index1++] = x1; 3756 | poly1[index1++] = y1; 3757 | } 3758 | else if (!b0 && !b1) 3759 | { 3760 | // out none 3761 | // out (x1, y1) 3762 | poly1[index1++] = x1; 3763 | poly1[index1++] = y1; 3764 | } 3765 | } 3766 | 3767 | *npoly0 = index0 / 2; 3768 | *npoly1 = index1 / 2; 3769 | 3770 | } 3771 | 3772 | 3773 | #endif 3774 | -------------------------------------------------------------------------------- /pr.h: -------------------------------------------------------------------------------- 1 | #ifndef PR_H_INCLUDED 2 | #define PR_H_INCLUDED 3 | 4 | #include 5 | 6 | #define OPENGL_ES 7 | 8 | #define GL_CLOSE_PATH_AC 0x00 9 | #define GL_MOVE_TO_AC 0x02 10 | #define GL_RELATIVE_MOVE_TO_AC 0x03 11 | #define GL_LINE_TO_AC 0x04 12 | #define GL_RELATIVE_LINE_TO_AC 0x05 13 | #define GL_HORIZONTAL_LINE_TO_AC 0x06 14 | #define GL_RELATIVE_HORIZONTAL_LINE_TO_AC 0x07 15 | #define GL_VERTICAL_LINE_TO_AC 0x08 16 | #define GL_RELATIVE_VERTICAL_LINE_TO_AC 0x09 17 | #define GL_QUADRATIC_CURVE_TO_AC 0x0A 18 | #define GL_RELATIVE_QUADRATIC_CURVE_TO_AC 0x0B 19 | #define GL_CUBIC_CURVE_TO_AC 0x0C 20 | #define GL_RELATIVE_CUBIC_CURVE_TO_AC 0x0D 21 | #define GL_SMOOTH_QUADRATIC_CURVE_TO_AC 0x0E 22 | #define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_AC 0x0F 23 | #define GL_SMOOTH_CUBIC_CURVE_TO_AC 0x10 24 | #define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_AC 0x11 25 | #define GL_SMALL_CCW_ARC_TO_AC 0x12 26 | #define GL_RELATIVE_SMALL_CCW_ARC_TO_AC 0x13 27 | #define GL_SMALL_CW_ARC_TO_AC 0x14 28 | #define GL_RELATIVE_SMALL_CW_ARC_TO_AC 0x15 29 | #define GL_LARGE_CCW_ARC_TO_AC 0x16 30 | #define GL_RELATIVE_LARGE_CCW_ARC_TO_AC 0x17 31 | #define GL_LARGE_CW_ARC_TO_AC 0x18 32 | #define GL_RELATIVE_LARGE_CW_ARC_TO_AC 0x19 33 | #define GL_RESTART_PATH_AC 0xF0 34 | #define GL_DUP_FIRST_CUBIC_CURVE_TO_AC 0xF2 35 | #define GL_DUP_LAST_CUBIC_CURVE_TO_AC 0xF4 36 | #define GL_RECT_AC 0xF6 37 | #define GL_CIRCULAR_CCW_ARC_TO_AC 0xF8 38 | #define GL_CIRCULAR_CW_ARC_TO_AC 0xFA 39 | #define GL_CIRCULAR_TANGENT_ARC_TO_AC 0xFC 40 | #define GL_ARC_TO_AC 0xFE 41 | #define GL_RELATIVE_ARC_TO_AC 0xFF 42 | #define GL_PATH_STROKE_WIDTH_AC 0x9075 43 | #define GL_PATH_INITIAL_END_CAP_AC 0x9077 44 | #define GL_PATH_TERMINAL_END_CAP_AC 0x9078 45 | #define GL_PATH_JOIN_STYLE_AC 0x9079 46 | #define GL_PATH_MITER_LIMIT_AC 0x907A 47 | #define GL_COUNT_UP_AC 0x9088 48 | #define GL_COUNT_DOWN_AC 0x9089 49 | #define GL_CONVEX_HULL_AC 0x908B 50 | #define GL_BOUNDING_BOX_AC 0x908D 51 | #define GL_SQUARE_AC 0x90A3 52 | #define GL_ROUND_AC 0x90A4 53 | #define GL_TRIANGULAR_AC 0x90A5 54 | #define GL_BEVEL_AC 0x90A6 55 | #define GL_MITER_REVERT_AC 0x90A7 56 | #define GL_MITER_TRUNCATE_AC 0x90A8 57 | #define GL_UTF8_AC 0x909A 58 | #define GL_UTF16_AC 0x909B 59 | #define GL_TRANSLATE_X_AC 0x908E 60 | #define GL_TRANSLATE_Y_AC 0x908F 61 | #define GL_TRANSLATE_2D_AC 0x9090 62 | #define GL_TRANSLATE_3D_AC 0x9091 63 | #define GL_AFFINE_2D_AC 0x9092 64 | #define GL_AFFINE_3D_AC 0x9094 65 | #define GL_TRANSPOSE_AFFINE_2D_AC 0x9096 66 | #define GL_TRANSPOSE_AFFINE_3D_AC 0x9098 67 | #define GL_PATH_OBJECT_BOUNDING_BOX_AC 0x908A 68 | #define GL_PATH_FILL_BOUNDING_BOX_AC 0x90A1 69 | #define GL_PATH_STROKE_BOUNDING_BOX_AC 0x90A2 70 | 71 | #ifndef GL_2_BYTES 72 | #define GL_2_BYTES 0x1407 73 | #endif 74 | 75 | #ifndef GL_3_BYTES 76 | #define GL_3_BYTES 0x1408 77 | #endif 78 | 79 | #ifndef GL_4_BYTES 80 | #define GL_4_BYTES 0x1409 81 | #endif 82 | 83 | #ifdef __cplusplus 84 | extern "C" { 85 | #endif 86 | 87 | void init_path_rendering(); 88 | void cleanup_path_rendering(); 89 | 90 | GLuint glGenPathsAC(GLsizei range); 91 | void glDeletePathsAC(GLuint path, GLsizei range); 92 | GLboolean glIsPathAC(GLuint path); 93 | void glPathCommandsAC(GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); 94 | void glStencilStrokePathAC(GLuint path, GLint reference, GLuint mask); 95 | void glStencilFillPathAC(GLuint path, GLenum fillMode, GLuint mask); 96 | void glPathParameterfAC(GLuint path, GLenum pname, GLfloat value); 97 | void glPathParameteriAC(GLuint path, GLenum pname, GLint value); 98 | 99 | void glStencilFillPathInstancedAC(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); 100 | void glStencilStrokePathInstancedAC(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); 101 | 102 | void glGetPathBoundingBoxInstancedAC(GLenum param, GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLenum transformType, const GLfloat *transformValues, GLfloat *bounds); 103 | 104 | void glGetPathParameterfvAC(GLuint path, GLenum param, GLfloat *value); 105 | void glGetPathParameterivAC(GLuint path, GLenum param, GLint *value); 106 | 107 | void glPathDashArrayAC(GLuint path, GLsizei dashCount, const GLfloat *dashArray); 108 | 109 | #ifdef OPENGL_ES 110 | void glLoadPathMatrix(const GLfloat *m); 111 | void glGetPathMatrix(GLfloat *m); 112 | #endif 113 | 114 | #ifdef __cplusplus 115 | } 116 | #endif 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /svg-path.c: -------------------------------------------------------------------------------- 1 | #include "svg-path.h" 2 | #include "kvec.h" 3 | #include 4 | #include 5 | 6 | struct ParseData 7 | { 8 | const char *str; 9 | jmp_buf buf; 10 | }; 11 | 12 | static void wsp(struct ParseData *d) 13 | { 14 | for (;;) 15 | { 16 | if (isspace(*d->str)) 17 | d->str++; 18 | else 19 | break; 20 | } 21 | } 22 | 23 | static void comma(struct ParseData *d) 24 | { 25 | wsp(d); 26 | 27 | if (*d->str == ',') 28 | d->str++; 29 | else 30 | return; 31 | 32 | wsp(d); 33 | } 34 | 35 | static float number(struct ParseData *d) 36 | { 37 | if (isspace(*d->str)) 38 | longjmp(d->buf, 1); 39 | char *end = NULL; 40 | float result = (float)strtod(d->str, &end); 41 | if (d->str == end) 42 | longjmp(d->buf, 1); 43 | d->str = end; 44 | return result; 45 | } 46 | 47 | static int hasNumber(struct ParseData *d) 48 | { 49 | if (isspace(*d->str)) 50 | return 0; 51 | char *end = NULL; 52 | strtod(d->str, &end); 53 | return d->str != end; 54 | } 55 | 56 | static int hasComma(struct ParseData *d) 57 | { 58 | const char *save = d->str; 59 | wsp(d); 60 | int result = (*d->str == ','); 61 | d->str = save; 62 | return result; 63 | } 64 | 65 | typedef kvec_t(float) kvec_float_t; 66 | 67 | static void numbers(struct ParseData *d, int alignment, int multiple, kvec_float_t *v) 68 | { 69 | int i; 70 | 71 | wsp(d); 72 | 73 | for (;;) 74 | { 75 | for (i = 0; i < alignment; ++i) 76 | { 77 | if (i == 0) 78 | { 79 | kv_push_back(*v, number(d)); 80 | } 81 | else 82 | { 83 | comma(d); 84 | kv_push_back(*v, number(d)); 85 | } 86 | } 87 | 88 | if (!multiple) 89 | break; 90 | 91 | if (hasComma(d)) 92 | { 93 | comma(d); 94 | continue; 95 | } 96 | 97 | wsp(d); 98 | 99 | if (!hasNumber(d)) 100 | break; 101 | } 102 | } 103 | 104 | typedef kvec_t(unsigned char) kvec_uchar_t; 105 | 106 | static void parseHelper(struct ParseData *d, kvec_uchar_t *commands, kvec_float_t *coords, int alignment, int multiple) 107 | { 108 | int i; 109 | size_t j; 110 | char command; 111 | kvec_float_t n; 112 | 113 | command = *d->str; 114 | d->str++; 115 | 116 | kv_init(n); 117 | numbers(d, alignment, multiple, &n); 118 | 119 | if (multiple) 120 | { 121 | for (j = 0; j < kv_size(n); j += alignment) 122 | { 123 | kv_push_back(*commands, command); 124 | for (i = 0; i < alignment; ++i) 125 | kv_push_back(*coords, kv_a(n, j + i)); 126 | } 127 | } 128 | else 129 | { 130 | kv_push_back(*commands, command); 131 | for (i = 0; i < alignment; ++i) 132 | kv_push_back(*coords, kv_a(n, i)); 133 | } 134 | 135 | kv_free(n); 136 | } 137 | 138 | static void parse(struct ParseData *d, kvec_uchar_t *commands, kvec_float_t *coords) 139 | { 140 | for (;;) 141 | { 142 | wsp(d); 143 | 144 | if (*d->str == 0) 145 | break; 146 | 147 | switch (*d->str) 148 | { 149 | case 'M': 150 | case 'm': 151 | parseHelper(d, commands, coords, 2, 0); 152 | break; 153 | case 'L': 154 | parseHelper(d, commands, coords, 2, 1); 155 | break; 156 | case 'Q': 157 | parseHelper(d, commands, coords, 4, 1); 158 | break; 159 | case 'C': 160 | parseHelper(d, commands, coords, 6, 1); 161 | break; 162 | case 'Z': 163 | case 'z': 164 | d->str++; 165 | kv_push_back(*commands, 'Z'); 166 | break; 167 | default: 168 | longjmp(d->buf, 1); 169 | break; 170 | } 171 | } 172 | } 173 | 174 | struct PrSvgPath *prParseSvgPath(size_t length, const char *pathString) 175 | { 176 | struct ParseData d; 177 | 178 | kvec_uchar_t commands; 179 | kvec_float_t coords; 180 | 181 | kv_init(commands); 182 | kv_init(coords); 183 | 184 | d.str = pathString; 185 | 186 | if (!setjmp(d.buf)) 187 | parse(&d, &commands, &coords); 188 | else 189 | return NULL; 190 | 191 | struct PrSvgPath *svgPath = (struct PrSvgPath*)malloc(sizeof(struct PrSvgPath)); 192 | 193 | if (kv_empty(commands)) 194 | { 195 | svgPath->numCommands = 0; 196 | svgPath->commands = NULL; 197 | } 198 | else 199 | { 200 | svgPath->numCommands = kv_size(commands); 201 | svgPath->commands = (unsigned char*)malloc(svgPath->numCommands * sizeof(unsigned char)); 202 | memcpy(svgPath->commands, kv_data(commands), svgPath->numCommands * sizeof(unsigned char)); 203 | } 204 | 205 | if (kv_empty(coords)) 206 | { 207 | svgPath->numCoords = 0; 208 | svgPath->coords = NULL; 209 | } 210 | else 211 | { 212 | svgPath->numCoords = kv_size(coords); 213 | svgPath->coords = (float*)malloc(svgPath->numCoords * sizeof(float)); 214 | memcpy(svgPath->coords, kv_data(coords), svgPath->numCoords * sizeof(float)); 215 | } 216 | 217 | return svgPath; 218 | } 219 | 220 | void prFreeSvgPath(struct PrSvgPath *svgPath) 221 | { 222 | if (svgPath == NULL) 223 | return; 224 | 225 | free(svgPath->coords); 226 | free(svgPath->commands); 227 | free(svgPath); 228 | } 229 | 230 | -------------------------------------------------------------------------------- /svg-path.h: -------------------------------------------------------------------------------- 1 | #ifndef SVGPATHPARSER_H 2 | #define SVGPATHPARSER_H 3 | 4 | #include 5 | 6 | struct PrSvgPath 7 | { 8 | int numCommands; 9 | unsigned char *commands; 10 | int numCoords; 11 | float *coords; 12 | }; 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | struct PrSvgPath *prParseSvgPath(size_t length, const char *pathString); 19 | void prFreeSvgPath(struct PrSvgPath *svgPath); 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | 25 | #endif --------------------------------------------------------------------------------