1 /*
2 * Copyright (c) 2007 Ivan Leben
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library in the file COPYING;
16 * if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #include <vg/openvg.h>
22 #include "shDefs.h"
23 #include "shExtensions.h"
24 #include "shContext.h"
25 #include "shPath.h"
26 #include "shImage.h"
27 #include "shGeometry.h"
28 #include "shPaint.h"
29
shPremultiplyFramebuffer()30 void shPremultiplyFramebuffer()
31 {
32 /* Multiply target color with its own alpha */
33 glBlendFunc(GL_ZERO, GL_DST_ALPHA);
34 }
35
shUnpremultiplyFramebuffer()36 void shUnpremultiplyFramebuffer()
37 {
38 /* TODO: hmmmm..... any idea? */
39 }
40
updateBlendingStateGL(VGContext * c,int alphaIsOne)41 void updateBlendingStateGL(VGContext *c, int alphaIsOne)
42 {
43 /* Most common drawing mode (SRC_OVER with alpha=1)
44 as well as SRC is optimized by turning OpenGL
45 blending off. In other cases its turned on. */
46
47 switch (c->blendMode)
48 {
49 case VG_BLEND_SRC:
50 glBlendFunc(GL_ONE, GL_ZERO);
51 glDisable(GL_BLEND); break;
52
53 case VG_BLEND_SRC_IN:
54 glBlendFunc(GL_DST_ALPHA, GL_ZERO);
55 glEnable(GL_BLEND); break;
56
57 case VG_BLEND_DST_IN:
58 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
59 glEnable(GL_BLEND); break;
60
61 case VG_BLEND_SRC_OUT_SH:
62 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);
63 glEnable(GL_BLEND); break;
64
65 case VG_BLEND_DST_OUT_SH:
66 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
67 glEnable(GL_BLEND); break;
68
69 case VG_BLEND_SRC_ATOP_SH:
70 glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
71 glEnable(GL_BLEND); break;
72
73 case VG_BLEND_DST_ATOP_SH:
74 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA);
75 glEnable(GL_BLEND); break;
76
77 case VG_BLEND_DST_OVER:
78 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
79 glEnable(GL_BLEND); break;
80
81 case VG_BLEND_SRC_OVER: default:
82 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
83 if (alphaIsOne) {
84 glDisable(GL_BLEND);
85 } else {
86 glEnable(GL_BLEND);
87 }
88 break;
89 };
90 }
91
92 /*-----------------------------------------------------------
93 * Draws the triangles representing the stroke of a path.
94 *-----------------------------------------------------------*/
95
shDrawStroke(SHPath * p)96 static void shDrawStroke(SHPath *p)
97 {
98 glEnableClientState(GL_VERTEX_ARRAY);
99 glVertexPointer(2, GL_FLOAT, 0, p->stroke.items);
100 glDrawArrays(GL_TRIANGLES, 0, p->stroke.size);
101 glDisableClientState(GL_VERTEX_ARRAY);
102 }
103
104 /*-----------------------------------------------------------
105 * Draws the subdivided vertices in the OpenGL mode given
106 * (this could be VG_TRIANGLE_FAN or VG_LINE_STRIP).
107 *-----------------------------------------------------------*/
108
shDrawVertices(SHPath * p,GLenum mode)109 static void shDrawVertices(SHPath *p, GLenum mode)
110 {
111 int start = 0;
112 int size = 0;
113
114 /* We separate vertex arrays by contours to properly
115 handle the fill modes */
116 glEnableClientState(GL_VERTEX_ARRAY);
117 glVertexPointer(2, GL_FLOAT, sizeof(SHVertex), p->vertices.items);
118
119 while (start < p->vertices.size) {
120 size = p->vertices.items[start].flags;
121 glDrawArrays(mode, start, size);
122 start += size;
123 }
124
125 glDisableClientState(GL_VERTEX_ARRAY);
126 }
127
128 /*-------------------------------------------------------------
129 * Draw a single quad that covers the bounding box of a path
130 *-------------------------------------------------------------*/
131
shDrawBoundBox(VGContext * c,SHPath * p,VGPaintMode mode)132 static void shDrawBoundBox(VGContext *c, SHPath *p, VGPaintMode mode)
133 {
134 SHfloat K = 1.0f;
135 if (mode == VG_STROKE_PATH)
136 K = SH_CEIL(c->strokeMiterLimit * c->strokeLineWidth) + 1.0f;
137
138 glBegin(GL_QUADS);
139 glVertex2f(p->min.x-K, p->min.y-K);
140 glVertex2f(p->max.x+K, p->min.y-K);
141 glVertex2f(p->max.x+K, p->max.y+K);
142 glVertex2f(p->min.x-K, p->max.y+K);
143 glEnd();
144 }
145
146 /*--------------------------------------------------------------
147 * Constructs & draws colored OpenGL primitives that cover the
148 * given bounding box to represent the currently selected
149 * stroke or fill paint
150 *--------------------------------------------------------------*/
151
shDrawPaintMesh(VGContext * c,SHVector2 * min,SHVector2 * max,VGPaintMode mode,GLenum texUnit)152 static void shDrawPaintMesh(VGContext *c, SHVector2 *min, SHVector2 *max,
153 VGPaintMode mode, GLenum texUnit)
154 {
155 SHPaint *p = 0;
156 SHVector2 pmin, pmax;
157 SHfloat K = 1.0f;
158
159 /* Pick the right paint */
160 if (mode == VG_FILL_PATH) {
161 p = (c->fillPaint ? c->fillPaint : &c->defaultPaint);
162 }else if (mode == VG_STROKE_PATH) {
163 p = (c->strokePaint ? c->strokePaint : &c->defaultPaint);
164 K = SH_CEIL(c->strokeMiterLimit * c->strokeLineWidth) + 1.0f;
165 }
166
167 /* We want to be sure to cover every pixel of this path so better
168 take a pixel more than leave some out (multisampling is tricky). */
169 SET2V(pmin, (*min)); SUB2(pmin, K,K);
170 SET2V(pmax, (*max)); ADD2(pmax, K,K);
171
172 /* Construct appropriate OpenGL primitives so as
173 to fill the stencil mask with select paint */
174
175 switch (p->type) {
176 case VG_PAINT_TYPE_LINEAR_GRADIENT:
177 shDrawLinearGradientMesh(p, min, max, mode, texUnit);
178 break;
179
180 case VG_PAINT_TYPE_RADIAL_GRADIENT:
181 shDrawRadialGradientMesh(p, min, max, mode, texUnit);
182 break;
183
184 case VG_PAINT_TYPE_PATTERN:
185 if (p->pattern != VG_INVALID_HANDLE) {
186 shDrawPatternMesh(p, min, max, mode, texUnit);
187 break;
188 }/* else behave as a color paint */
189
190 case VG_PAINT_TYPE_COLOR:
191 glColor4fv((GLfloat*)&p->color);
192 glBegin(GL_QUADS);
193 glVertex2f(pmin.x, pmin.y);
194 glVertex2f(pmax.x, pmin.y);
195 glVertex2f(pmax.x, pmax.y);
196 glVertex2f(pmin.x, pmax.y);
197 glEnd();
198 break;
199 }
200 }
201
shIsTessCacheValid(VGContext * c,SHPath * p)202 VGboolean shIsTessCacheValid (VGContext *c, SHPath *p)
203 {
204 SHfloat nX, nY;
205 SHVector2 X, Y;
206 SHMatrix3x3 mi;//, mchange;
207 VGboolean valid = VG_TRUE;
208
209 if (p->cacheDataValid == VG_FALSE) {
210 valid = VG_FALSE;
211 }
212 else if (p->cacheTransformInit == VG_FALSE) {
213 valid = VG_FALSE;
214 }
215 else if (shInvertMatrix( &p->cacheTransform, &mi ) == VG_FALSE) {
216 valid = VG_FALSE;
217 }
218 else
219 {
220 /* TODO: Compare change matrix for any scale or shear */
221 // MULMATMAT( c->pathTransform, mi, mchange );
222 SET2( X, mi.m[0][0], mi.m[1][0] );
223 SET2( Y, mi.m[0][1], mi.m[1][1] );
224 nX = NORM2( X ); nY = NORM2( Y );
225 if (nX > 1.01f || nX < 0.99 ||
226 nY > 1.01f || nY < 0.99)
227 valid = VG_FALSE;
228 }
229
230 if (valid == VG_FALSE)
231 {
232 /* Update cache */
233 p->cacheDataValid = VG_TRUE;
234 p->cacheTransformInit = VG_TRUE;
235 p->cacheTransform = c->pathTransform;
236 p->cacheStrokeTessValid = VG_FALSE;
237 }
238
239 return valid;
240 }
241
shIsStrokeCacheValid(VGContext * c,SHPath * p)242 VGboolean shIsStrokeCacheValid (VGContext *c, SHPath *p)
243 {
244 VGboolean valid = VG_TRUE;
245
246 if (p->cacheStrokeInit == VG_FALSE) {
247 valid = VG_FALSE;
248 }
249 else if (p->cacheStrokeTessValid == VG_FALSE) {
250 valid = VG_FALSE;
251 }
252 else if (c->strokeDashPattern.size > 0) {
253 valid = VG_FALSE;
254 }
255 else if (p->cacheStrokeLineWidth != c->strokeLineWidth ||
256 p->cacheStrokeCapStyle != c->strokeCapStyle ||
257 p->cacheStrokeJoinStyle != c->strokeJoinStyle ||
258 p->cacheStrokeMiterLimit != c->strokeMiterLimit) {
259 valid = VG_FALSE;
260 }
261
262 if (valid == VG_FALSE)
263 {
264 /* Update cache */
265 p->cacheStrokeInit = VG_TRUE;
266 p->cacheStrokeTessValid = VG_TRUE;
267 p->cacheStrokeLineWidth = c->strokeLineWidth;
268 p->cacheStrokeCapStyle = c->strokeCapStyle;
269 p->cacheStrokeJoinStyle = c->strokeJoinStyle;
270 p->cacheStrokeMiterLimit = c->strokeMiterLimit;
271 }
272
273 return valid;
274 }
275
276 /*-----------------------------------------------------------
277 * Tessellates / strokes the path and draws it according to
278 * VGContext state.
279 *-----------------------------------------------------------*/
280
vgDrawPath(VGPath path,VGbitfield paintModes)281 VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes)
282 {
283 SHPath *p;
284 SHMatrix3x3 mi;
285 SHfloat mgl[16];
286 SHPaint *fill, *stroke;
287 SHRectangle *rect;
288
289 VG_GETCONTEXT(VG_NO_RETVAL);
290
291 VG_RETURN_ERR_IF(!shIsValidPath(context, path),
292 VG_BAD_HANDLE_ERROR, VG_NO_RETVAL);
293
294 VG_RETURN_ERR_IF(paintModes & (~(VG_STROKE_PATH | VG_FILL_PATH)),
295 VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
296
297 /* Check whether scissoring is enabled and scissor
298 rectangle is valid */
299 if (context->scissoring == VG_TRUE) {
300 rect = &context->scissor.items[0];
301 if (context->scissor.size == 0) VG_RETURN( VG_NO_RETVAL );
302 if (rect->w <= 0.0f || rect->h <= 0.0f) VG_RETURN( VG_NO_RETVAL );
303 glScissor( (GLint)rect->x, (GLint)rect->y, (GLint)rect->w, (GLint)rect->h );
304 glEnable( GL_SCISSOR_TEST );
305 }
306
307 p = (SHPath*)path;
308
309 /* If user-to-surface matrix invertible tessellate in
310 surface space for better path resolution */
311 if (shIsTessCacheValid( context, p ) == VG_FALSE)
312 {
313 if (shInvertMatrix(&context->pathTransform, &mi)) {
314 shFlattenPath(p, 1);
315 shTransformVertices(&mi, p);
316 }else shFlattenPath(p, 0);
317 shFindBoundbox(p);
318 }
319
320 /* TODO: Turn antialiasing on/off */
321 // glDisable(GL_LINE_SMOOTH);
322 // glDisable(GL_POLYGON_SMOOTH);
323 // glEnable(GL_MULTISAMPLE);
324
325 /* Pick paint if available or default*/
326 fill = (context->fillPaint ? context->fillPaint : &context->defaultPaint);
327 stroke = (context->strokePaint ? context->strokePaint : &context->defaultPaint);
328
329 /* Apply transformation */
330 shMatrixToGL(&context->pathTransform, mgl);
331 glMatrixMode(GL_MODELVIEW);
332 glPushMatrix();
333 glMultMatrixf(mgl);
334
335 if (paintModes & VG_FILL_PATH) {
336
337 /* Tesselate into stencil */
338 glEnable(GL_STENCIL_TEST);
339
340 if( context->fillRule == VG_EVEN_ODD )
341 {
342 glStencilFunc(GL_ALWAYS, 0, 0);
343 glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
344 }
345 else
346 {
347 // pseudo non-zero fill rule. Fill everything at least covered once, don't
348 // care for possible decrements.
349 // TODO implement real non-zero fill-rule
350 glStencilFunc(GL_ALWAYS, 1, 1);
351 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
352 }
353 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
354 shDrawVertices(p, GL_TRIANGLE_FAN);
355
356 /* Setup blending */
357 updateBlendingStateGL(context,
358 fill->type == VG_PAINT_TYPE_COLOR &&
359 fill->color.a == 1.0f);
360
361 /* Draw paint where stencil odd */
362 glStencilFunc(GL_EQUAL, 1, 1);
363 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
364 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
365 shDrawPaintMesh(context, &p->min, &p->max, VG_FILL_PATH, GL_TEXTURE0);
366
367 /* Clear stencil for sure */
368 /* TODO: Is there any way to do this safely along
369 with the paint generation pass?? */
370 glDisable(GL_BLEND);
371 // glDisable(GL_MULTISAMPLE);
372 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
373 shDrawBoundBox(context, p, VG_FILL_PATH);
374
375 /* Reset state */
376 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
377 glDisable(GL_STENCIL_TEST);
378 // glDisable(GL_BLEND);
379 }
380
381 /* TODO: Turn antialiasing on/off */
382 // glDisable(GL_LINE_SMOOTH);
383 // glDisable(GL_POLYGON_SMOOTH);
384 // glEnable(GL_MULTISAMPLE);
385
386 if ((paintModes & VG_STROKE_PATH) &&
387 context->strokeLineWidth > 0.0f) {
388
389 #if 0
390 if (1) {/*context->strokeLineWidth > 1.0f) {*/
391 #endif
392 if (shIsStrokeCacheValid( context, p ) == VG_FALSE)
393 {
394 /* Generate stroke triangles in user space */
395 shVector2ArrayClear(&p->stroke);
396 shStrokePath(context, p);
397 }
398
399 /* Stroke into stencil */
400 glEnable(GL_STENCIL_TEST);
401 glStencilFunc(GL_NOTEQUAL, 1, 1);
402 glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
403 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
404 shDrawStroke(p);
405
406 /* Setup blending */
407 updateBlendingStateGL(context,
408 stroke->type == VG_PAINT_TYPE_COLOR &&
409 stroke->color.a == 1.0f);
410
411 /* Draw paint where stencil odd */
412 glStencilFunc(GL_EQUAL, 1, 1);
413 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
414 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
415 shDrawPaintMesh(context, &p->min, &p->max, VG_STROKE_PATH, GL_TEXTURE0);
416
417 /* Clear stencil for sure */
418 glDisable(GL_BLEND);
419 // glDisable(GL_MULTISAMPLE);
420 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
421 shDrawBoundBox(context, p, VG_STROKE_PATH);
422
423 /* Reset state */
424 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
425 glDisable(GL_STENCIL_TEST);
426 // glDisable(GL_BLEND);
427 #if 0
428 }else{
429
430 /* Simulate thin stroke by alpha */
431 SHColor c = stroke->color;
432 if (context->strokeLineWidth < 1.0f)
433 c.a *= context->strokeLineWidth;
434
435 /* Draw contour as a line */
436 glDisable(GL_MULTISAMPLE);
437 glEnable(GL_BLEND);
438 glEnable(GL_LINE_SMOOTH);
439 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
440 glColor4fv((GLfloat*)&c);
441 shDrawVertices(p, GL_LINE_STRIP);
442
443 glDisable(GL_BLEND);
444 glDisable(GL_LINE_SMOOTH);
445 }
446 #endif
447 }
448
449
450 glPopMatrix();
451
452 if (context->scissoring == VG_TRUE)
453 glDisable( GL_SCISSOR_TEST );
454
455 VG_RETURN(VG_NO_RETVAL);
456 }
457
vgDrawImage(VGImage image)458 VG_API_CALL void vgDrawImage(VGImage image)
459 {
460 SHImage *i;
461 SHfloat mgl[16];
462 SHfloat texGenS[4] = {0,0,0,0};
463 SHfloat texGenT[4] = {0,0,0,0};
464 SHPaint *fill;
465 SHVector2 min, max;
466 SHRectangle *rect;
467
468 VG_GETCONTEXT(VG_NO_RETVAL);
469
470 VG_RETURN_ERR_IF(!shIsValidImage(context, image),
471 VG_BAD_HANDLE_ERROR, VG_NO_RETVAL);
472
473 /* TODO: check if image is current render target */
474
475 /* Check whether scissoring is enabled and scissor
476 rectangle is valid */
477 if (context->scissoring == VG_TRUE) {
478 rect = &context->scissor.items[0];
479 if (context->scissor.size == 0) VG_RETURN( VG_NO_RETVAL );
480 if (rect->w <= 0.0f || rect->h <= 0.0f) VG_RETURN( VG_NO_RETVAL );
481 glScissor( (GLint)rect->x, (GLint)rect->y, (GLint)rect->w, (GLint)rect->h );
482 glEnable( GL_SCISSOR_TEST );
483 }
484
485 /* Apply image-user-to-surface transformation */
486 i = (SHImage*)image;
487 shMatrixToGL(&context->imageTransform, mgl);
488 glMatrixMode(GL_MODELVIEW);
489 glPushMatrix();
490 glMultMatrixf(mgl);
491
492 /* Clamp to edge for proper filtering, modulate for multiply mode */
493 glActiveTexture(GL_TEXTURE0);
494 glBindTexture(GL_TEXTURE_2D, i->texture);
495 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
496 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
497 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
498
499 /* Adjust antialiasing to settings */
500 if (context->imageQuality == VG_IMAGE_QUALITY_NONANTIALIASED) {
501 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
502 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
503 glDisable(GL_MULTISAMPLE);
504 }else{
505 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
506 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
507 glEnable(GL_MULTISAMPLE);
508 }
509
510 /* Generate image texture coords automatically */
511 texGenS[0] = 1.0f / i->texwidth;
512 texGenT[1] = 1.0f / i->texheight;
513 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
514 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
515 glTexGenfv(GL_S, GL_OBJECT_PLANE, texGenS);
516 glTexGenfv(GL_T, GL_OBJECT_PLANE, texGenT);
517 glEnable(GL_TEXTURE_GEN_S);
518 glEnable(GL_TEXTURE_GEN_T);
519
520 /* Pick fill paint */
521 fill = (context->fillPaint ? context->fillPaint : &context->defaultPaint);
522
523 /* Use paint color when multiplying with a color-paint */
524 if (context->imageMode == VG_DRAW_IMAGE_MULTIPLY &&
525 fill->type == VG_PAINT_TYPE_COLOR)
526 glColor4fv((GLfloat*)&fill->color);
527 else glColor4f(1,1,1,1);
528
529
530 /* Check image drawing mode */
531 if (context->imageMode == VG_DRAW_IMAGE_MULTIPLY &&
532 fill->type != VG_PAINT_TYPE_COLOR) {
533
534 /* Draw image quad into stencil */
535 glDisable(GL_BLEND);
536 glDisable(GL_TEXTURE_2D);
537 glEnable(GL_STENCIL_TEST);
538 glStencilFunc(GL_ALWAYS, 1, 1);
539 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
540 glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
541
542 glBegin(GL_QUADS);
543 glVertex2i(0, 0);
544 glVertex2i(i->width, 0);
545 glVertex2i(i->width, i->height);
546 glVertex2i(0, i->height);
547 glEnd();
548
549 /* Setup blending */
550 updateBlendingStateGL(context, 0);
551
552 /* Draw gradient mesh where stencil 1*/
553 glEnable(GL_TEXTURE_2D);
554 glStencilFunc(GL_EQUAL, 1, 1);
555 glStencilOp(GL_ZERO,GL_ZERO,GL_ZERO);
556 glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
557
558 SET2(min,0,0);
559 SET2(max, (SHfloat)i->width, (SHfloat)i->height);
560 if (fill->type == VG_PAINT_TYPE_RADIAL_GRADIENT) {
561 shDrawRadialGradientMesh(fill, &min, &max, VG_FILL_PATH, GL_TEXTURE1);
562 }else if (fill->type == VG_PAINT_TYPE_LINEAR_GRADIENT) {
563 shDrawLinearGradientMesh(fill, &min, &max, VG_FILL_PATH, GL_TEXTURE1);
564 }else if (fill->type == VG_PAINT_TYPE_PATTERN) {
565 shDrawPatternMesh(fill, &min, &max, VG_FILL_PATH, GL_TEXTURE1); }
566
567 glActiveTexture(GL_TEXTURE0);
568 glDisable(GL_TEXTURE_2D);
569 glDisable(GL_STENCIL_TEST);
570
571 }else if (context->imageMode == VG_DRAW_IMAGE_STENCIL) {
572
573
574 }else{/* Either normal mode or multiplying with a color-paint */
575
576 /* Setup blending */
577 updateBlendingStateGL(context, 0);
578
579 /* Draw textured quad */
580 glEnable(GL_TEXTURE_2D);
581
582 glBegin(GL_QUADS);
583 glVertex2i(0, 0);
584 glVertex2i(i->width, 0);
585 glVertex2i(i->width, i->height);
586 glVertex2i(0, i->height);
587 glEnd();
588
589 glDisable(GL_TEXTURE_2D);
590 }
591
592
593 glDisable(GL_TEXTURE_GEN_S);
594 glDisable(GL_TEXTURE_GEN_T);
595 glPopMatrix();
596
597 if (context->scissoring == VG_TRUE)
598 glDisable( GL_SCISSOR_TEST );
599
600 VG_RETURN(VG_NO_RETVAL);
601 }
602