summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Gall <tom.gall@linaro.org>2014-10-13 15:53:21 -0500
committerTom Gall <tom.gall@linaro.org>2014-10-13 15:53:21 -0500
commit633fcf77b2d7015384a2e19c80cd4d21826acbc6 (patch)
treef78fafec101eff33ff7b1e77ac8cf54ae7e598ce
parentde7390905710d5294a48c7ffeedec4e4b64d4e42 (diff)
Add new a new very very stripped down Api.cpp which is moved overcairo
to using cairo as it's backend 2D api. To Image, start the change over to using cairo as the 2D api for doing drawing operations. Add Image.cpp.orig and Api.cpp.orig as useful references to keep around as things move over to the Cairo engine.
-rw-r--r--src/vg/Api.cpp4334
-rw-r--r--src/vg/Api.cpp.orig3679
-rw-r--r--src/vg/Image.cpp66
-rw-r--r--src/vg/Image.cpp.orig2680
4 files changed, 7026 insertions, 3733 deletions
diff --git a/src/vg/Api.cpp b/src/vg/Api.cpp
index 10dcc0d..d94747e 100644
--- a/src/vg/Api.cpp
+++ b/src/vg/Api.cpp
@@ -1,3679 +1,655 @@
-/*------------------------------------------------------------------------
- *
- * OpenVG 1.1 Reference Implementation
- * -----------------------------------
- *
- * Copyright (c) 2007 The Khronos Group Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and /or associated documentation files
- * (the "Materials "), to deal in the Materials without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Materials,
- * and to permit persons to whom the Materials are furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Materials.
- *
- * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
- * THE USE OR OTHER DEALINGS IN THE MATERIALS.
- *
- *//**
- * \file
- * \brief Implementations of OpenVG API functions.
- * \note The actual processing is done in Path, Image, Rasterizer and PixelPipe classes.
- *//*-------------------------------------------------------------------*/
-
-#include "VG/openvg.h"
-#include "EGL/egl.h"
-#include "Context.h"
-#include "Rasterizer.h"
-#include "PixelPipe.h"
-#include "Path.h"
-#include <stdio.h>
-
-//==============================================================================================
-
-namespace tgOpenVG
-{
-
-/* EGL&OS functions for use in an OpenVG implementation */
-void* eglvgGetCurrentVGContext(void);
-bool eglvgIsInUse(void* image);
-void OSAcquireMutex(void);
-void OSReleaseMutex(void);
-
-
-#define RI_NO_RETVAL
-
-//this must be the first line in an API function
-#define RI_GET_CONTEXT(RETVAL) \
- OSAcquireMutex(); \
- VGContext* context = (VGContext*)eglvgGetCurrentVGContext(); \
- if(!context) \
- { \
- OSReleaseMutex(); \
- return RETVAL;\
- }
-
-#define RI_IF_ERROR(COND, ERRORCODE, RETVAL) \
- if(COND) { context->setError(ERRORCODE); OSReleaseMutex(); return RETVAL; }
-
-//all API functions must call this as their last operation (also functions that don't return values)
-//NOTE: don't evaluate anything or read state in RETVAL (it'll be executed after the mutex has been released)
-#define RI_RETURN(RETVAL) \
- { OSReleaseMutex(); \
- return RETVAL; }
-
-static bool isAligned(const void* ptr, int alignment)
-{
- RI_ASSERT(alignment == 1 || alignment == 2 || alignment == 4);
- if(((RIuintptr)ptr) & (alignment-1))
- return false;
- return true;
-}
-
-static bool isAligned(const void* ptr, VGImageFormat format)
-{
- RI_ASSERT(isValidImageFormat(format));
- int alignment = Color::formatToDescriptor(format).bitsPerPixel >> 3;
- if(alignment <= 1)
- return true; //one bit or byte per pixel
- return isAligned(ptr, alignment);
-}
-
-bool isValidImageFormat(int f)
-{
- if(f < VG_sRGBX_8888 || f > VG_lABGR_8888_PRE)
- return false;
- return true;
-}
-
-} //namespace OpenVGRI
-
-using namespace tgOpenVG;
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgFlush(void)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- //the RI doesn't cache anything, so this is a no-op
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgFinish(void)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- //the RI doesn't cache anything, so this is a no-op
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGErrorCode RI_APIENTRY vgGetError(void)
-{
- RI_GET_CONTEXT(VG_NO_CONTEXT_ERROR);
- VGErrorCode error = context->m_error;
- context->m_error = VG_NO_ERROR;
- RI_RETURN(error);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-namespace tgOpenVG
-{
-
-RIfloat inputFloat(VGfloat f)
-{
- //this function is used for all floating point input values
- if(RI_ISNAN(f)) return 0.0f; //convert NaN to zero
- return RI_CLAMP(f, -RI_FLOAT_MAX, RI_FLOAT_MAX); //clamp +-inf to +-RIfloat max
-}
-
-Vector2 inputVector2(const Vector2& v)
-{
- return Vector2(inputFloat(v.x), inputFloat(v.y));
-}
-
-Color inputColor(const Color& c)
-{
- Color r = c;
- r.r = inputFloat(r.r);
- r.g = inputFloat(r.g);
- r.b = inputFloat(r.b);
- r.a = inputFloat(r.a);
- return r;
-}
-
-static int inputFloatToInt(VGfloat value)
-{
- double v = (double)floor(value);
- v = v > (double)RI_INT32_MAX ? (double)RI_INT32_MAX : v;
- v = v < (double)RI_INT32_MIN ? (double)RI_INT32_MIN : v;
- return (int)v;
-}
-
-static int paramToInt(const void* values, bool floats, int count, int i)
-{
- RI_ASSERT(i >= 0);
- if(i >= count || !values)
- return 0;
- if(floats)
- return inputFloatToInt(((const VGfloat*)values)[i]);
- return (int)((const VGint*)values)[i];
-}
-
-static RIfloat paramToFloat(const void* values, bool floats, int count, int i)
-{
- RI_ASSERT(i >= 0);
- if(i >= count || !values)
- return 0.0f;
- if(floats)
- return ((const VGfloat*)values)[i];
- return (RIfloat)((const VGint*)values)[i];
-}
-
-static void floatToParam(void* output, bool outputFloats, int count, int i, VGfloat value)
-{
- RI_ASSERT(i >= 0);
- RI_ASSERT(output);
- if(i >= count)
- return;
- if(outputFloats)
- ((VGfloat*)output)[i] = value;
- else
- ((VGint*)output)[i] = (VGint)inputFloatToInt(value);
-}
-
-static void intToParam(void* output, bool outputFloats, int count, int i, VGint value)
-{
- RI_ASSERT(i >= 0);
- RI_ASSERT(output);
- if(i >= count)
- return;
- if(outputFloats)
- ((VGfloat*)output)[i] = (VGfloat)value;
- else
- ((VGint*)output)[i] = value;
-}
-
-} //namespace OpenVGRI
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static void setifv(VGContext* context, VGParamType type, VGint count, const void* values, bool floats)
-{
- RI_ASSERT(context);
- RI_ASSERT(!count || (count && values));
-
- int ivalue = paramToInt(values, floats, count, 0);
- RIfloat fvalue = paramToFloat(values, floats, count, 0);
-
- switch(type)
- {
- case VG_MATRIX_MODE:
- if(count != 1 || ivalue < VG_MATRIX_PATH_USER_TO_SURFACE || ivalue > VG_MATRIX_GLYPH_USER_TO_SURFACE) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_matrixMode = (VGMatrixMode)ivalue;
- break;
-
- case VG_FILL_RULE:
- if(count != 1 || ivalue < VG_EVEN_ODD || ivalue > VG_NON_ZERO) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_fillRule = (VGFillRule)ivalue;
- break;
-
- case VG_IMAGE_QUALITY:
- if(count != 1 || ivalue < VG_IMAGE_QUALITY_NONANTIALIASED || ivalue > VG_IMAGE_QUALITY_BETTER) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_imageQuality = (VGImageQuality)ivalue;
- break;
-
- case VG_RENDERING_QUALITY:
- if(count != 1 || ivalue < VG_RENDERING_QUALITY_NONANTIALIASED || ivalue > VG_RENDERING_QUALITY_BETTER) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_renderingQuality = (VGRenderingQuality)ivalue;
- break;
-
- case VG_BLEND_MODE:
- if(count != 1 || ivalue < VG_BLEND_SRC || ivalue > VG_BLEND_ADDITIVE) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_blendMode = (VGBlendMode)ivalue;
- break;
-
- case VG_IMAGE_MODE:
- if(count != 1 || ivalue < VG_DRAW_IMAGE_NORMAL || ivalue > VG_DRAW_IMAGE_STENCIL) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_imageMode = (VGImageMode)ivalue;
- break;
-
- case VG_SCISSOR_RECTS:
- {
- if(count & 3) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; } //count must be a multiple of four
- try
- {
- Array<Rectangle> scissor;
- for(int i=0;i<RI_INT_MIN(count, RI_MAX_SCISSOR_RECTANGLES*4);i+=4)
- {
- Rectangle s;
- s.x = paramToInt(values, floats, count, i+0);
- s.y = paramToInt(values, floats, count, i+1);
- s.width = paramToInt(values, floats, count, i+2);
- s.height = paramToInt(values, floats, count, i+3);
- scissor.push_back(s); //throws bad_alloc
- }
- context->m_scissor.swap(scissor); //replace context data
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- break;
- }
-
- case VG_COLOR_TRANSFORM:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_colorTransform = ivalue ? VG_TRUE : VG_FALSE;
- break;
-
- case VG_COLOR_TRANSFORM_VALUES:
- if(count != 8 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- {
- for(int i=0;i<8;i++)
- {
- context->m_inputColorTransformValues[i] = paramToFloat(values, floats, count, i);
- context->m_colorTransformValues[i] = inputFloat(context->m_inputColorTransformValues[i]);
- }
- }
- break;
-
- case VG_STROKE_LINE_WIDTH:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_inputStrokeLineWidth = fvalue;
- context->m_strokeLineWidth = inputFloat(fvalue);
- break;
-
- case VG_STROKE_CAP_STYLE:
- if(count != 1 || ivalue < VG_CAP_BUTT || ivalue > VG_CAP_SQUARE) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_strokeCapStyle = (VGCapStyle)ivalue;
- break;
-
- case VG_STROKE_JOIN_STYLE:
- if(count != 1 || ivalue < VG_JOIN_MITER || ivalue > VG_JOIN_BEVEL) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_strokeJoinStyle = (VGJoinStyle)ivalue;
- break;
-
- case VG_STROKE_MITER_LIMIT:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_inputStrokeMiterLimit = fvalue;
- context->m_strokeMiterLimit = inputFloat(fvalue);
- break;
-
- case VG_STROKE_DASH_PATTERN:
- {
- try
- {
- Array<RIfloat> inputStrokeDashPattern;
- Array<RIfloat> strokeDashPattern;
- for(int i=0;i<RI_INT_MIN(count, RI_MAX_DASH_COUNT);i++)
- {
- RIfloat v = paramToFloat(values, floats, count, i);
- inputStrokeDashPattern.push_back(v); //throws bad_alloc
- strokeDashPattern.push_back(inputFloat(v)); //throws bad_alloc
- }
- context->m_inputStrokeDashPattern.swap(inputStrokeDashPattern); //replace context data
- context->m_strokeDashPattern.swap(strokeDashPattern); //replace context data
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- break;
- }
-
- case VG_STROKE_DASH_PHASE:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_inputStrokeDashPhase = fvalue;
- context->m_strokeDashPhase = inputFloat(fvalue);
- break;
-
- case VG_STROKE_DASH_PHASE_RESET:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_strokeDashPhaseReset = ivalue ? VG_TRUE : VG_FALSE;
- break;
-
- case VG_TILE_FILL_COLOR:
- if(count != 4 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_inputTileFillColor.set(paramToFloat(values, floats, count, 0),
- paramToFloat(values, floats, count, 1),
- paramToFloat(values, floats, count, 2),
- paramToFloat(values, floats, count, 3),
- Color::sRGBA);
- context->m_tileFillColor = inputColor(context->m_inputTileFillColor);
- break;
-
- case VG_GLYPH_ORIGIN:
- if(count != 2 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_inputGlyphOrigin.x = paramToFloat(values, floats, count, 0);
- context->m_inputGlyphOrigin.y = paramToFloat(values, floats, count, 1);
- context->m_glyphOrigin = inputVector2(context->m_inputGlyphOrigin);
- break;
-
- case VG_CLEAR_COLOR:
- if(count != 4 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_inputClearColor.set(paramToFloat(values, floats, count, 0),
- paramToFloat(values, floats, count, 1),
- paramToFloat(values, floats, count, 2),
- paramToFloat(values, floats, count, 3),
- Color::sRGBA);
- context->m_clearColor = inputColor(context->m_inputClearColor);
- break;
-
- case VG_MASKING:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_masking = ivalue ? VG_TRUE : VG_FALSE;
- break;
-
- case VG_SCISSORING:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_scissoring = ivalue ? VG_TRUE : VG_FALSE;
- break;
-
- case VG_PIXEL_LAYOUT:
- if(count != 1 || ivalue < VG_PIXEL_LAYOUT_UNKNOWN || ivalue > VG_PIXEL_LAYOUT_BGR_HORIZONTAL) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_pixelLayout = (VGPixelLayout)ivalue;
- break;
-
- case VG_SCREEN_LAYOUT:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- break; //setting read-only values has no effect
-
- case VG_FILTER_FORMAT_LINEAR:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_filterFormatLinear = ivalue ? VG_TRUE : VG_FALSE;
- break;
-
- case VG_FILTER_FORMAT_PREMULTIPLIED:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- context->m_filterFormatPremultiplied = ivalue ? VG_TRUE : VG_FALSE;
- break;
-
- case VG_FILTER_CHANNEL_MASK:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- //undefined bits are ignored
- context->m_filterChannelMask = (VGbitfield)ivalue;
- break;
-
- case VG_MAX_SCISSOR_RECTS:
- case VG_MAX_DASH_COUNT:
- case VG_MAX_KERNEL_SIZE:
- case VG_MAX_SEPARABLE_KERNEL_SIZE:
- case VG_MAX_COLOR_RAMP_STOPS:
- case VG_MAX_IMAGE_WIDTH:
- case VG_MAX_IMAGE_HEIGHT:
- case VG_MAX_IMAGE_PIXELS:
- case VG_MAX_IMAGE_BYTES:
- case VG_MAX_FLOAT:
- case VG_MAX_GAUSSIAN_STD_DEVIATION:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- break; //setting read-only values has no effect
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- break;
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetf(VGParamType type, VGfloat value)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(type == VG_SCISSOR_RECTS || type == VG_STROKE_DASH_PATTERN || type == VG_TILE_FILL_COLOR ||
- type == VG_CLEAR_COLOR, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //vector type value
- VGfloat values[1] = {value};
- setifv(context, type, 1, values, true);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSeti(VGParamType type, VGint value)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(type == VG_SCISSOR_RECTS || type == VG_STROKE_DASH_PATTERN || type == VG_TILE_FILL_COLOR ||
- type == VG_CLEAR_COLOR, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //vector type value
- VGint values[1] = {value};
- setifv(context, type, 1, values, false);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetiv(VGParamType type, VGint count, const VGint * values)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(count < 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR((!values && count > 0) || (values && !isAligned(values,4)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- setifv(context, type, count, values, false);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetfv(VGParamType type, VGint count, const VGfloat * values)
-{
- OSAcquireMutex();
- VGContext* context = (VGContext*)eglvgGetCurrentVGContext();
- if(!context)
- {
- OSReleaseMutex();
- return RI_NO_RETVAL;
- }
-// RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(count < 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR((!values && count > 0) || (values && !isAligned(values,4)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- setifv(context, type, count, values, true);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static void getifv(VGContext* context, VGParamType type, VGint count, void* values, bool floats)
-{
- switch(type)
- {
- case VG_MATRIX_MODE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_matrixMode);
- break;
-
- case VG_FILL_RULE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_fillRule);
- break;
-
- case VG_IMAGE_QUALITY:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_imageQuality);
- break;
-
- case VG_RENDERING_QUALITY:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_renderingQuality);
- break;
-
- case VG_BLEND_MODE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_blendMode);
- break;
-
- case VG_IMAGE_MODE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_imageMode);
- break;
-
- case VG_SCISSOR_RECTS:
- {
- if(count > context->m_scissor.size()*4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- for(int i=0;i<context->m_scissor.size();i++)
- {
- intToParam(values, floats, count, i*4+0, context->m_scissor[i].x);
- intToParam(values, floats, count, i*4+1, context->m_scissor[i].y);
- intToParam(values, floats, count, i*4+2, context->m_scissor[i].width);
- intToParam(values, floats, count, i*4+3, context->m_scissor[i].height);
- }
- break;
- }
-
- case VG_COLOR_TRANSFORM:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_colorTransform);
- break;
-
- case VG_COLOR_TRANSFORM_VALUES:
- if(count > 8) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- {
- for(int i=0;i<count;i++)
- {
- floatToParam(values, floats, count, i, context->m_inputColorTransformValues[i]);
- }
- }
- break;
-
- case VG_STROKE_LINE_WIDTH:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, context->m_inputStrokeLineWidth);
- break;
-
- case VG_STROKE_CAP_STYLE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_strokeCapStyle);
- break;
-
- case VG_STROKE_JOIN_STYLE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_strokeJoinStyle);
- break;
-
- case VG_STROKE_MITER_LIMIT:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, context->m_inputStrokeMiterLimit);
- break;
-
- case VG_STROKE_DASH_PATTERN:
- {
- if(count > context->m_inputStrokeDashPattern.size()) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- for(int i=0;i<context->m_inputStrokeDashPattern.size();i++)
- floatToParam(values, floats, count, i, context->m_inputStrokeDashPattern[i]);
- break;
- }
-
- case VG_STROKE_DASH_PHASE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, context->m_inputStrokeDashPhase);
- break;
-
- case VG_STROKE_DASH_PHASE_RESET:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_strokeDashPhaseReset);
- break;
-
- case VG_TILE_FILL_COLOR:
- if(count > 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, context->m_inputTileFillColor.r);
- floatToParam(values, floats, count, 1, context->m_inputTileFillColor.g);
- floatToParam(values, floats, count, 2, context->m_inputTileFillColor.b);
- floatToParam(values, floats, count, 3, context->m_inputTileFillColor.a);
- break;
-
- case VG_CLEAR_COLOR:
- if(count > 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, context->m_inputClearColor.r);
- floatToParam(values, floats, count, 1, context->m_inputClearColor.g);
- floatToParam(values, floats, count, 2, context->m_inputClearColor.b);
- floatToParam(values, floats, count, 3, context->m_inputClearColor.a);
- break;
-
- case VG_GLYPH_ORIGIN:
- if(count > 2) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, context->m_inputGlyphOrigin.x);
- floatToParam(values, floats, count, 1, context->m_inputGlyphOrigin.y);
- break;
-
- case VG_MASKING:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_masking);
- break;
-
- case VG_SCISSORING:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_scissoring);
- break;
-
- case VG_PIXEL_LAYOUT:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_pixelLayout);
- break;
-
- case VG_SCREEN_LAYOUT:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, VG_PIXEL_LAYOUT_UNKNOWN);
- break;
-
- case VG_FILTER_FORMAT_LINEAR:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_filterFormatLinear);
- break;
-
- case VG_FILTER_FORMAT_PREMULTIPLIED:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_filterFormatPremultiplied);
- break;
-
- case VG_FILTER_CHANNEL_MASK:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, context->m_filterChannelMask);
- break;
-
- case VG_MAX_SCISSOR_RECTS:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, RI_MAX_SCISSOR_RECTANGLES);
- break;
-
- case VG_MAX_DASH_COUNT:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, RI_MAX_DASH_COUNT);
- break;
-
- case VG_MAX_KERNEL_SIZE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, RI_MAX_KERNEL_SIZE);
- break;
-
- case VG_MAX_SEPARABLE_KERNEL_SIZE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, RI_MAX_SEPARABLE_KERNEL_SIZE);
- break;
-
- case VG_MAX_COLOR_RAMP_STOPS:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, RI_MAX_COLOR_RAMP_STOPS);
- break;
-
- case VG_MAX_IMAGE_WIDTH:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, RI_MAX_IMAGE_WIDTH);
- break;
-
- case VG_MAX_IMAGE_HEIGHT:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, RI_MAX_IMAGE_HEIGHT);
- break;
-
- case VG_MAX_IMAGE_PIXELS:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, RI_MAX_IMAGE_PIXELS);
- break;
-
- case VG_MAX_IMAGE_BYTES:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, RI_MAX_IMAGE_BYTES);
- break;
-
- case VG_MAX_FLOAT:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, RI_FLOAT_MAX);
- break;
-
- case VG_MAX_GAUSSIAN_STD_DEVIATION:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, RI_MAX_GAUSSIAN_STD_DEVIATION);
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- break;
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGfloat RI_APIENTRY vgGetf(VGParamType type)
-{
- RI_GET_CONTEXT(0.0f);
- RI_IF_ERROR(type == VG_SCISSOR_RECTS || type == VG_STROKE_DASH_PATTERN || type == VG_TILE_FILL_COLOR ||
- type == VG_CLEAR_COLOR, VG_ILLEGAL_ARGUMENT_ERROR, 0.0f); //vector type value
- RIfloat ret = 0.0f;
- getifv(context, type, 1, &ret, true);
- RI_RETURN(ret);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGint RI_APIENTRY vgGeti(VGParamType type)
-{
- RI_GET_CONTEXT(0);
- RI_IF_ERROR(type == VG_SCISSOR_RECTS || type == VG_STROKE_DASH_PATTERN || type == VG_TILE_FILL_COLOR ||
- type == VG_CLEAR_COLOR, VG_ILLEGAL_ARGUMENT_ERROR, 0); //vector type value
- VGint ret = 0;
- getifv(context, type, 1, &ret, false);
- RI_RETURN(ret);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgGetiv(VGParamType type, VGint count, VGint * values)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(count <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!values || !isAligned(values,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- getifv(context, type, count, values, false);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgGetfv(VGParamType type, VGint count, VGfloat * values)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(count <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!values || !isAligned(values,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- getifv(context, type, count, values, true);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGint RI_APIENTRY vgGetVectorSize(VGParamType type)
-{
- RI_GET_CONTEXT(0);
- VGint ret = 0;
- switch(type)
- {
- case VG_MATRIX_MODE:
- case VG_FILL_RULE:
- case VG_IMAGE_QUALITY:
- case VG_RENDERING_QUALITY:
- case VG_BLEND_MODE:
- case VG_IMAGE_MODE:
- ret = 1;
- break;
-
- case VG_SCISSOR_RECTS:
- ret = 4*context->m_scissor.size();
- break;
-
- case VG_COLOR_TRANSFORM:
- ret = 1;
- break;
-
- case VG_COLOR_TRANSFORM_VALUES:
- ret = 8;
- break;
-
- case VG_STROKE_LINE_WIDTH:
- case VG_STROKE_CAP_STYLE:
- case VG_STROKE_JOIN_STYLE:
- case VG_STROKE_MITER_LIMIT:
- ret = 1;
- break;
-
- case VG_STROKE_DASH_PATTERN:
- ret = context->m_inputStrokeDashPattern.size();
- break;
-
- case VG_STROKE_DASH_PHASE:
- case VG_STROKE_DASH_PHASE_RESET:
- ret = 1;
- break;
-
- case VG_TILE_FILL_COLOR:
- case VG_CLEAR_COLOR:
- ret = 4;
- break;
-
- case VG_GLYPH_ORIGIN:
- ret = 2;
- break;
-
- case VG_MASKING:
- case VG_SCISSORING:
- case VG_PIXEL_LAYOUT:
- case VG_SCREEN_LAYOUT:
- case VG_FILTER_FORMAT_LINEAR:
- case VG_FILTER_FORMAT_PREMULTIPLIED:
- case VG_FILTER_CHANNEL_MASK:
- case VG_MAX_SCISSOR_RECTS:
- case VG_MAX_DASH_COUNT:
- case VG_MAX_KERNEL_SIZE:
- case VG_MAX_SEPARABLE_KERNEL_SIZE:
- case VG_MAX_COLOR_RAMP_STOPS:
- case VG_MAX_IMAGE_WIDTH:
- case VG_MAX_IMAGE_HEIGHT:
- case VG_MAX_IMAGE_PIXELS:
- case VG_MAX_IMAGE_BYTES:
- case VG_MAX_FLOAT:
- case VG_MAX_GAUSSIAN_STD_DEVIATION:
- ret = 1;
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- break;
- }
- RI_RETURN(ret);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static void setPaintParameterifv(VGContext* context, Paint* paint, VGPaintParamType paramType, VGint count, const void* values, bool floats)
-{
- RI_ASSERT(context);
- RI_ASSERT(paint);
-
- int ivalue = paramToInt(values, floats, count, 0);
-
- switch(paramType)
- {
- case VG_PAINT_TYPE:
- if(count != 1 || ivalue < VG_PAINT_TYPE_COLOR || ivalue > VG_PAINT_TYPE_PATTERN) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- paint->m_paintType = (VGPaintType)ivalue;
- break;
-
- case VG_PAINT_COLOR:
- if(count != 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- paint->m_inputPaintColor.set(paramToFloat(values, floats, count, 0),
- paramToFloat(values, floats, count, 1),
- paramToFloat(values, floats, count, 2),
- paramToFloat(values, floats, count, 3),
- Color::sRGBA);
- paint->m_paintColor = inputColor(paint->m_inputPaintColor);
- paint->m_paintColor.clamp();
- paint->m_paintColor.premultiply();
- break;
-
- case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
- if(count != 1 || ivalue < VG_COLOR_RAMP_SPREAD_PAD || ivalue > VG_COLOR_RAMP_SPREAD_REFLECT) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- paint->m_colorRampSpreadMode = (VGColorRampSpreadMode)ivalue;
- break;
-
- case VG_PAINT_COLOR_RAMP_STOPS:
- {
- int numStops = count/5;
- if(count != numStops*5) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; } //count must be a multiple of five
- try
- {
- Array<Paint::GradientStop> colorRampStops;
- Array<Paint::GradientStop> inputColorRampStops;
- RIfloat prevOffset = -RI_FLOAT_MAX;
- bool valid = true;
- for(int i=0;i<RI_INT_MIN(numStops, RI_MAX_COLOR_RAMP_STOPS);i++) //NOTE: ignores the final stop if there is not enough parameters
- {
- Paint::GradientStop gs;
- gs.offset = paramToFloat(values, floats, count, i*5);
- gs.color.set(paramToFloat(values, floats, count, i*5+1),
- paramToFloat(values, floats, count, i*5+2),
- paramToFloat(values, floats, count, i*5+3),
- paramToFloat(values, floats, count, i*5+4),
- Color::sRGBA);
- inputColorRampStops.push_back(gs);
-
- if(gs.offset < prevOffset)
- valid = false; //decreasing sequence, ignore it
-
- if(gs.offset >= 0.0f && gs.offset <= 1.0f)
- {
- gs.color.clamp();
-
- if(!colorRampStops.size() && gs.offset > 0.0f)
- { //the first valid stop is not at 0, replicate the first one
- RIfloat tmp = gs.offset;
- gs.offset = 0.0f;
- colorRampStops.push_back(gs); //throws bad_alloc
- gs.offset = tmp;
- }
- colorRampStops.push_back(gs); //throws bad_alloc
- }
- prevOffset = gs.offset;
- }
- if(valid && colorRampStops.size() && colorRampStops[colorRampStops.size()-1].offset < 1.0f)
- { //there is at least one stop, but the last one is not at 1, replicate the last one
- Paint::GradientStop gs = colorRampStops[colorRampStops.size()-1];
- gs.offset = 1.0f;
- colorRampStops.push_back(gs); //throws bad_alloc
- }
- if(!valid || !colorRampStops.size())
- { //there are no valid stops, add implicit stops
- colorRampStops.clear();
- Paint::GradientStop gs;
- gs.offset = 0.0f;
- gs.color.set(0,0,0,1,Color::sRGBA);
- colorRampStops.push_back(gs); //throws bad_alloc
- gs.offset = 1.0f;
- gs.color.set(1,1,1,1,Color::sRGBA);
- colorRampStops.push_back(gs); //throws bad_alloc
- }
- RI_ASSERT(colorRampStops.size() >= 2 && colorRampStops.size() <= RI_MAX_COLOR_RAMP_STOPS);
- paint->m_colorRampStops.swap(colorRampStops); //set paint array
- paint->m_inputColorRampStops.swap(inputColorRampStops); //set paint array
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- break;
- }
-
- case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
- if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- paint->m_colorRampPremultiplied = ivalue ? VG_TRUE : VG_FALSE;
- break;
-
- case VG_PAINT_LINEAR_GRADIENT:
- if(count != 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- paint->m_inputLinearGradientPoint0.set(paramToFloat(values, floats, count, 0),
- paramToFloat(values, floats, count, 1));
- paint->m_inputLinearGradientPoint1.set(paramToFloat(values, floats, count, 2),
- paramToFloat(values, floats, count, 3));
- paint->m_linearGradientPoint0 = inputVector2(paint->m_inputLinearGradientPoint0);
- paint->m_linearGradientPoint1 = inputVector2(paint->m_inputLinearGradientPoint1);
- break;
-
- case VG_PAINT_RADIAL_GRADIENT:
- if(count != 5) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- paint->m_inputRadialGradientCenter.set(paramToFloat(values, floats, count, 0),
- paramToFloat(values, floats, count, 1));
- paint->m_inputRadialGradientFocalPoint.set(paramToFloat(values, floats, count, 2),
- paramToFloat(values, floats, count, 3));
- paint->m_inputRadialGradientRadius = paramToFloat(values, floats, count, 4);
- paint->m_radialGradientCenter = inputVector2(paint->m_inputRadialGradientCenter);
- paint->m_radialGradientFocalPoint = inputVector2(paint->m_inputRadialGradientFocalPoint);
- paint->m_radialGradientRadius = inputFloat(paint->m_inputRadialGradientRadius);
- break;
-
- case VG_PAINT_PATTERN_TILING_MODE:
- if(count != 1 || ivalue < VG_TILE_FILL || ivalue > VG_TILE_REFLECT) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- paint->m_patternTilingMode = (VGTilingMode)ivalue;
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- break;
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetParameterf(VGHandle object, VGint paramType, VGfloat value)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- bool isImage = context->isValidImage(object);
- bool isPath = context->isValidPath(object);
- bool isPaint = context->isValidPaint(object);
- bool isMaskLayer = context->isValidMaskLayer(object);
- bool isFont = context->isValidFont(object);
- RI_IF_ERROR(!isImage && !isPath && !isPaint && !isMaskLayer && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
- RI_IF_ERROR(paramType == VG_PAINT_COLOR || paramType == VG_PAINT_COLOR_RAMP_STOPS || paramType == VG_PAINT_LINEAR_GRADIENT ||
- paramType == VG_PAINT_RADIAL_GRADIENT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //vector valued parameter
- VGfloat values[1] = {value};
- if(isImage)
- { //read only, the function does nothing
- RI_ASSERT(!isPath && !isPaint && !isMaskLayer && !isFont);
- if(paramType < VG_IMAGE_FORMAT || paramType > VG_IMAGE_HEIGHT)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else if(isPath)
- { //read only, the function does nothing
- RI_ASSERT(!isImage && !isPaint && !isMaskLayer && !isFont);
- if(paramType < VG_PATH_FORMAT || paramType > VG_PATH_NUM_COORDS)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else if(isPaint)
- {
- RI_ASSERT(!isImage && !isPath && !isMaskLayer && !isFont);
- setPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, 1, values, true);
- }
- else if(isMaskLayer)
- {
- RI_ASSERT(!isImage && !isPath && !isPaint && !isFont);
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else
- { //read only, the function does nothing
- RI_ASSERT(!isImage && !isPath && !isPaint && !isMaskLayer && isFont);
- if (paramType != VG_FONT_NUM_GLYPHS)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetParameteri(VGHandle object, VGint paramType, VGint value)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- bool isImage = context->isValidImage(object);
- bool isPath = context->isValidPath(object);
- bool isPaint = context->isValidPaint(object);
- bool isMaskLayer = context->isValidMaskLayer(object);
- bool isFont = context->isValidFont(object);
- RI_IF_ERROR(!isImage && !isPath && !isPaint && !isMaskLayer && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
- RI_IF_ERROR(paramType == VG_PAINT_COLOR || paramType == VG_PAINT_COLOR_RAMP_STOPS || paramType == VG_PAINT_LINEAR_GRADIENT ||
- paramType == VG_PAINT_RADIAL_GRADIENT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //vector valued parameter
- VGint values[1] = {value};
- if(isImage)
- { //read only, the function does nothing
- RI_ASSERT(!isPath && !isPaint && !isMaskLayer && !isFont);
- if(paramType < VG_IMAGE_FORMAT || paramType > VG_IMAGE_HEIGHT)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else if(isPath)
- { //read only, the function does nothing
- RI_ASSERT(!isImage && !isPaint && !isMaskLayer && !isFont);
- if(paramType < VG_PATH_FORMAT || paramType > VG_PATH_NUM_COORDS)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else if(isPaint)
- {
- RI_ASSERT(!isImage && !isPath && !isMaskLayer && !isFont);
- setPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, 1, values, false);
- }
- else if(isMaskLayer)
- {
- RI_ASSERT(!isImage && !isPath && !isPaint && !isFont);
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else
- { //read only, the function does nothing
- RI_ASSERT(!isImage && !isPath && !isPaint && !isMaskLayer && isFont);
- if (paramType != VG_FONT_NUM_GLYPHS)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetParameterfv(VGHandle object, VGint paramType, VGint count, const VGfloat * values)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(count < 0 || (!values && count > 0) || (values && !isAligned(values,4)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- bool isImage = context->isValidImage(object);
- bool isPath = context->isValidPath(object);
- bool isPaint = context->isValidPaint(object);
- bool isMaskLayer = context->isValidMaskLayer(object);
- bool isFont = context->isValidFont(object);
- RI_IF_ERROR(!isImage && !isPath && !isPaint && !isMaskLayer && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
- if(isImage)
- { //read only, the function does nothing
- RI_ASSERT(!isPath && !isPaint && !isMaskLayer && !isFont);
- if(paramType < VG_IMAGE_FORMAT || paramType > VG_IMAGE_HEIGHT)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else if(isPath)
- { //read only, the function does nothing
- RI_ASSERT(!isImage && !isPaint && !isMaskLayer && !isFont);
- if(paramType < VG_PATH_FORMAT || paramType > VG_PATH_NUM_COORDS)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else if(isPaint)
- {
- RI_ASSERT(!isImage && !isPath && !isMaskLayer && !isFont);
- setPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, count, values, true);
- }
- else if(isMaskLayer)
- {
- RI_ASSERT(!isImage && !isPath && !isPaint && !isFont);
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else
- { //read only, the function does nothing
- RI_ASSERT(!isImage && !isPath && !isPaint && !isMaskLayer && isFont);
- if (paramType != VG_FONT_NUM_GLYPHS)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetParameteriv(VGHandle object, VGint paramType, VGint count, const VGint * values)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(count < 0 || (!values && count > 0) || (values && !isAligned(values,4)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- bool isImage = context->isValidImage(object);
- bool isPath = context->isValidPath(object);
- bool isPaint = context->isValidPaint(object);
- bool isMaskLayer = context->isValidMaskLayer(object);
- bool isFont = context->isValidFont(object);
- RI_IF_ERROR(!isImage && !isPath && !isPaint && !isMaskLayer && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
- if(isImage)
- { //read only, the function does nothing
- RI_ASSERT(!isPath && !isPaint && !isMaskLayer && !isFont);
- if(paramType < VG_IMAGE_FORMAT || paramType > VG_IMAGE_HEIGHT)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else if(isPath)
- { //read only, the function does nothing
- RI_ASSERT(!isImage && !isPaint && !isMaskLayer && !isFont);
- if(paramType < VG_PATH_FORMAT || paramType > VG_PATH_NUM_COORDS)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else if(isPaint)
- {
- RI_ASSERT(!isImage && !isPath && !isMaskLayer && !isFont);
- setPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, count, values, false);
- }
- else if(isMaskLayer)
- {
- RI_ASSERT(!isImage && !isPath && !isPaint && !isFont);
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- else
- { //read only, the function does nothing
- RI_ASSERT(!isImage && !isPath && !isPaint && !isMaskLayer && isFont);
- if (paramType != VG_FONT_NUM_GLYPHS)
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static void getPaintParameterifv(VGContext* context, Paint* paint, VGPaintParamType type, VGint count, void* values, bool floats)
-{
- switch(type)
- {
- case VG_PAINT_TYPE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, paint->m_paintType);
- break;
-
- case VG_PAINT_COLOR:
- if(count > 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, paint->m_inputPaintColor.r);
- floatToParam(values, floats, count, 1, paint->m_inputPaintColor.g);
- floatToParam(values, floats, count, 2, paint->m_inputPaintColor.b);
- floatToParam(values, floats, count, 3, paint->m_inputPaintColor.a);
- break;
-
- case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, paint->m_colorRampSpreadMode);
- break;
-
- case VG_PAINT_COLOR_RAMP_STOPS:
- {
- if(count > paint->m_inputColorRampStops.size()*5) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- int j = 0;
- for(int i=0;i<paint->m_inputColorRampStops.size();i++)
- {
- floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].offset);
- floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.r);
- floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.g);
- floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.b);
- floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.a);
- }
- break;
- }
-
- case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, paint->m_colorRampPremultiplied);
- break;
-
- case VG_PAINT_LINEAR_GRADIENT:
- if(count > 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, paint->m_inputLinearGradientPoint0.x);
- floatToParam(values, floats, count, 1, paint->m_inputLinearGradientPoint0.y);
- floatToParam(values, floats, count, 2, paint->m_inputLinearGradientPoint1.x);
- floatToParam(values, floats, count, 3, paint->m_inputLinearGradientPoint1.y);
- break;
-
- case VG_PAINT_RADIAL_GRADIENT:
- if(count > 5) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, paint->m_inputRadialGradientCenter.x);
- floatToParam(values, floats, count, 1, paint->m_inputRadialGradientCenter.y);
- floatToParam(values, floats, count, 2, paint->m_inputRadialGradientFocalPoint.x);
- floatToParam(values, floats, count, 3, paint->m_inputRadialGradientFocalPoint.y);
- floatToParam(values, floats, count, 4, paint->m_inputRadialGradientRadius);
- break;
-
- case VG_PAINT_PATTERN_TILING_MODE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, paint->m_patternTilingMode);
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- break;
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static void getPathParameterifv(VGContext* context, Path* path, VGPathParamType type, VGint count, void* values, bool floats)
-{
- switch(type)
- {
- case VG_PATH_FORMAT:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, path->getFormat());
- break;
-
- case VG_PATH_DATATYPE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, path->getDatatype());
- break;
-
- case VG_PATH_SCALE:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, path->getScale());
- break;
-
- case VG_PATH_BIAS:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- floatToParam(values, floats, count, 0, path->getBias());
- break;
-
- case VG_PATH_NUM_SEGMENTS:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, path->getNumSegments());
- break;
-
- case VG_PATH_NUM_COORDS:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, path->getNumCoordinates());
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- break;
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static void getImageParameterifv(VGContext* context, Image* image, VGImageParamType type, VGint count, void* values, bool floats)
-{
- switch(type)
- {
- case VG_IMAGE_FORMAT:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- RI_ASSERT(isValidImageFormat(image->getDescriptor().format));
- intToParam(values, floats, count, 0, image->getDescriptor().format);
- break;
-
- case VG_IMAGE_WIDTH:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, image->getWidth());
- break;
-
- case VG_IMAGE_HEIGHT:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, image->getHeight());
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- break;
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static void getFontParameterifv(VGContext* context, Font* font, VGFontParamType type, VGint count, void* values, bool floats)
-{
- switch(type)
- {
- case VG_FONT_NUM_GLYPHS:
- if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
- intToParam(values, floats, count, 0, font->getNumGlyphs());
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
- break;
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGfloat RI_APIENTRY vgGetParameterf(VGHandle object, VGint paramType)
-{
- RI_GET_CONTEXT(0.0f);
- RI_IF_ERROR(paramType == VG_PAINT_COLOR || paramType == VG_PAINT_COLOR_RAMP_STOPS || paramType == VG_PAINT_LINEAR_GRADIENT ||
- paramType == VG_PAINT_RADIAL_GRADIENT, VG_ILLEGAL_ARGUMENT_ERROR, 0.0f); //vector valued parameter
- bool isImage = context->isValidImage(object);
- bool isPath = context->isValidPath(object);
- bool isPaint = context->isValidPaint(object);
- bool isFont = context->isValidFont(object);
- RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, 0.0f); //invalid object handle
- VGfloat ret = 0.0f;
- if(isImage)
- {
- RI_ASSERT(!isPath && !isPaint && !isFont);
- getImageParameterifv(context, (Image*)object, (VGImageParamType)paramType, 1, &ret, true);
- }
- else if(isPath)
- {
- RI_ASSERT(!isImage && !isPaint && !isFont);
- getPathParameterifv(context, (Path*)object, (VGPathParamType)paramType, 1, &ret, true);
- }
- else if(isPaint)
- {
- RI_ASSERT(!isImage && !isPath && !isFont);
- getPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, 1, &ret, true);
- }
- else
- {
- RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
- getFontParameterifv(context, (Font*)object, (VGFontParamType)paramType, 1, &ret, true);
- }
- RI_RETURN(ret);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGint RI_APIENTRY vgGetParameteri(VGHandle object, VGint paramType)
-{
- RI_GET_CONTEXT(0);
- RI_IF_ERROR(paramType == VG_PAINT_COLOR || paramType == VG_PAINT_COLOR_RAMP_STOPS || paramType == VG_PAINT_LINEAR_GRADIENT ||
- paramType == VG_PAINT_RADIAL_GRADIENT, VG_ILLEGAL_ARGUMENT_ERROR, 0); //vector valued parameter
- bool isImage = context->isValidImage(object);
- bool isPath = context->isValidPath(object);
- bool isPaint = context->isValidPaint(object);
- bool isFont = context->isValidFont(object);
- RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, 0); //invalid object handle
- VGint ret = 0;
- if(isImage)
- {
- RI_ASSERT(!isPath && !isPaint && !isFont);
- getImageParameterifv(context, (Image*)object, (VGImageParamType)paramType, 1, &ret, false);
- }
- else if(isPath)
- {
- RI_ASSERT(!isImage && !isPaint && !isFont);
- getPathParameterifv(context, (Path*)object, (VGPathParamType)paramType, 1, &ret, false);
- }
- else if(isPaint)
- {
- RI_ASSERT(!isImage && !isPath && !isFont);
- getPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, 1, &ret, false);
- }
- else
- {
- RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
- getFontParameterifv(context, (Font*)object, (VGFontParamType)paramType, 1, &ret, false);
- }
- RI_RETURN(ret);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgGetParameterfv(VGHandle object, VGint paramType, VGint count, VGfloat * values)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(count <= 0 || !values || !isAligned(values,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- bool isImage = context->isValidImage(object);
- bool isPath = context->isValidPath(object);
- bool isPaint = context->isValidPaint(object);
- bool isFont = context->isValidFont(object);
- RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
- if(isImage)
- {
- RI_ASSERT(!isPath && !isPaint && !isFont);
- getImageParameterifv(context, (Image*)object, (VGImageParamType)paramType, count, values, true);
- }
- else if(isPath)
- {
- RI_ASSERT(!isImage && !isPaint && !isFont);
- getPathParameterifv(context, (Path*)object, (VGPathParamType)paramType, count, values, true);
- }
- else if(isPaint)
- {
- RI_ASSERT(!isImage && !isPath && !isFont);
- getPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, count, values, true);
- }
- else
- {
- RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
- getFontParameterifv(context, (Font*)object, (VGFontParamType)paramType, count, values, true);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgGetParameteriv(VGHandle object, VGint paramType, VGint count, VGint * values)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(count <= 0 || !values || !isAligned(values,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- bool isImage = context->isValidImage(object);
- bool isPath = context->isValidPath(object);
- bool isPaint = context->isValidPaint(object);
- bool isFont = context->isValidFont(object);
- RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
- if(isImage)
- {
- RI_ASSERT(!isPath && !isPaint && !isFont);
- getImageParameterifv(context, (Image*)object, (VGImageParamType)paramType, count, values, false);
- }
- else if(isPath)
- {
- RI_ASSERT(!isImage && !isPaint && !isFont);
- getPathParameterifv(context, (Path*)object, (VGPathParamType)paramType, count, values, false);
- }
- else if(isPaint)
- {
- RI_ASSERT(!isImage && !isPath && !isFont);
- getPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, count, values, false);
- }
- else
- {
- RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
- getFontParameterifv(context, (Font*)object, (VGFontParamType)paramType, count, values, false);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGint RI_APIENTRY vgGetParameterVectorSize(VGHandle object, VGint paramType)
-{
- RI_GET_CONTEXT(0);
- bool isImage = context->isValidImage(object);
- bool isPath = context->isValidPath(object);
- bool isPaint = context->isValidPaint(object);
- bool isFont = context->isValidFont(object);
- RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, 0); //invalid object handle
- int ret = 0;
- if(isImage)
- {
- RI_ASSERT(!isPath && !isPaint && !isFont);
- switch(paramType)
- {
- case VG_IMAGE_FORMAT:
- case VG_IMAGE_WIDTH:
- case VG_IMAGE_HEIGHT:
- ret = 1;
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid paramType
- break;
- }
- }
- else if(isPath)
- {
- RI_ASSERT(!isImage && !isPaint && !isFont);
- switch(paramType)
- {
- case VG_PATH_FORMAT:
- case VG_PATH_DATATYPE:
- case VG_PATH_SCALE:
- case VG_PATH_BIAS:
- case VG_PATH_NUM_SEGMENTS:
- case VG_PATH_NUM_COORDS:
- ret = 1;
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid paramType
- break;
- }
- }
- else if(isPaint)
- {
- RI_ASSERT(!isImage && !isPath && !isFont);
- switch(paramType)
- {
- case VG_PAINT_TYPE:
- case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
- case VG_PAINT_PATTERN_TILING_MODE:
- ret = 1;
- break;
-
- case VG_PAINT_COLOR:
- case VG_PAINT_LINEAR_GRADIENT:
- ret = 4;
- break;
-
- case VG_PAINT_COLOR_RAMP_STOPS:
- ret = ((Paint*)object)->m_inputColorRampStops.size() * 5;
- break;
-
- case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
- ret = 1;
- break;
-
- case VG_PAINT_RADIAL_GRADIENT:
- ret = 5;
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid paramType
- break;
- }
- }
- else
- {
- RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
- switch(paramType)
- {
- case VG_FONT_NUM_GLYPHS:
- ret = 1;
- break;
-
- default:
- context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid paramType
- break;
- }
- }
- RI_RETURN(ret);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static Matrix3x3* getCurrentMatrix(VGContext* context)
-{
- RI_ASSERT(context);
- switch(context->m_matrixMode)
- {
- case VG_MATRIX_PATH_USER_TO_SURFACE:
- return &context->m_pathUserToSurface;
-
- case VG_MATRIX_IMAGE_USER_TO_SURFACE:
- return &context->m_imageUserToSurface;
-
- case VG_MATRIX_FILL_PAINT_TO_USER:
- return &context->m_fillPaintToUser;
-
- case VG_MATRIX_STROKE_PAINT_TO_USER:
- return &context->m_strokePaintToUser;
-
- default:
- RI_ASSERT(context->m_matrixMode == VG_MATRIX_GLYPH_USER_TO_SURFACE);
- return &context->m_glyphUserToSurface;
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgLoadIdentity(void)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- Matrix3x3* d = getCurrentMatrix(context);
- d->identity();
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgLoadMatrix(const VGfloat * m)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!m || !isAligned(m,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Matrix3x3* d = getCurrentMatrix(context);
- d->set(inputFloat(m[0]), inputFloat(m[3]), inputFloat(m[6]),
- inputFloat(m[1]), inputFloat(m[4]), inputFloat(m[7]),
- inputFloat(m[2]), inputFloat(m[5]), inputFloat(m[8]));
- if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
- {
- (*d)[2].set(0,0,1);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgGetMatrix(VGfloat * m)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!m || !isAligned(m,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Matrix3x3* d = getCurrentMatrix(context);
- m[0] = (*d)[0][0];
- m[1] = (*d)[1][0];
- m[2] = (*d)[2][0];
- m[3] = (*d)[0][1];
- m[4] = (*d)[1][1];
- m[5] = (*d)[2][1];
- m[6] = (*d)[0][2];
- m[7] = (*d)[1][2];
- m[8] = (*d)[2][2];
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgMultMatrix(const VGfloat * m)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!m || !isAligned(m,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Matrix3x3 n(inputFloat(m[0]), inputFloat(m[3]), inputFloat(m[6]),
- inputFloat(m[1]), inputFloat(m[4]), inputFloat(m[7]),
- inputFloat(m[2]), inputFloat(m[5]), inputFloat(m[8]));
- if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
- n[2].set(0,0,1);
-
- Matrix3x3* d = getCurrentMatrix(context);
- *d *= n;
- if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
- {
- (*d)[2].set(0,0,1); //force affinity
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgTranslate(VGfloat tx, VGfloat ty)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- Matrix3x3 n(1, 0, inputFloat(tx),
- 0, 1, inputFloat(ty),
- 0, 0, 1 );
- Matrix3x3* d = getCurrentMatrix(context);
- *d *= n;
- if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
- {
- (*d)[2].set(0,0,1); //force affinity
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgScale(VGfloat sx, VGfloat sy)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- Matrix3x3 n(inputFloat(sx), 0, 0,
- 0, inputFloat(sy), 0,
- 0, 0, 1 );
- Matrix3x3* d = getCurrentMatrix(context);
- *d *= n;
- if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
- {
- (*d)[2].set(0,0,1); //force affinity
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgShear(VGfloat shx, VGfloat shy)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- Matrix3x3 n(1, inputFloat(shx), 0,
- inputFloat(shy), 1, 0,
- 0, 0, 1);
- Matrix3x3* d = getCurrentMatrix(context);
- *d *= n;
- if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
- {
- (*d)[2].set(0,0,1); //force affinity
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgRotate(VGfloat angle)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RIfloat a = RI_DEG_TO_RAD(inputFloat(angle));
- Matrix3x3 n((RIfloat)cos(a), -(RIfloat)sin(a), 0,
- (RIfloat)sin(a), (RIfloat)cos(a), 0,
- 0, 0, 1 );
- Matrix3x3* d = getCurrentMatrix(context);
- *d *= n;
- if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
- {
- (*d)[2].set(0,0,1); //force affinity
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgMask(VGHandle mask, VGMaskOperation operation, VGint x, VGint y, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- bool isImage = context->isValidImage(mask);
- bool isMaskLayer = context->isValidMaskLayer(mask);
- RI_IF_ERROR(operation != VG_CLEAR_MASK && operation != VG_FILL_MASK && !isImage && !isMaskLayer, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(operation != VG_CLEAR_MASK && operation != VG_FILL_MASK && isImage && eglvgIsInUse((Image*)mask), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(operation < VG_CLEAR_MASK || operation > VG_SUBTRACT_MASK, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Drawable* drawable = context->getCurrentDrawable();
- RI_IF_ERROR(isMaskLayer && drawable->getNumSamples() != ((Surface*)mask)->getNumSamples(), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- if(!drawable || !drawable->getMaskBuffer())
- {
- RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment or context has no mask buffer
- }
- if(isImage)
- drawable->getMaskBuffer()->mask((Image*)mask, operation, x, y, width, height);
- else
- drawable->getMaskBuffer()->mask((Surface*)mask, operation, x, y, width, height);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static void renderStroke(const VGContext* context, int w, int h, int numSamples, Path* path, Rasterizer& rasterizer, const PixelPipe* pixelPipe, const Matrix3x3& userToSurface)
-{
- RI_ASSERT(context);
- RI_ASSERT(w > 0 && h > 0 && numSamples >= 1 && numSamples <= 32);
-
- RIuint32* covBuffer = RI_NEW_ARRAY(RIuint32, w*h);
- memset(covBuffer, 0, w*h*sizeof(RIuint32));
-
- rasterizer.setup(0, 0, w, h, VG_NON_ZERO, NULL, covBuffer);
- path->stroke(userToSurface, rasterizer, context->m_strokeDashPattern, context->m_strokeDashPhase, context->m_strokeDashPhaseReset ? true : false,
- context->m_strokeLineWidth, context->m_strokeCapStyle, context->m_strokeJoinStyle, RI_MAX(context->m_strokeMiterLimit, 1.0f)); //throws bad_alloc
-
- int sx,sy,ex,ey;
- rasterizer.getBBox(sx,sy,ex,ey);
- RI_ASSERT(sx >= 0 && sx <= w);
- RI_ASSERT(sy >= 0 && sy <= h);
- RI_ASSERT(ex >= 0 && ex <= w);
- RI_ASSERT(ey >= 0 && ey <= h);
-
- for(int j=sy;j<ey;j++)
- {
- for(int i=sx;i<ex;i++)
- {
- unsigned int c = covBuffer[j*w+i];
- if(c)
- {
- int coverage = 0;
- for(int k=0;k<numSamples;k++)
- {
- if(c & (1<<k))
- coverage++;
- }
- pixelPipe->pixelPipe(i, j, (RIfloat)coverage/(RIfloat)numSamples, c);
- }
- }
- }
- RI_DELETE_ARRAY(covBuffer);
-}
-
-void RI_APIENTRY vgRenderToMask(VGPath path, VGbitfield paintModes, VGMaskOperation operation)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- RI_IF_ERROR(!paintModes || (paintModes & ~(VG_FILL_PATH | VG_STROKE_PATH)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid paint mode
- RI_IF_ERROR(operation < VG_CLEAR_MASK || operation > VG_SUBTRACT_MASK, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Drawable* curr = context->getCurrentDrawable();
- if(!curr || !curr->getMaskBuffer())
- {
- RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment or context has no mask buffer
- }
-
- if(operation == VG_CLEAR_MASK || operation == VG_FILL_MASK)
- {
- Surface* dummy = NULL;
- curr->getMaskBuffer()->mask(dummy, operation, 0, 0, curr->getWidth(), curr->getHeight());
- RI_RETURN(RI_NO_RETVAL);
- }
-
- try
- {
- Drawable drawable(Color::formatToDescriptor(VG_A_8), curr->getWidth(), curr->getHeight(), curr->getNumSamples(), 1); //TODO 0 mask bits (mask buffer is not used)
-
- Rasterizer rasterizer;
- if(context->m_scissoring)
- rasterizer.setScissor(context->m_scissor); //throws bad_alloc
- int numSamples = rasterizer.setupSamplingPattern(context->m_renderingQuality, drawable.getNumSamples());
-
- PixelPipe pixelPipe;
- pixelPipe.setDrawable(&drawable);
- pixelPipe.setMask(false);
- pixelPipe.setPaint(NULL); //use default paint (solid color alpha = 1)
- pixelPipe.setBlendMode(VG_BLEND_SRC); //write solid color * coverage to dest
-
- Matrix3x3 userToSurface = context->m_pathUserToSurface;
- userToSurface[2].set(0,0,1); //force affinity
-
- if(paintModes & VG_FILL_PATH)
- {
- drawable.getColorBuffer()->clear(Color(0,0,0,0,drawable.getColorBuffer()->getDescriptor().internalFormat), 0, 0, drawable.getWidth(), drawable.getHeight());
- ((Path*)path)->fill(userToSurface, rasterizer); //throws bad_alloc
- rasterizer.setup(0, 0, drawable.getWidth(), drawable.getHeight(), context->m_fillRule, &pixelPipe, NULL);
- rasterizer.fill(); //throws bad_alloc
- curr->getMaskBuffer()->mask(drawable.getColorBuffer(), operation, 0, 0, drawable.getWidth(), drawable.getHeight());
- }
-
- if(paintModes & VG_STROKE_PATH && context->m_strokeLineWidth > 0.0f)
- {
- drawable.getColorBuffer()->clear(Color(0,0,0,0,drawable.getColorBuffer()->getDescriptor().internalFormat), 0, 0, drawable.getWidth(), drawable.getHeight());
- renderStroke(context, drawable.getWidth(), drawable.getHeight(), numSamples, (Path*)path, rasterizer, &pixelPipe, userToSurface);
- curr->getMaskBuffer()->mask(drawable.getColorBuffer(), operation, 0, 0, drawable.getWidth(), drawable.getHeight());
- }
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGMaskLayer RI_APIENTRY vgCreateMaskLayer(VGint width, VGint height)
-{
- RI_GET_CONTEXT(VG_INVALID_HANDLE);
- RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
- RI_IF_ERROR(width > RI_MAX_IMAGE_WIDTH || height > RI_MAX_IMAGE_HEIGHT || width*height > RI_MAX_IMAGE_PIXELS ||
- width*height > RI_MAX_IMAGE_BYTES, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
- Drawable* curr = context->getCurrentDrawable();
- if(!curr || !curr->getMaskBuffer())
- RI_RETURN(VG_INVALID_HANDLE); //no current drawing surface
-
- Surface* layer = NULL;
- try
- {
- layer = RI_NEW(Surface, (Color::formatToDescriptor(VG_A_8), width, height, curr->getNumSamples())); //throws bad_alloc
- RI_ASSERT(layer);
- context->m_maskLayerManager->addResource(layer, context); //throws bad_alloc
- layer->clear(Color(1,1,1,1,Color::sRGBA), 0, 0, width, height);
- RI_RETURN((VGMaskLayer)layer);
- }
- catch(std::bad_alloc)
- {
- RI_DELETE(layer);
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- RI_RETURN(VG_INVALID_HANDLE);
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgDestroyMaskLayer(VGMaskLayer maskLayer)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidMaskLayer(maskLayer), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid handle
-
- context->m_maskLayerManager->removeResource((Surface*)maskLayer);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgFillMaskLayer(VGMaskLayer maskLayer, VGint x, VGint y, VGint width, VGint height, VGfloat value)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidMaskLayer(maskLayer), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid handle
- RI_IF_ERROR(value < 0.0f || value > 1.0f, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Surface* layer = (Surface*)maskLayer;
- RI_IF_ERROR(width <= 0 || height <= 0 || x < 0 || y < 0 || x > layer->getWidth()-width || y > layer->getHeight()-height, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- layer->clear(Color(1,1,1,value,Color::sRGBA), x, y, width, height);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgCopyMask(VGMaskLayer maskLayer, VGint dx, VGint dy, VGint sx, VGint sy, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidMaskLayer(maskLayer), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid handle
- Drawable* drawable = context->getCurrentDrawable();
- if(!drawable || !drawable->getMaskBuffer())
- {
- RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment or context has no mask buffer
- }
- Surface* layer = (Surface*)maskLayer;
- RI_IF_ERROR(width <= 0 || height <= 0 || drawable->getNumSamples() != layer->getNumSamples(), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- try
- { //copy drawing surface mask to mask layer
- layer->blit(drawable->getMaskBuffer(), sx, sy, dx, dy, width, height); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgClear(VGint x, VGint y, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Drawable* drawable = context->getCurrentDrawable();
- if(!drawable)
- {
- RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
- }
-
- try
- {
- if(context->m_scissoring)
- drawable->getColorBuffer()->clear(context->m_clearColor, x, y, width, height, context->m_scissor); //throws bad_alloc
- else
- drawable->getColorBuffer()->clear(context->m_clearColor, x, y, width, height);
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGPath RI_APIENTRY vgCreatePath(VGint pathFormat, VGPathDatatype datatype, VGfloat scale, VGfloat bias, VGint segmentCapacityHint, VGint coordCapacityHint, VGbitfield capabilities)
-{
- RI_GET_CONTEXT(VG_INVALID_HANDLE);
- RI_IF_ERROR(pathFormat != VG_PATH_FORMAT_STANDARD, VG_UNSUPPORTED_PATH_FORMAT_ERROR, VG_INVALID_HANDLE);
- RI_IF_ERROR(datatype < VG_PATH_DATATYPE_S_8 || datatype > VG_PATH_DATATYPE_F, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
- RIfloat s = inputFloat(scale);
- RIfloat b = inputFloat(bias);
- RI_IF_ERROR(s == 0.0f, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
- capabilities &= VG_PATH_CAPABILITY_ALL; //undefined bits are ignored
-
- Path* path = NULL;
- try
- {
- path = RI_NEW(Path, (pathFormat, datatype, s, b, segmentCapacityHint, coordCapacityHint, capabilities)); //throws bad_alloc
- RI_ASSERT(path);
- context->m_pathManager->addResource(path, context); //throws bad_alloc
- RI_RETURN((VGPath)path);
- }
- catch(std::bad_alloc)
- {
- RI_DELETE(path);
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- RI_RETURN(VG_INVALID_HANDLE);
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgClearPath(VGPath path, VGbitfield capabilities)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- capabilities &= VG_PATH_CAPABILITY_ALL; //undefined bits are ignored
- ((Path*)path)->clear(capabilities);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgDestroyPath(VGPath path)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
-
- context->m_pathManager->removeResource((Path*)path);
-
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgRemovePathCapabilities(VGPath path, VGbitfield capabilities)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- capabilities &= VG_PATH_CAPABILITY_ALL; //undefined bits are ignored
-
- VGbitfield caps = ((Path*)path)->getCapabilities();
- caps &= ~capabilities;
- ((Path*)path)->setCapabilities(caps);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGbitfield RI_APIENTRY vgGetPathCapabilities(VGPath path)
-{
- RI_GET_CONTEXT(0);
- RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, 0); //invalid path handle
- VGbitfield ret = ((Path*)path)->getCapabilities();
- RI_RETURN(ret);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgAppendPathData(VGPath dstPath, VGint numSegments, const VGubyte * pathSegments, const void * pathData)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(dstPath), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- Path* p = (Path*)dstPath;
- RI_IF_ERROR(!(p->getCapabilities() & VG_PATH_CAPABILITY_APPEND_TO), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //no append cap
- RI_IF_ERROR(numSegments <= 0 || !pathSegments || !pathData, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //no segments or data
- RI_IF_ERROR((p->getDatatype() == VG_PATH_DATATYPE_S_16 && !isAligned(pathData,2)) ||
- ((p->getDatatype() == VG_PATH_DATATYPE_S_32 || p->getDatatype() == VG_PATH_DATATYPE_F) && !isAligned(pathData,4)),
- VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid alignment
- for(int i=0;i<numSegments;i++)
- {
- VGPathSegment c = (VGPathSegment)(pathSegments[i] & 0x1e);
- RI_IF_ERROR(c < VG_CLOSE_PATH || c > VG_LCWARC_TO, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid segment
- RI_IF_ERROR(c & ~0x1f, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //reserved bits are nonzero
- }
-
- try
- {
- p->appendData((const RIuint8*)pathSegments, numSegments, (const RIuint8*)pathData); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgModifyPathCoords(VGPath dstPath, VGint startIndex, VGint numSegments, const void * pathData)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(dstPath), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- Path* p = (Path*)dstPath;
- RI_IF_ERROR(!(p->getCapabilities() & VG_PATH_CAPABILITY_MODIFY), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //no modify cap
- RI_IF_ERROR(!pathData || startIndex < 0 || numSegments <= 0 || RI_INT_ADDSATURATE(startIndex, numSegments) > p->getNumSegments(), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //no segments
- RI_IF_ERROR((p->getDatatype() == VG_PATH_DATATYPE_S_16 && !isAligned(pathData,2)) ||
- ((p->getDatatype() == VG_PATH_DATATYPE_S_32 || p->getDatatype() == VG_PATH_DATATYPE_F) && !isAligned(pathData,4)),
- VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid alignment
- p->modifyCoords(startIndex, numSegments, (const RIuint8*)pathData);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgAppendPath(VGPath dstPath, VGPath srcPath)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(dstPath) || !context->isValidPath(srcPath), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- RI_IF_ERROR(!(((Path*)dstPath)->getCapabilities() & VG_PATH_CAPABILITY_APPEND_TO) ||
- !(((Path*)srcPath)->getCapabilities() & VG_PATH_CAPABILITY_APPEND_FROM), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //invalid caps
-
- try
- {
- ((Path*)dstPath)->append((Path*)srcPath); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgTransformPath(VGPath dstPath, VGPath srcPath)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(dstPath) || !context->isValidPath(srcPath), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- RI_IF_ERROR(!(((Path*)dstPath)->getCapabilities() & VG_PATH_CAPABILITY_TRANSFORM_TO) ||
- !(((Path*)srcPath)->getCapabilities() & VG_PATH_CAPABILITY_TRANSFORM_FROM), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //invalid caps
- try
- {
- ((Path*)dstPath)->transform((Path*)srcPath, context->m_pathUserToSurface); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static bool drawPath(VGContext* context, VGPath path, const Matrix3x3& userToSurfaceMatrix, VGbitfield paintModes)
-{
- //set up rendering surface and mask buffer
- Drawable* drawable = context->getCurrentDrawable();
- if(!drawable)
- return false; //no EGL surface is current at the moment
-
- Rasterizer rasterizer;
- if(context->m_scissoring)
- rasterizer.setScissor(context->m_scissor); //throws bad_alloc
- int numSamples = rasterizer.setupSamplingPattern(context->m_renderingQuality, drawable->getNumSamples());
-
- PixelPipe pixelPipe;
- pixelPipe.setDrawable(drawable);
- pixelPipe.setMask(context->m_masking ? true : false);
- pixelPipe.setBlendMode(context->m_blendMode);
- pixelPipe.setTileFillColor(context->m_tileFillColor);
- pixelPipe.setImageQuality(context->m_imageQuality);
- pixelPipe.setColorTransform(context->m_colorTransform ? true : false, context->m_colorTransformValues);
-
- Matrix3x3 userToSurface = userToSurfaceMatrix;
- userToSurface[2].set(0,0,1); //force affinity
-
- if(paintModes & VG_FILL_PATH)
- {
- pixelPipe.setPaint((Paint*)context->m_fillPaint);
-
- Matrix3x3 surfaceToPaintMatrix = userToSurface * context->m_fillPaintToUser;
- if(surfaceToPaintMatrix.invert())
- {
- surfaceToPaintMatrix[2].set(0,0,1); //force affinity
- pixelPipe.setSurfaceToPaintMatrix(surfaceToPaintMatrix);
-
- rasterizer.setup(0, 0, drawable->getWidth(), drawable->getHeight(), context->m_fillRule, &pixelPipe, NULL);
- ((Path*)path)->fill(userToSurface, rasterizer); //throws bad_alloc
- rasterizer.fill(); //throws bad_alloc
- }
- }
-
- if(paintModes & VG_STROKE_PATH && context->m_strokeLineWidth > 0.0f)
- {
- pixelPipe.setPaint((Paint*)context->m_strokePaint);
-
- Matrix3x3 surfaceToPaintMatrix = userToSurface * context->m_strokePaintToUser;
- if(surfaceToPaintMatrix.invert())
- {
- surfaceToPaintMatrix[2].set(0,0,1); //force affinity
- pixelPipe.setSurfaceToPaintMatrix(surfaceToPaintMatrix);
-
- renderStroke(context, drawable->getWidth(), drawable->getHeight(), numSamples, (Path*)path, rasterizer, &pixelPipe, userToSurface);
- }
- }
- return true;
-}
-
-void RI_APIENTRY vgDrawPath(VGPath path, VGbitfield paintModes)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- RI_IF_ERROR(!paintModes || (paintModes & ~(VG_FILL_PATH | VG_STROKE_PATH)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid paint mode
-
- try
- {
- if(!drawPath(context, path, context->m_pathUserToSurface, paintModes))
- {
- RI_RETURN(RI_NO_RETVAL);
- }
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGfloat RI_APIENTRY vgPathLength(VGPath path, VGint startSegment, VGint numSegments)
-{
- RI_GET_CONTEXT(-1.0f);
- RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, -1.0f); //invalid path handle
- Path* p = (Path*)path;
- RI_IF_ERROR(!(p->getCapabilities() & VG_PATH_CAPABILITY_PATH_LENGTH), VG_PATH_CAPABILITY_ERROR, -1.0f); //invalid caps
- RI_IF_ERROR(startSegment < 0 || numSegments <= 0 || RI_INT_ADDSATURATE(startSegment, numSegments) > p->getNumSegments(), VG_ILLEGAL_ARGUMENT_ERROR, -1.0f);
- RIfloat pathLength = -1.0f;
- try
- {
- pathLength = p->getPathLength(startSegment, numSegments); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(pathLength);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgPointAlongPath(VGPath path, VGint startSegment, VGint numSegments, VGfloat distance, VGfloat * x, VGfloat * y, VGfloat * tangentX, VGfloat * tangentY)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- Path* p = (Path*)path;
- RI_IF_ERROR((x && y && !(p->getCapabilities() & VG_PATH_CAPABILITY_POINT_ALONG_PATH)) ||
- (tangentX && tangentY && !(p->getCapabilities() & VG_PATH_CAPABILITY_TANGENT_ALONG_PATH)), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //invalid caps
- RI_IF_ERROR(startSegment < 0 || numSegments <= 0 || RI_INT_ADDSATURATE(startSegment, numSegments) > p->getNumSegments(), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!isAligned(x,4) || !isAligned(y,4) || !isAligned(tangentX,4) || !isAligned(tangentY,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- try
- {
- Vector2 point, tangent;
- p->getPointAlong(startSegment, numSegments, distance, point, tangent); //throws bad_alloc
- if(x && y)
- {
- *x = point.x;
- *y = point.y;
- }
- if(tangentX && tangentY)
- {
- tangent.normalize();
- *tangentX = tangent.x;
- *tangentY = tangent.y;
- }
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgPathBounds(VGPath path, VGfloat * minx, VGfloat * miny, VGfloat * width, VGfloat * height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- RI_IF_ERROR(!(((Path*)path)->getCapabilities() & VG_PATH_CAPABILITY_PATH_BOUNDS), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //invalid caps
- RI_IF_ERROR(!minx || !miny || !width || !height, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!isAligned(minx,4) || !isAligned(miny,4) || !isAligned(width,4) || !isAligned(height,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- try
- {
- RIfloat pminx,pminy,pmaxx,pmaxy;
- ((Path*)path)->getPathBounds(pminx, pminy, pmaxx, pmaxy); //throws bad_alloc
- *minx = pminx;
- *miny = pminy;
- *width = pmaxx - pminx;
- *height = pmaxy - pminy;
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgPathTransformedBounds(VGPath path, VGfloat * minx, VGfloat * miny, VGfloat * width, VGfloat * height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- RI_IF_ERROR(!(((Path*)path)->getCapabilities() & VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //invalid caps
- RI_IF_ERROR(!minx || !miny || !width || !height, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!isAligned(minx,4) || !isAligned(miny,4) || !isAligned(width,4) || !isAligned(height,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- try
- {
- RIfloat pminx, pminy, pmaxx, pmaxy;
- ((Path*)path)->getPathTransformedBounds(context->m_pathUserToSurface, pminx, pminy, pmaxx, pmaxy); //throws bad_alloc
- *minx = pminx;
- *miny = pminy;
- *width = pmaxx - pminx;
- *height = pmaxy - pminy;
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGboolean RI_APIENTRY vgInterpolatePath(VGPath dstPath, VGPath startPath, VGPath endPath, VGfloat amount)
-{
- RI_GET_CONTEXT(VG_FALSE);
- RI_IF_ERROR(!context->isValidPath(dstPath) || !context->isValidPath(startPath) || !context->isValidPath(endPath), VG_BAD_HANDLE_ERROR, VG_FALSE); //invalid path handle
- RI_IF_ERROR(!(((Path*)dstPath)->getCapabilities() & VG_PATH_CAPABILITY_INTERPOLATE_TO) ||
- !(((Path*)startPath)->getCapabilities() & VG_PATH_CAPABILITY_INTERPOLATE_FROM) ||
- !(((Path*)endPath)->getCapabilities() & VG_PATH_CAPABILITY_INTERPOLATE_FROM), VG_PATH_CAPABILITY_ERROR, VG_FALSE); //invalid caps
- VGboolean ret = VG_FALSE;
- try
- {
- if(((Path*)dstPath)->interpolate((const Path*)startPath, (const Path*)endPath, inputFloat(amount))) //throws bad_alloc
- ret = VG_TRUE;
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(ret);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGPaint RI_APIENTRY vgCreatePaint(void)
-{
-// RI_GET_CONTEXT(VG_INVALID_HANDLE);
- OSAcquireMutex();
- VGContext* context = (VGContext*)eglvgGetCurrentVGContext();
- if(!context)
- {
- OSReleaseMutex();
- return VG_INVALID_HANDLE;
- }
- Paint* paint = NULL;
- try
- {
- paint = RI_NEW(Paint, ()); //throws bad_alloc
- RI_ASSERT(paint);
- context->m_paintManager->addResource(paint, context); //throws bad_alloc
- RI_RETURN((VGPaint)paint);
- }
- catch(std::bad_alloc)
- {
- RI_DELETE(paint);
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- RI_RETURN(VG_INVALID_HANDLE);
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgDestroyPaint(VGPaint paint)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPaint(paint), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid paint handle
-
- context->m_paintManager->removeResource((Paint*)paint);
-
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetPaint(VGPaint paint, VGbitfield paintModes)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(paint && !context->isValidPaint(paint), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid paint handle
- RI_IF_ERROR(!paintModes || paintModes & ~(VG_FILL_PATH | VG_STROKE_PATH), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid paint mode
-
- context->releasePaint(paintModes);
-
- if(paintModes & VG_FILL_PATH)
- {
- if(paint)
- ((Paint*)paint)->addReference();
- context->m_fillPaint = paint;
- }
- if(paintModes & VG_STROKE_PATH)
- {
- if(paint)
- ((Paint*)paint)->addReference();
- context->m_strokePaint = paint;
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetColor(VGPaint paint, VGuint rgba)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPaint(paint), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid paint handle
- Paint* p = (Paint*)paint;
- p->m_inputPaintColor.unpack(rgba, Color::formatToDescriptor(VG_sRGBA_8888));
- p->m_paintColor = inputColor(p->m_inputPaintColor);
- p->m_paintColor.clamp();
- p->m_paintColor.premultiply();
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGuint RI_APIENTRY vgGetColor(VGPaint paint)
-{
- RI_GET_CONTEXT(0);
- RI_IF_ERROR(!context->isValidPaint(paint), VG_BAD_HANDLE_ERROR, 0); //invalid paint handle
- unsigned int ret = ((Paint*)paint)->m_inputPaintColor.pack(Color::formatToDescriptor(VG_sRGBA_8888));
- RI_RETURN(ret);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGPaint RI_APIENTRY vgGetPaint(VGPaintMode paintMode)
-{
- RI_GET_CONTEXT(VG_INVALID_HANDLE);
- RI_IF_ERROR(paintMode != VG_FILL_PATH && paintMode != VG_STROKE_PATH, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE); //invalid paint mode
-
- if(paintMode == VG_FILL_PATH)
- {
- RI_RETURN(context->m_fillPaint);
- }
- RI_RETURN(context->m_strokePaint);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgPaintPattern(VGPaint paint, VGImage image)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidPaint(paint) || (image != VG_INVALID_HANDLE && !context->isValidImage(image)), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid handle
- Image* img = (Image*)image;
- Paint* pnt = (Paint*)paint;
- RI_IF_ERROR(image != VG_INVALID_HANDLE && eglvgIsInUse(img), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- Image* pattern = pnt->m_pattern;
- if(pattern)
- {
- pattern->removeInUse();
- if(!pattern->removeReference())
- RI_DELETE(pattern);
- }
- pnt->m_pattern = img;
- if(img)
- {
- img->addReference();
- img->addInUse();
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGImage RI_APIENTRY vgCreateImage(VGImageFormat format, VGint width, VGint height, VGbitfield allowedQuality)
-{
- RI_GET_CONTEXT(VG_INVALID_HANDLE);
- RI_IF_ERROR(!isValidImageFormat(format), VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, VG_INVALID_HANDLE);
- RI_IF_ERROR(width <= 0 || height <= 0 || !allowedQuality ||
- (allowedQuality & ~(VG_IMAGE_QUALITY_NONANTIALIASED | VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_BETTER)), VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
- RI_IF_ERROR(width > RI_MAX_IMAGE_WIDTH || height > RI_MAX_IMAGE_HEIGHT || width*height > RI_MAX_IMAGE_PIXELS ||
- ((width*Color::formatToDescriptor(format).bitsPerPixel+7)/8)*height > RI_MAX_IMAGE_BYTES, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
-
- Image* image = NULL;
- try
- {
- image = RI_NEW(Image, (Color::formatToDescriptor(format), width, height, allowedQuality)); //throws bad_alloc
- RI_ASSERT(image);
- context->m_imageManager->addResource(image, context); //throws bad_alloc
- RI_RETURN((VGImage)image);
- }
- catch(std::bad_alloc)
- {
- RI_DELETE(image);
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- RI_RETURN(VG_INVALID_HANDLE);
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgDestroyImage(VGImage image)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid image handle
-
- context->m_imageManager->removeResource((Image*)image);
-
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgClearImage(VGImage image, VGint x, VGint y, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- Image* img = (Image*)image;
- RI_IF_ERROR(eglvgIsInUse(img), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- img->clear(context->m_clearColor, x, y, width, height);
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgImageSubData(VGImage image, const void * data, VGint dataStride, VGImageFormat dataFormat, VGint x, VGint y, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- Image* img = (Image*)image;
- RI_IF_ERROR(eglvgIsInUse(img), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!isValidImageFormat(dataFormat), VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!data || !isAligned(data, dataFormat) || width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- {
- Image input(Color::formatToDescriptor(dataFormat), width, height, dataStride, const_cast<RIuint8*>((const RIuint8*)data));
- input.addReference();
- try
- {
- img->blit(input, 0, 0, x, y, width, height, false); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- }
- input.removeReference();
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgGetImageSubData(VGImage image, void * data, VGint dataStride, VGImageFormat dataFormat, VGint x, VGint y, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- Image* img = (Image*)image;
- RI_IF_ERROR(eglvgIsInUse(img), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!isValidImageFormat(dataFormat), VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!data || !isAligned(data, dataFormat) || width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- {
- Image output(Color::formatToDescriptor(dataFormat), width, height, dataStride, (RIuint8*)data);
- output.addReference();
- try
- {
- output.blit(*img, x, y, 0, 0, width, height, false); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- }
- output.removeReference();
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGImage RI_APIENTRY vgChildImage(VGImage parent, VGint x, VGint y, VGint width, VGint height)
-{
- RI_GET_CONTEXT(VG_INVALID_HANDLE);
- RI_IF_ERROR(!context->isValidImage(parent), VG_BAD_HANDLE_ERROR, VG_INVALID_HANDLE);
- Image* p = (Image*)parent;
- RI_IF_ERROR(eglvgIsInUse((Image*)parent), VG_IMAGE_IN_USE_ERROR, VG_INVALID_HANDLE);
- RI_IF_ERROR(x < 0 || x >= p->getWidth() || y < 0 || y >= p->getHeight() ||
- width <= 0 || height <= 0 || RI_INT_ADDSATURATE(x, width) > p->getWidth() || RI_INT_ADDSATURATE(y, height) > p->getHeight(), VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
-
- Image* child = NULL;
- try
- {
- child = RI_NEW(Image, (p, x, y, width, height)); //throws bad_alloc
- RI_ASSERT(child);
- context->m_imageManager->addResource(child, context); //throws bad_alloc
- RI_RETURN((VGImage)child);
- }
- catch(std::bad_alloc)
- {
- RI_DELETE(child);
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- RI_RETURN(VG_INVALID_HANDLE);
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGImage RI_APIENTRY vgGetParent(VGImage image)
-{
- RI_GET_CONTEXT(VG_INVALID_HANDLE);
- RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, VG_INVALID_HANDLE);
- VGImage ret = image; //if image has no ancestors, image is returned.
-
- //The vgGetParent function returns the closest valid ancestor (i.e., one that has not been the target of a vgDestroyImage call)
- // of the given image.
- Image* im = ((Image*)image)->getParent();
- for(;im;im = im->getParent())
- {
- if(context->isValidImage((VGImage)im))
- { //the parent is valid and alive
- ret = (VGImage)im;
- break;
- }
- }
- RI_RETURN(ret);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgCopyImage(VGImage dst, VGint dx, VGint dy, VGImage src, VGint sx, VGint sy, VGint width, VGint height, VGboolean dither)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(eglvgIsInUse((Image*)dst) || eglvgIsInUse((Image*)src), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- try
- {
- ((Image*)dst)->blit(*(Image*)src, sx, sy, dx, dy, width, height, dither ? true : false); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-static bool drawImage(VGContext* context, VGImage image, const Matrix3x3& userToSurfaceMatrix)
-{
- Drawable* drawable = context->getCurrentDrawable();
- if(!drawable)
- return false; //no EGL surface is current at the moment
-
- Image* img = (Image*)image;
- //transform image corners into the surface space
- Vector3 p0(0, 0, 1);
- Vector3 p1(0, (RIfloat)img->getHeight(), 1);
- Vector3 p2((RIfloat)img->getWidth(), (RIfloat)img->getHeight(), 1);
- Vector3 p3((RIfloat)img->getWidth(), 0, 1);
- p0 = userToSurfaceMatrix * p0;
- p1 = userToSurfaceMatrix * p1;
- p2 = userToSurfaceMatrix * p2;
- p3 = userToSurfaceMatrix * p3;
- if(p0.z <= 0.0f || p1.z <= 0.0f || p2.z <= 0.0f || p3.z <= 0.0f)
- return false;
-
- //projection
- p0 *= 1.0f/p0.z;
- p1 *= 1.0f/p1.z;
- p2 *= 1.0f/p2.z;
- p3 *= 1.0f/p3.z;
-
- Rasterizer rasterizer;
- if(context->m_scissoring)
- rasterizer.setScissor(context->m_scissor); //throws bad_alloc
- rasterizer.setupSamplingPattern(context->m_renderingQuality, drawable->getNumSamples());
-
- PixelPipe pixelPipe;
- pixelPipe.setTileFillColor(context->m_tileFillColor);
- pixelPipe.setPaint((Paint*)context->m_fillPaint);
- pixelPipe.setImageQuality(context->m_imageQuality);
- pixelPipe.setBlendMode(context->m_blendMode);
- pixelPipe.setDrawable(drawable);
- pixelPipe.setMask(context->m_masking ? true : false);
- pixelPipe.setColorTransform(context->m_colorTransform ? true : false, context->m_colorTransformValues);
-
- Matrix3x3 surfaceToImageMatrix = userToSurfaceMatrix;
- Matrix3x3 surfaceToPaintMatrix = userToSurfaceMatrix * context->m_fillPaintToUser;
- if(surfaceToImageMatrix.invert() && surfaceToPaintMatrix.invert())
- {
- VGImageMode imode = context->m_imageMode;
- if(!surfaceToPaintMatrix.isAffine())
- imode = VG_DRAW_IMAGE_NORMAL; //if paint matrix is not affine, always use normal image mode
- surfaceToPaintMatrix[2].set(0,0,1); //force affine
-
- pixelPipe.setImage(img, imode);
- pixelPipe.setSurfaceToPaintMatrix(surfaceToPaintMatrix);
- pixelPipe.setSurfaceToImageMatrix(surfaceToImageMatrix);
-
- rasterizer.addEdge(Vector2(p0.x,p0.y), Vector2(p1.x,p1.y)); //throws bad_alloc
- rasterizer.addEdge(Vector2(p1.x,p1.y), Vector2(p2.x,p2.y)); //throws bad_alloc
- rasterizer.addEdge(Vector2(p2.x,p2.y), Vector2(p3.x,p3.y)); //throws bad_alloc
- rasterizer.addEdge(Vector2(p3.x,p3.y), Vector2(p0.x,p0.y)); //throws bad_alloc
- rasterizer.setup(0, 0, drawable->getWidth(), drawable->getHeight(), VG_EVEN_ODD, &pixelPipe, NULL);
- rasterizer.fill(); //throws bad_alloc
- }
- return true;
-}
-
-void RI_APIENTRY vgDrawImage(VGImage image)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- Image* img = (Image*)image;
- RI_IF_ERROR(eglvgIsInUse(img), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
-
- try
- {
- if(!drawImage(context, image, context->m_imageUserToSurface))
- {
- RI_RETURN(RI_NO_RETVAL);
- }
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetPixels(VGint dx, VGint dy, VGImage src, VGint sx, VGint sy, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(eglvgIsInUse((Image*)src), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Drawable* drawable = context->getCurrentDrawable();
- if(!drawable)
- {
- RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
- }
- try
- {
- if(context->m_scissoring)
- drawable->getColorBuffer()->blit(*(Image*)src, sx, sy, dx, dy, width, height, context->m_scissor); //throws bad_alloc
- else
- drawable->getColorBuffer()->blit(*(Image*)src, sx, sy, dx, dy, width, height); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgWritePixels(const void * data, VGint dataStride, VGImageFormat dataFormat, VGint dx, VGint dy, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!isValidImageFormat(dataFormat), VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!data || !isAligned(data, dataFormat) || width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Drawable* drawable = context->getCurrentDrawable();
- if(!drawable)
- {
- RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
- }
- {
- Image input(Color::formatToDescriptor(dataFormat), width, height, dataStride, const_cast<RIuint8*>((const RIuint8*)data));
- input.addReference();
- try
- {
- if(context->m_scissoring)
- drawable->getColorBuffer()->blit(input, 0, 0, dx, dy, width, height, context->m_scissor); //throws bad_alloc
- else
- drawable->getColorBuffer()->blit(input, 0, 0, dx, dy, width, height); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- }
- input.removeReference();
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgGetPixels(VGImage dst, VGint dx, VGint dy, VGint sx, VGint sy, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(dst), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(eglvgIsInUse((Image*)dst), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Drawable* drawable = context->getCurrentDrawable();
- if(!drawable)
- {
- RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
- }
- try
- {
- ((Image*)dst)->blit(drawable->getColorBuffer(), sx, sy, dx, dy, width, height); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgReadPixels(void* data, VGint dataStride, VGImageFormat dataFormat, VGint sx, VGint sy, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!isValidImageFormat(dataFormat), VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!data || !isAligned(data, dataFormat) || width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Drawable* drawable = context->getCurrentDrawable();
- if(!drawable)
- {
- RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
- }
- {
- Image output(Color::formatToDescriptor(dataFormat), width, height, dataStride, (RIuint8*)data);
- output.addReference();
- try
- {
- output.blit(drawable->getColorBuffer(), sx, sy, 0, 0, width, height); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- }
- output.removeReference();
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgCopyPixels(VGint dx, VGint dy, VGint sx, VGint sy, VGint width, VGint height)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Drawable* drawable = context->getCurrentDrawable();
- if(!drawable)
- {
- RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
- }
- try
- {
- if(context->m_scissoring)
- drawable->getColorBuffer()->blit(drawable->getColorBuffer(), sx, sy, dx, dy, width, height, context->m_scissor); //throws bad_alloc
- else
- drawable->getColorBuffer()->blit(drawable->getColorBuffer(), sx, sy, dx, dy, width, height); //throws bad_alloc
- }
- catch(std::bad_alloc)
- {
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgColorMatrix(VGImage dst, VGImage src, const VGfloat * matrix)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- Image* d = (Image*)dst;
- Image* s = (Image*)src;
- RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!matrix || !isAligned(matrix,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
-
- RIfloat m[20];
- for(int i=0;i<20;i++)
- {
- m[i] = inputFloat(matrix[i]);
- }
- try
- {
- d->colorMatrix(*s, m, context->m_filterFormatLinear ? true : false, context->m_filterFormatPremultiplied ? true : false, channelMask);
- }
- catch(std::bad_alloc)
- {
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgConvolve(VGImage dst, VGImage src, VGint kernelWidth, VGint kernelHeight, VGint shiftX, VGint shiftY, const VGshort * kernel, VGfloat scale, VGfloat bias, VGTilingMode tilingMode)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- Image* d = (Image*)dst;
- Image* s = (Image*)src;
- RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!kernel || !isAligned(kernel,2) || kernelWidth <= 0 || kernelHeight <= 0 || kernelWidth > RI_MAX_KERNEL_SIZE || kernelHeight > RI_MAX_KERNEL_SIZE, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(tilingMode < VG_TILE_FILL || tilingMode > VG_TILE_REFLECT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
- try
- {
- d->convolve(*s, kernelWidth, kernelHeight, shiftX, shiftY, (const RIint16*)kernel, inputFloat(scale), inputFloat(bias), tilingMode, context->m_tileFillColor, context->m_filterFormatLinear ? true : false, context->m_filterFormatPremultiplied ? true : false, channelMask);
- }
- catch(std::bad_alloc)
- {
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSeparableConvolve(VGImage dst, VGImage src, VGint kernelWidth, VGint kernelHeight, VGint shiftX, VGint shiftY, const VGshort * kernelX, const VGshort * kernelY, VGfloat scale, VGfloat bias, VGTilingMode tilingMode)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- Image* d = (Image*)dst;
- Image* s = (Image*)src;
- RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!kernelX || !kernelY || !isAligned(kernelX,2) || !isAligned(kernelY,2) || kernelWidth <= 0 || kernelHeight <= 0 || kernelWidth > RI_MAX_SEPARABLE_KERNEL_SIZE || kernelHeight > RI_MAX_SEPARABLE_KERNEL_SIZE, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(tilingMode < VG_TILE_FILL || tilingMode > VG_TILE_REFLECT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
- try
- {
- d->separableConvolve(*s, kernelWidth, kernelHeight, shiftX, shiftY, (const RIint16*)kernelX, (const RIint16*)kernelY,
- inputFloat(scale), inputFloat(bias), tilingMode, context->m_tileFillColor, context->m_filterFormatLinear ? true : false,
- context->m_filterFormatPremultiplied ? true : false, channelMask);
- }
- catch(std::bad_alloc)
- {
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgGaussianBlur(VGImage dst, VGImage src, VGfloat stdDeviationX, VGfloat stdDeviationY, VGTilingMode tilingMode)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- Image* d = (Image*)dst;
- Image* s = (Image*)src;
- RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RIfloat sx = inputFloat(stdDeviationX);
- RIfloat sy = inputFloat(stdDeviationY);
- RI_IF_ERROR(sx <= 0.0f || sy <= 0.0f || sx > (RIfloat)RI_MAX_GAUSSIAN_STD_DEVIATION || sy > (RIfloat)RI_MAX_GAUSSIAN_STD_DEVIATION, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(tilingMode < VG_TILE_FILL || tilingMode > VG_TILE_REFLECT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
- try
- {
- d->gaussianBlur(*s, sx, sy, tilingMode, context->m_tileFillColor, context->m_filterFormatLinear ? true : false,
- context->m_filterFormatPremultiplied ? true : false, channelMask);
- }
- catch(std::bad_alloc)
- {
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgLookup(VGImage dst, VGImage src, const VGubyte * redLUT, const VGubyte * greenLUT, const VGubyte * blueLUT, const VGubyte * alphaLUT, VGboolean outputLinear, VGboolean outputPremultiplied)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- Image* d = (Image*)dst;
- Image* s = (Image*)src;
- RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!redLUT || !greenLUT || !blueLUT || !alphaLUT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
- try
- {
- d->lookup(*s, (const RIuint8*)redLUT, (const RIuint8*)greenLUT, (const RIuint8*)blueLUT, (const RIuint8*)alphaLUT,
- outputLinear ? true : false, outputPremultiplied ? true : false, context->m_filterFormatLinear ? true : false,
- context->m_filterFormatPremultiplied ? true : false, channelMask);
- }
- catch(std::bad_alloc)
- {
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgLookupSingle(VGImage dst, VGImage src, const VGuint * lookupTable, VGImageChannel sourceChannel, VGboolean outputLinear, VGboolean outputPremultiplied)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
- Image* d = (Image*)dst;
- Image* s = (Image*)src;
- RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(!lookupTable || !isAligned(lookupTable,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- const Color::Descriptor& desc = s->getDescriptor();
- RI_ASSERT(Color::isValidDescriptor(desc));
- //give an error if src is in rgb format and the source channel is not valid
- RI_IF_ERROR((!desc.isLuminance() && !desc.isAlphaOnly()) && (sourceChannel != VG_RED && sourceChannel != VG_GREEN && sourceChannel != VG_BLUE && sourceChannel != VG_ALPHA), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
- try
- {
- d->lookupSingle(*s, (const RIuint32*)lookupTable, sourceChannel, outputLinear ? true : false, outputPremultiplied ? true : false,
- context->m_filterFormatLinear ? true : false, context->m_filterFormatPremultiplied ? true : false, channelMask);
- }
- catch(std::bad_alloc)
- {
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGHardwareQueryResult RI_APIENTRY vgHardwareQuery(VGHardwareQueryType key, VGint setting)
-{
- RI_GET_CONTEXT(VG_HARDWARE_UNACCELERATED);
- RI_IF_ERROR(key != VG_IMAGE_FORMAT_QUERY && key != VG_PATH_DATATYPE_QUERY, VG_ILLEGAL_ARGUMENT_ERROR, VG_HARDWARE_UNACCELERATED);
- RI_IF_ERROR(key == VG_IMAGE_FORMAT_QUERY && !isValidImageFormat(setting), VG_ILLEGAL_ARGUMENT_ERROR, VG_HARDWARE_UNACCELERATED);
- RI_IF_ERROR(key == VG_PATH_DATATYPE_QUERY && (setting < VG_PATH_DATATYPE_S_8 || setting > VG_PATH_DATATYPE_F), VG_ILLEGAL_ARGUMENT_ERROR, VG_HARDWARE_UNACCELERATED);
- RI_RETURN(VG_HARDWARE_UNACCELERATED);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-const VGubyte * RI_APIENTRY vgGetString(VGStringID name)
-{
- static const VGubyte vendor[] = "Khronos Group";
- static const VGubyte renderer[] = {"OpenVG 1.1 Reference Implementation May 13 2008"};
- static const VGubyte version[] = "1.1";
- static const VGubyte extensions[] = "";
- const VGubyte* r = NULL;
- RI_GET_CONTEXT(NULL);
- switch(name)
- {
- case VG_VENDOR:
- r = vendor;
- break;
- case VG_RENDERER:
- r = renderer;
- break;
- case VG_VERSION:
- r = version;
- break;
- case VG_EXTENSIONS:
- r = extensions;
- break;
- default:
- break;
- }
- RI_RETURN(r);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-VGFont RI_APIENTRY vgCreateFont(VGint glyphCapacityHint)
-{
- RI_GET_CONTEXT(VG_INVALID_HANDLE);
- RI_IF_ERROR(glyphCapacityHint < 0, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
-
- Font* font = NULL;
- try
- {
- font = RI_NEW(Font, (glyphCapacityHint)); //throws bad_alloc
- RI_ASSERT(font);
- context->m_fontManager->addResource(font, context); //throws bad_alloc
- RI_RETURN((VGFont)font);
- }
- catch(std::bad_alloc)
- {
- RI_DELETE(font);
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- RI_RETURN(VG_INVALID_HANDLE);
- }
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgDestroyFont(VGFont font)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
-
- context->m_fontManager->removeResource((Font*)font);
-
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetGlyphToPath(VGFont font, VGuint glyphIndex, VGPath path, VGboolean isHinted, VGfloat glyphOrigin[2], VGfloat escapement[2])
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
- RI_IF_ERROR(path != VG_INVALID_HANDLE && !context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
- RI_IF_ERROR(!glyphOrigin || !escapement || !isAligned(glyphOrigin,sizeof(VGfloat)) || !isAligned(escapement,sizeof(VGfloat)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Font* f = (Font*)font;
-
- try
- {
- f->setGlyphToPath(glyphIndex, path, isHinted ? true : false, Vector2(inputFloat(glyphOrigin[0]), inputFloat(glyphOrigin[1])), Vector2(inputFloat(escapement[0]), inputFloat(escapement[1])));
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgSetGlyphToImage(VGFont font, VGuint glyphIndex, VGImage image, VGfloat glyphOrigin[2], VGfloat escapement[2])
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
- if(image != VG_INVALID_HANDLE)
- {
- RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid image handle
- RI_IF_ERROR(eglvgIsInUse((Image*)image), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL); //image in use
- }
- RI_IF_ERROR(!glyphOrigin || !escapement || !isAligned(glyphOrigin,sizeof(VGfloat)) || !isAligned(escapement,sizeof(VGfloat)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- Font* f = (Font*)font;
-
- try
- {
- f->setGlyphToImage(glyphIndex, image, Vector2(inputFloat(glyphOrigin[0]), inputFloat(glyphOrigin[1])), Vector2(inputFloat(escapement[0]), inputFloat(escapement[1])));
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgClearGlyph(VGFont font, VGuint glyphIndex)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
- Font* f = (Font*)font;
- Font::Glyph* g = f->findGlyph(glyphIndex);
- RI_IF_ERROR(!g, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //glyphIndex not defined
-
- f->clearGlyph(g);
-
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgDrawGlyph(VGFont font, VGuint glyphIndex, VGbitfield paintModes, VGboolean allowAutoHinting)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
- RI_IF_ERROR(paintModes & ~(VG_FILL_PATH | VG_STROKE_PATH), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid paint mode
- Font* f = (Font*)font;
- Font::Glyph* g = f->findGlyph(glyphIndex);
- RI_IF_ERROR(!g, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //glyphIndex not defined
- RI_UNREF(allowAutoHinting); //RI doesn't implement autohinting
-
- try
- {
- if(paintModes)
- {
- Matrix3x3 userToSurfaceMatrix = context->m_glyphUserToSurface;
- Vector2 t = context->m_glyphOrigin - g->m_origin;
- Matrix3x3 n(1, 0, t.x,
- 0, 1, t.y,
- 0, 0, 1 );
- userToSurfaceMatrix *= n;
- userToSurfaceMatrix[2].set(0,0,1); //force affinity
-
- bool ret = true;
- if(g->m_image != VG_INVALID_HANDLE)
- ret = drawImage(context, g->m_image, userToSurfaceMatrix);
- else if(g->m_path != VG_INVALID_HANDLE)
- ret = drawPath(context, g->m_path, userToSurfaceMatrix, paintModes);
- if(!ret)
- {
- RI_RETURN(RI_NO_RETVAL);
- }
- }
-
- context->m_glyphOrigin += g->m_escapement;
- context->m_inputGlyphOrigin = context->m_glyphOrigin;
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
-
- RI_RETURN(RI_NO_RETVAL);
-}
-
-/*-------------------------------------------------------------------*//*!
-* \brief
-* \param
-* \return
-* \note
-*//*-------------------------------------------------------------------*/
-
-void RI_APIENTRY vgDrawGlyphs(VGFont font, VGint glyphCount, VGuint *glyphIndices, VGfloat *adjustments_x, VGfloat *adjustments_y, VGbitfield paintModes, VGboolean allowAutoHinting)
-{
- RI_GET_CONTEXT(RI_NO_RETVAL);
- RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
- RI_IF_ERROR(!glyphIndices || !isAligned(glyphIndices, sizeof(VGuint)) || glyphCount <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR((adjustments_x && !isAligned(adjustments_x, sizeof(VGfloat))) || (adjustments_y && !isAligned(adjustments_y, sizeof(VGfloat))), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
- RI_IF_ERROR(paintModes & ~(VG_FILL_PATH | VG_STROKE_PATH), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid paint mode
- Font* f = (Font*)font;
- for(int i=0;i<glyphCount;i++)
- {
- Font::Glyph* g = f->findGlyph(glyphIndices[i]);
- RI_IF_ERROR(!g, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //glyphIndex not defined
- }
- RI_UNREF(allowAutoHinting); //RI doesn't implement autohinting
-
- try
- {
- for(int i=0;i<glyphCount;i++)
- {
- Font::Glyph* g = f->findGlyph(glyphIndices[i]);
-
- if(paintModes)
- {
- Matrix3x3 userToSurfaceMatrix = context->m_glyphUserToSurface;
- Vector2 t = context->m_glyphOrigin - g->m_origin;
- Matrix3x3 n(1, 0, t.x,
- 0, 1, t.y,
- 0, 0, 1 );
- userToSurfaceMatrix *= n;
- userToSurfaceMatrix[2].set(0,0,1); //force affinity
-
- bool ret = true;
- if(g->m_image != VG_INVALID_HANDLE)
- ret = drawImage(context, g->m_image, userToSurfaceMatrix);
- else if(g->m_path != VG_INVALID_HANDLE)
- ret = drawPath(context, g->m_path, userToSurfaceMatrix, paintModes);
- if(!ret)
- {
- RI_RETURN(RI_NO_RETVAL);
- }
- }
-
- context->m_glyphOrigin += g->m_escapement;
- if(adjustments_x)
- context->m_glyphOrigin.x += inputFloat(adjustments_x[i]);
- if(adjustments_y)
- context->m_glyphOrigin.y += inputFloat(adjustments_y[i]);
- context->m_inputGlyphOrigin = context->m_glyphOrigin;
- }
- }
- catch(std::bad_alloc)
- {
- context->setError(VG_OUT_OF_MEMORY_ERROR);
- }
-
- RI_RETURN(RI_NO_RETVAL);
-}
+
+#include "VG/openvg.h"
+#include "EGL/egl.h"
+#include "Context.h"
+#include "Rasterizer.h"
+#include "PixelPipe.h"
+#include "Path.h"
+#include <stdio.h>
+
+namespace tgOpenVG {
+
+void* eglvgGetCurrentVGContext(void);
+
+#define RI_NO_RETVAL
+#define RI_IF_ERROR(COND, ERRORCODE, RETVAL) \
+ if(COND) { context->setError(ERRORCODE); return RETVAL; }
+
+
+static int inputFloatToInt(VGfloat value)
+{
+ double v = (double)floor(value);
+ v = v > (double)RI_INT32_MAX ? (double)RI_INT32_MAX : v;
+ v = v < (double)RI_INT32_MIN ? (double)RI_INT32_MIN : v;
+ return (int)v;
+}
+
+static int paramToInt(const void* values, bool floats, int count, int i)
+{
+ RI_ASSERT(i >= 0);
+ if(i >= count || !values)
+ return 0;
+ if(floats)
+ return inputFloatToInt(((const VGfloat*)values)[i]);
+ return (int)((const VGint*)values)[i];
+}
+
+static RIfloat paramToFloat(const void* values, bool floats, int count, int i)
+{
+ RI_ASSERT(i >= 0);
+ if(i >= count || !values)
+ return 0.0f;
+ if(floats)
+ return ((const VGfloat*)values)[i];
+ return (RIfloat)((const VGint*)values)[i];
+}
+
+static void floatToParam(void* output, bool outputFloats, int count, int i, VGfloat value)
+{
+ RI_ASSERT(i >= 0);
+ RI_ASSERT(output);
+ if(i >= count)
+ return;
+ if(outputFloats)
+ ((VGfloat*)output)[i] = value;
+ else
+ ((VGint*)output)[i] = (VGint)inputFloatToInt(value);
+}
+
+static void intToParam(void* output, bool outputFloats, int count, int i, VGint value)
+{
+ RI_ASSERT(i >= 0);
+ RI_ASSERT(output);
+ if(i >= count)
+ return;
+ if(outputFloats)
+ ((VGfloat*)output)[i] = (VGfloat)value;
+ else
+ ((VGint*)output)[i] = value;
+}
+
+RIfloat inputFloat(VGfloat f)
+{
+ //this function is used for all floating point input values
+ if(RI_ISNAN(f)) return 0.0f; //convert NaN to zero
+ return RI_CLAMP(f, -RI_FLOAT_MAX, RI_FLOAT_MAX); //clamp +-inf to +-RIfloat max
+}
+
+Vector2 inputVector2(const Vector2& v)
+{
+ return Vector2(inputFloat(v.x), inputFloat(v.y));
+}
+
+Color inputColor(const Color& c)
+{
+ Color r = c;
+ r.r = inputFloat(r.r);
+ r.g = inputFloat(r.g);
+ r.b = inputFloat(r.b);
+ r.a = inputFloat(r.a);
+ return r;
+}
+
+bool isValidImageFormat(int f)
+{
+ if(f < VG_sRGBX_8888 || f > VG_lABGR_8888_PRE)
+ return false;
+ return true;
+}
+
+static bool isAligned(const void* ptr, int alignment)
+{
+ RI_ASSERT(alignment == 1 || alignment == 2 || alignment == 4);
+ if(((unsigned long)ptr) & (alignment-1))
+ return false;
+ return true;
+}
+
+static bool isAligned(const void* ptr, VGImageFormat format)
+{
+ RI_ASSERT(isValidImageFormat(format));
+ int alignment = Color::formatToDescriptor(format).bitsPerPixel >> 3;
+ if(alignment <= 1)
+ return true; //one bit or byte per pixel
+ return isAligned(ptr, alignment);
+}
+
+} /* Namespace tgOpenVG */
+
+/**************************************************************************
+ * Helper Functions
+ */
+
+using namespace tgOpenVG;
+
+static void getFontParameterifv(VGContext* context, Font* font, VGFontParamType type, VGint count, void* values, bool floats)
+{
+ switch(type)
+ {
+ case VG_FONT_NUM_GLYPHS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, font->getNumGlyphs());
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+static void getImageParameterifv(VGContext* context, Image* image, VGImageParamType type, VGint count, void* values, bool floats)
+{
+ switch(type)
+ {
+ case VG_IMAGE_FORMAT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ RI_ASSERT(isValidImageFormat(image->getDescriptor().format));
+ intToParam(values, floats, count, 0, image->getDescriptor().format);
+ break;
+
+ case VG_IMAGE_WIDTH:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, image->getWidth());
+ break;
+
+ case VG_IMAGE_HEIGHT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, image->getHeight());
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+static void getPathParameterifv(VGContext* context, Path* path, VGPathParamType type, VGint count, void* values, bool floats)
+{
+ switch(type)
+ {
+ case VG_PATH_FORMAT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, path->getFormat());
+ break;
+
+ case VG_PATH_DATATYPE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, path->getDatatype());
+ break;
+
+ case VG_PATH_SCALE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, path->getScale());
+ break;
+
+ case VG_PATH_BIAS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, path->getBias());
+ break;
+
+ case VG_PATH_NUM_SEGMENTS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, path->getNumSegments());
+ break;
+
+ case VG_PATH_NUM_COORDS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, path->getNumCoordinates());
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+static void getPaintParameterifv(VGContext* context, Paint* paint, VGPaintParamType type, VGint count, void* values, bool floats)
+{
+ switch(type)
+ {
+ case VG_PAINT_TYPE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, paint->m_paintType);
+ break;
+
+ case VG_PAINT_COLOR:
+ if(count > 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, paint->m_inputPaintColor.r);
+ floatToParam(values, floats, count, 1, paint->m_inputPaintColor.g);
+ floatToParam(values, floats, count, 2, paint->m_inputPaintColor.b);
+ floatToParam(values, floats, count, 3, paint->m_inputPaintColor.a);
+ break;
+
+ case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, paint->m_colorRampSpreadMode);
+ break;
+
+ case VG_PAINT_COLOR_RAMP_STOPS:
+ {
+ if(count > paint->m_inputColorRampStops.size()*5) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ int j = 0;
+ for(int i=0;i<paint->m_inputColorRampStops.size();i++)
+ {
+ floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].offset);
+ floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.r);
+ floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.g);
+ floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.b);
+ floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.a);
+ }
+ break;
+ }
+
+ case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, paint->m_colorRampPremultiplied);
+ break;
+
+ case VG_PAINT_LINEAR_GRADIENT:
+ if(count > 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, paint->m_inputLinearGradientPoint0.x);
+ floatToParam(values, floats, count, 1, paint->m_inputLinearGradientPoint0.y); floatToParam(values, floats, count, 2, paint->m_inputLinearGradientPoint1.x);
+ floatToParam(values, floats, count, 3, paint->m_inputLinearGradientPoint1.y);
+ break;
+
+ case VG_PAINT_RADIAL_GRADIENT:
+ if(count > 5) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, paint->m_inputRadialGradientCenter.x);
+ floatToParam(values, floats, count, 1, paint->m_inputRadialGradientCenter.y);
+ floatToParam(values, floats, count, 2, paint->m_inputRadialGradientFocalPoint.x);
+ floatToParam(values, floats, count, 3, paint->m_inputRadialGradientFocalPoint.y);
+ floatToParam(values, floats, count, 4, paint->m_inputRadialGradientRadius);
+ break;
+
+ case VG_PAINT_PATTERN_TILING_MODE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, paint->m_patternTilingMode);
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+
+static void setifv(VGContext* context, VGParamType type, VGint count, const void* values, bool floats)
+{
+ RI_ASSERT(context);
+ RI_ASSERT(!count || (count && values));
+
+ int ivalue = paramToInt(values, floats, count, 0);
+ float fvalue = paramToFloat(values, floats, count, 0);
+
+ switch(type) {
+ case VG_MATRIX_MODE:
+ if(count != 1 || ivalue < VG_MATRIX_PATH_USER_TO_SURFACE || ivalue > VG_MATRIX_GLYPH_USER_TO_SURFACE) {
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR);
+ return;
+ }
+ context->m_matrixMode = (VGMatrixMode)ivalue;
+ break;
+
+ case VG_FILL_RULE:
+ if(count != 1 || ivalue < VG_EVEN_ODD || ivalue > VG_NON_ZERO) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_fillRule = (VGFillRule)ivalue;
+ break;
+
+ case VG_IMAGE_QUALITY:
+ if(count != 1 || ivalue < VG_IMAGE_QUALITY_NONANTIALIASED || ivalue > VG_IMAGE_QUALITY_BETTER) {
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR);
+ return;
+ }
+ context->m_imageQuality = (VGImageQuality)ivalue;
+ break;
+
+ case VG_RENDERING_QUALITY:
+ if(count != 1 || ivalue < VG_RENDERING_QUALITY_NONANTIALIASED || ivalue > VG_RENDERING_QUALITY_BETTER) {
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR);
+ return;
+ }
+ context->m_renderingQuality = (VGRenderingQuality)ivalue;
+ break;
+
+ case VG_BLEND_MODE:
+ if(count != 1 || ivalue < VG_BLEND_SRC || ivalue > VG_BLEND_ADDITIVE) {
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR);
+ return;
+ }
+ context->m_blendMode = (VGBlendMode)ivalue;
+ break;
+
+ case VG_IMAGE_MODE:
+ if(count != 1 || ivalue < VG_DRAW_IMAGE_NORMAL || ivalue > VG_DRAW_IMAGE_STENCIL) {
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR);
+ return;
+ }
+ context->m_imageMode = (VGImageMode)ivalue;
+ break;
+
+ case VG_SCISSOR_RECTS:
+ {
+ if(count & 3) {
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR);
+ return;
+ } //count must be a multiple of four
+ try {
+ Array<Rectangle> scissor;
+ for(int i=0;i<RI_INT_MIN(count, RI_MAX_SCISSOR_RECTANGLES*4);i+=4) {
+ Rectangle s;
+ s.x = paramToInt(values, floats, count, i+0);
+ s.y = paramToInt(values, floats, count, i+1);
+ s.width = paramToInt(values, floats, count, i+2);
+ s.height = paramToInt(values, floats, count, i+3);
+ scissor.push_back(s); //throws bad_alloc
+ }
+ context->m_scissor.swap(scissor); //replace context data
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ break;
+ }
+
+ case VG_COLOR_TRANSFORM:
+ if(count != 1) {
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR);
+ return;
+ }
+ context->m_colorTransform = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_COLOR_TRANSFORM_VALUES:
+ if(count != 8 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ for(int i=0;i<8;i++) {
+ context->m_inputColorTransformValues[i] = paramToFloat(values, floats, count, i);
+ context->m_colorTransformValues[i] = inputFloat(context->m_inputColorTransformValues[i]);
+ }
+ break;
+
+ case VG_STROKE_LINE_WIDTH:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputStrokeLineWidth = fvalue;
+ context->m_strokeLineWidth = inputFloat(fvalue);
+ break;
+
+ case VG_STROKE_CAP_STYLE:
+ if(count != 1 || ivalue < VG_CAP_BUTT || ivalue > VG_CAP_SQUARE) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_strokeCapStyle = (VGCapStyle)ivalue;
+ break;
+
+ case VG_STROKE_JOIN_STYLE:
+ if(count != 1 || ivalue < VG_JOIN_MITER || ivalue > VG_JOIN_BEVEL) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_strokeJoinStyle = (VGJoinStyle)ivalue;
+ break;
+
+ case VG_STROKE_MITER_LIMIT:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputStrokeMiterLimit = fvalue;
+ context->m_strokeMiterLimit = inputFloat(fvalue);
+ break;
+
+ case VG_STROKE_DASH_PATTERN:
+ {
+ try {
+ Array<RIfloat> inputStrokeDashPattern;
+ Array<RIfloat> strokeDashPattern;
+ for(int i=0;i<RI_INT_MIN(count, RI_MAX_DASH_COUNT);i++) {
+ RIfloat v = paramToFloat(values, floats, count, i);
+ inputStrokeDashPattern.push_back(v); //throws bad_alloc
+ strokeDashPattern.push_back(inputFloat(v)); //throws bad_alloc
+ }
+ context->m_inputStrokeDashPattern.swap(inputStrokeDashPattern); //replace context data
+ context->m_strokeDashPattern.swap(strokeDashPattern); //replace context data
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ break;
+ }
+
+ case VG_STROKE_DASH_PHASE:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputStrokeDashPhase = fvalue;
+ context->m_strokeDashPhase = inputFloat(fvalue);
+ break;
+
+ case VG_STROKE_DASH_PHASE_RESET:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_strokeDashPhaseReset = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_TILE_FILL_COLOR:
+ if(count != 4 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputTileFillColor.set(paramToFloat(values, floats, count, 0),
+ paramToFloat(values, floats, count, 1),
+ paramToFloat(values, floats, count, 2),
+ paramToFloat(values, floats, count, 3),
+ Color::sRGBA);
+ context->m_tileFillColor = inputColor(context->m_inputTileFillColor);
+ break;
+
+ case VG_GLYPH_ORIGIN:
+ if(count != 2 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputGlyphOrigin.x = paramToFloat(values, floats, count, 0);
+ context->m_inputGlyphOrigin.y = paramToFloat(values, floats, count, 1);
+ context->m_glyphOrigin = inputVector2(context->m_inputGlyphOrigin);
+ break;
+
+ case VG_CLEAR_COLOR:
+ if(count != 4 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputClearColor.set(paramToFloat(values, floats, count, 0),
+ paramToFloat(values, floats, count, 1),
+ paramToFloat(values, floats, count, 2),
+ paramToFloat(values, floats, count, 3),
+ Color::sRGBA);
+ context->m_clearColor = inputColor(context->m_inputClearColor);
+ break;
+
+ case VG_MASKING:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_masking = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_SCISSORING:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_scissoring = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_PIXEL_LAYOUT:
+ if(count != 1 || ivalue < VG_PIXEL_LAYOUT_UNKNOWN || ivalue > VG_PIXEL_LAYOUT_BGR_HORIZONTAL) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_pixelLayout = (VGPixelLayout)ivalue;
+ break;
+
+ case VG_SCREEN_LAYOUT:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ break; //setting read-only values has no effect
+
+ case VG_FILTER_FORMAT_LINEAR:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_filterFormatLinear = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_FILTER_FORMAT_PREMULTIPLIED:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_filterFormatPremultiplied = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_FILTER_CHANNEL_MASK:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ //undefined bits are ignored
+ context->m_filterChannelMask = (VGbitfield)ivalue;
+ break;
+
+ case VG_MAX_SCISSOR_RECTS:
+ case VG_MAX_DASH_COUNT:
+ case VG_MAX_KERNEL_SIZE:
+ case VG_MAX_SEPARABLE_KERNEL_SIZE:
+ case VG_MAX_COLOR_RAMP_STOPS:
+ case VG_MAX_IMAGE_WIDTH:
+ case VG_MAX_IMAGE_HEIGHT:
+ case VG_MAX_IMAGE_PIXELS:
+ case VG_MAX_IMAGE_BYTES:
+ case VG_MAX_FLOAT:
+ case VG_MAX_GAUSSIAN_STD_DEVIATION:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ break; //setting read-only values has no effect
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+// OpenVG API
+// vgAppendPathData *
+// vgClear
+// vgGetError
+// vgGetParameterf *
+// vgGetParameteri *
+// vgSetfv
+
+void RI_APIENTRY vgAppendPathData(VGPath dstPath, VGint numSegments, const VGubyte * pathSegments, const void * pathData)
+{
+ VGContext* context = (VGContext*)eglvgGetCurrentVGContext();
+ if(!context) {
+ return;
+ }
+ RI_IF_ERROR(!context->isValidPath(dstPath), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+
+ Path* p = (Path*)dstPath;
+ RI_IF_ERROR(!(p->getCapabilities() & VG_PATH_CAPABILITY_APPEND_TO), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //no append cap
+ RI_IF_ERROR(numSegments <= 0 || !pathSegments || !pathData, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //no segments or data
+ RI_IF_ERROR((p->getDatatype() == VG_PATH_DATATYPE_S_16 && !isAligned(pathData,2)) ||
+ ((p->getDatatype() == VG_PATH_DATATYPE_S_32 || p->getDatatype() == VG_PATH_DATATYPE_F) && !isAligned(pathData,4)),
+ VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid alignment
+ for(int i=0;i<numSegments;i++) {
+ VGPathSegment c = (VGPathSegment)(pathSegments[i] & 0x1e);
+ RI_IF_ERROR(c < VG_CLOSE_PATH || c > VG_LCWARC_TO, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid segment
+ RI_IF_ERROR(c & ~0x1f, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //reserved bits are nonzero
+ }
+
+ try {
+ p->appendData((const RIuint8*)pathSegments, numSegments, (const RIuint8*)pathData); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+}
+
+void RI_APIENTRY vgClear(VGint x, VGint y, VGint width, VGint height)
+{
+ VGContext* context = (VGContext*)eglvgGetCurrentVGContext();
+ if(!context) {
+ return;
+ }
+ RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Drawable* drawable = context->getCurrentDrawable();
+ if(!drawable) {
+ return; //no EGL surface is current at the moment
+ }
+
+ try {
+ if(context->m_scissoring)
+ drawable->getColorBuffer()->clear(context->m_clearColor, x, y, width, height, context->m_scissor); //throws bad_alloc
+ else
+ drawable->getColorBuffer()->clear(context->m_clearColor, x, y, width, height);
+ }
+ catch(std::bad_alloc) {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ return;
+}
+
+
+VGErrorCode RI_APIENTRY vgGetError(void)
+{
+ VGContext* context = (VGContext*)eglvgGetCurrentVGContext();
+ if(!context) {
+ return VG_NO_CONTEXT_ERROR;
+ }
+ VGErrorCode error = context->m_error;
+ context->m_error = VG_NO_ERROR;
+ return error;
+}
+
+VGfloat RI_APIENTRY vgGetParameterf(VGHandle object, VGint paramType)
+{
+ VGContext* context = (VGContext*)eglvgGetCurrentVGContext();
+ if(!context) {
+ return 0.0;
+ }
+ RI_IF_ERROR(paramType == VG_PAINT_COLOR || paramType == VG_PAINT_COLOR_RAMP_STOPS || paramType == VG_PAINT_LINEAR_GRADIENT ||
+ paramType == VG_PAINT_RADIAL_GRADIENT, VG_ILLEGAL_ARGUMENT_ERROR, 0.0f); //vector valued parameter
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, 0.0f); //invalid object handle
+ VGfloat ret = 0.0f;
+ if(isImage) {
+ RI_ASSERT(!isPath && !isPaint && !isFont);
+ getImageParameterifv(context, (Image*)object, (VGImageParamType)paramType, 1, &ret, true);
+ }
+ else if(isPath) {
+ RI_ASSERT(!isImage && !isPaint && !isFont);
+ getPathParameterifv(context, (Path*)object, (VGPathParamType)paramType, 1, &ret, true);
+ }
+ else if(isPaint) {
+ RI_ASSERT(!isImage && !isPath && !isFont);
+ getPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, 1, &ret, true);
+ }
+ else {
+ RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
+ getFontParameterifv(context, (Font*)object, (VGFontParamType)paramType, 1, &ret, true);
+ }
+ return ret;
+}
+
+VGint RI_APIENTRY vgGetParameteri(VGHandle object, VGint paramType)
+{
+ VGContext* context = (VGContext*)eglvgGetCurrentVGContext();
+ if(!context) {
+ return 0.0;
+ }
+ RI_IF_ERROR(paramType == VG_PAINT_COLOR || paramType == VG_PAINT_COLOR_RAMP_STOPS || paramType == VG_PAINT_LINEAR_GRADIENT ||
+ paramType == VG_PAINT_RADIAL_GRADIENT, VG_ILLEGAL_ARGUMENT_ERROR, 0); //vector valued parameter
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, 0); //invalid object handle
+ VGint ret = 0;
+ if(isImage) {
+ RI_ASSERT(!isPath && !isPaint && !isFont);
+ getImageParameterifv(context, (Image*)object, (VGImageParamType)paramType, 1, &ret, false);
+ }
+ else if(isPath) {
+ RI_ASSERT(!isImage && !isPaint && !isFont);
+ getPathParameterifv(context, (Path*)object, (VGPathParamType)paramType, 1, &ret, false);
+ }
+ else if(isPaint) {
+ RI_ASSERT(!isImage && !isPath && !isFont);
+ getPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, 1, &ret, false);
+ }
+ else {
+ RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
+ getFontParameterifv(context, (Font*)object, (VGFontParamType)paramType, 1, &ret, false);
+ }
+ return ret;
+}
+
+void RI_APIENTRY vgSetfv(VGParamType type, VGint count, const VGfloat * values)
+{
+ VGContext* context = (VGContext*)eglvgGetCurrentVGContext();
+ if(!context) {
+ return;
+ }
+ RI_IF_ERROR(count < 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR((!values && count > 0) || (values && !isAligned(values,4)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ setifv(context, type, count, values, true);
+ return;
+}
diff --git a/src/vg/Api.cpp.orig b/src/vg/Api.cpp.orig
new file mode 100644
index 0000000..10dcc0d
--- /dev/null
+++ b/src/vg/Api.cpp.orig
@@ -0,0 +1,3679 @@
+/*------------------------------------------------------------------------
+ *
+ * OpenVG 1.1 Reference Implementation
+ * -----------------------------------
+ *
+ * Copyright (c) 2007 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and /or associated documentation files
+ * (the "Materials "), to deal in the Materials without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Materials,
+ * and to permit persons to whom the Materials are furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//**
+ * \file
+ * \brief Implementations of OpenVG API functions.
+ * \note The actual processing is done in Path, Image, Rasterizer and PixelPipe classes.
+ *//*-------------------------------------------------------------------*/
+
+#include "VG/openvg.h"
+#include "EGL/egl.h"
+#include "Context.h"
+#include "Rasterizer.h"
+#include "PixelPipe.h"
+#include "Path.h"
+#include <stdio.h>
+
+//==============================================================================================
+
+namespace tgOpenVG
+{
+
+/* EGL&OS functions for use in an OpenVG implementation */
+void* eglvgGetCurrentVGContext(void);
+bool eglvgIsInUse(void* image);
+void OSAcquireMutex(void);
+void OSReleaseMutex(void);
+
+
+#define RI_NO_RETVAL
+
+//this must be the first line in an API function
+#define RI_GET_CONTEXT(RETVAL) \
+ OSAcquireMutex(); \
+ VGContext* context = (VGContext*)eglvgGetCurrentVGContext(); \
+ if(!context) \
+ { \
+ OSReleaseMutex(); \
+ return RETVAL;\
+ }
+
+#define RI_IF_ERROR(COND, ERRORCODE, RETVAL) \
+ if(COND) { context->setError(ERRORCODE); OSReleaseMutex(); return RETVAL; }
+
+//all API functions must call this as their last operation (also functions that don't return values)
+//NOTE: don't evaluate anything or read state in RETVAL (it'll be executed after the mutex has been released)
+#define RI_RETURN(RETVAL) \
+ { OSReleaseMutex(); \
+ return RETVAL; }
+
+static bool isAligned(const void* ptr, int alignment)
+{
+ RI_ASSERT(alignment == 1 || alignment == 2 || alignment == 4);
+ if(((RIuintptr)ptr) & (alignment-1))
+ return false;
+ return true;
+}
+
+static bool isAligned(const void* ptr, VGImageFormat format)
+{
+ RI_ASSERT(isValidImageFormat(format));
+ int alignment = Color::formatToDescriptor(format).bitsPerPixel >> 3;
+ if(alignment <= 1)
+ return true; //one bit or byte per pixel
+ return isAligned(ptr, alignment);
+}
+
+bool isValidImageFormat(int f)
+{
+ if(f < VG_sRGBX_8888 || f > VG_lABGR_8888_PRE)
+ return false;
+ return true;
+}
+
+} //namespace OpenVGRI
+
+using namespace tgOpenVG;
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgFlush(void)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ //the RI doesn't cache anything, so this is a no-op
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgFinish(void)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ //the RI doesn't cache anything, so this is a no-op
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGErrorCode RI_APIENTRY vgGetError(void)
+{
+ RI_GET_CONTEXT(VG_NO_CONTEXT_ERROR);
+ VGErrorCode error = context->m_error;
+ context->m_error = VG_NO_ERROR;
+ RI_RETURN(error);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+namespace tgOpenVG
+{
+
+RIfloat inputFloat(VGfloat f)
+{
+ //this function is used for all floating point input values
+ if(RI_ISNAN(f)) return 0.0f; //convert NaN to zero
+ return RI_CLAMP(f, -RI_FLOAT_MAX, RI_FLOAT_MAX); //clamp +-inf to +-RIfloat max
+}
+
+Vector2 inputVector2(const Vector2& v)
+{
+ return Vector2(inputFloat(v.x), inputFloat(v.y));
+}
+
+Color inputColor(const Color& c)
+{
+ Color r = c;
+ r.r = inputFloat(r.r);
+ r.g = inputFloat(r.g);
+ r.b = inputFloat(r.b);
+ r.a = inputFloat(r.a);
+ return r;
+}
+
+static int inputFloatToInt(VGfloat value)
+{
+ double v = (double)floor(value);
+ v = v > (double)RI_INT32_MAX ? (double)RI_INT32_MAX : v;
+ v = v < (double)RI_INT32_MIN ? (double)RI_INT32_MIN : v;
+ return (int)v;
+}
+
+static int paramToInt(const void* values, bool floats, int count, int i)
+{
+ RI_ASSERT(i >= 0);
+ if(i >= count || !values)
+ return 0;
+ if(floats)
+ return inputFloatToInt(((const VGfloat*)values)[i]);
+ return (int)((const VGint*)values)[i];
+}
+
+static RIfloat paramToFloat(const void* values, bool floats, int count, int i)
+{
+ RI_ASSERT(i >= 0);
+ if(i >= count || !values)
+ return 0.0f;
+ if(floats)
+ return ((const VGfloat*)values)[i];
+ return (RIfloat)((const VGint*)values)[i];
+}
+
+static void floatToParam(void* output, bool outputFloats, int count, int i, VGfloat value)
+{
+ RI_ASSERT(i >= 0);
+ RI_ASSERT(output);
+ if(i >= count)
+ return;
+ if(outputFloats)
+ ((VGfloat*)output)[i] = value;
+ else
+ ((VGint*)output)[i] = (VGint)inputFloatToInt(value);
+}
+
+static void intToParam(void* output, bool outputFloats, int count, int i, VGint value)
+{
+ RI_ASSERT(i >= 0);
+ RI_ASSERT(output);
+ if(i >= count)
+ return;
+ if(outputFloats)
+ ((VGfloat*)output)[i] = (VGfloat)value;
+ else
+ ((VGint*)output)[i] = value;
+}
+
+} //namespace OpenVGRI
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static void setifv(VGContext* context, VGParamType type, VGint count, const void* values, bool floats)
+{
+ RI_ASSERT(context);
+ RI_ASSERT(!count || (count && values));
+
+ int ivalue = paramToInt(values, floats, count, 0);
+ RIfloat fvalue = paramToFloat(values, floats, count, 0);
+
+ switch(type)
+ {
+ case VG_MATRIX_MODE:
+ if(count != 1 || ivalue < VG_MATRIX_PATH_USER_TO_SURFACE || ivalue > VG_MATRIX_GLYPH_USER_TO_SURFACE) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_matrixMode = (VGMatrixMode)ivalue;
+ break;
+
+ case VG_FILL_RULE:
+ if(count != 1 || ivalue < VG_EVEN_ODD || ivalue > VG_NON_ZERO) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_fillRule = (VGFillRule)ivalue;
+ break;
+
+ case VG_IMAGE_QUALITY:
+ if(count != 1 || ivalue < VG_IMAGE_QUALITY_NONANTIALIASED || ivalue > VG_IMAGE_QUALITY_BETTER) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_imageQuality = (VGImageQuality)ivalue;
+ break;
+
+ case VG_RENDERING_QUALITY:
+ if(count != 1 || ivalue < VG_RENDERING_QUALITY_NONANTIALIASED || ivalue > VG_RENDERING_QUALITY_BETTER) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_renderingQuality = (VGRenderingQuality)ivalue;
+ break;
+
+ case VG_BLEND_MODE:
+ if(count != 1 || ivalue < VG_BLEND_SRC || ivalue > VG_BLEND_ADDITIVE) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_blendMode = (VGBlendMode)ivalue;
+ break;
+
+ case VG_IMAGE_MODE:
+ if(count != 1 || ivalue < VG_DRAW_IMAGE_NORMAL || ivalue > VG_DRAW_IMAGE_STENCIL) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_imageMode = (VGImageMode)ivalue;
+ break;
+
+ case VG_SCISSOR_RECTS:
+ {
+ if(count & 3) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; } //count must be a multiple of four
+ try
+ {
+ Array<Rectangle> scissor;
+ for(int i=0;i<RI_INT_MIN(count, RI_MAX_SCISSOR_RECTANGLES*4);i+=4)
+ {
+ Rectangle s;
+ s.x = paramToInt(values, floats, count, i+0);
+ s.y = paramToInt(values, floats, count, i+1);
+ s.width = paramToInt(values, floats, count, i+2);
+ s.height = paramToInt(values, floats, count, i+3);
+ scissor.push_back(s); //throws bad_alloc
+ }
+ context->m_scissor.swap(scissor); //replace context data
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ break;
+ }
+
+ case VG_COLOR_TRANSFORM:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_colorTransform = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_COLOR_TRANSFORM_VALUES:
+ if(count != 8 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ {
+ for(int i=0;i<8;i++)
+ {
+ context->m_inputColorTransformValues[i] = paramToFloat(values, floats, count, i);
+ context->m_colorTransformValues[i] = inputFloat(context->m_inputColorTransformValues[i]);
+ }
+ }
+ break;
+
+ case VG_STROKE_LINE_WIDTH:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputStrokeLineWidth = fvalue;
+ context->m_strokeLineWidth = inputFloat(fvalue);
+ break;
+
+ case VG_STROKE_CAP_STYLE:
+ if(count != 1 || ivalue < VG_CAP_BUTT || ivalue > VG_CAP_SQUARE) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_strokeCapStyle = (VGCapStyle)ivalue;
+ break;
+
+ case VG_STROKE_JOIN_STYLE:
+ if(count != 1 || ivalue < VG_JOIN_MITER || ivalue > VG_JOIN_BEVEL) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_strokeJoinStyle = (VGJoinStyle)ivalue;
+ break;
+
+ case VG_STROKE_MITER_LIMIT:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputStrokeMiterLimit = fvalue;
+ context->m_strokeMiterLimit = inputFloat(fvalue);
+ break;
+
+ case VG_STROKE_DASH_PATTERN:
+ {
+ try
+ {
+ Array<RIfloat> inputStrokeDashPattern;
+ Array<RIfloat> strokeDashPattern;
+ for(int i=0;i<RI_INT_MIN(count, RI_MAX_DASH_COUNT);i++)
+ {
+ RIfloat v = paramToFloat(values, floats, count, i);
+ inputStrokeDashPattern.push_back(v); //throws bad_alloc
+ strokeDashPattern.push_back(inputFloat(v)); //throws bad_alloc
+ }
+ context->m_inputStrokeDashPattern.swap(inputStrokeDashPattern); //replace context data
+ context->m_strokeDashPattern.swap(strokeDashPattern); //replace context data
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ break;
+ }
+
+ case VG_STROKE_DASH_PHASE:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputStrokeDashPhase = fvalue;
+ context->m_strokeDashPhase = inputFloat(fvalue);
+ break;
+
+ case VG_STROKE_DASH_PHASE_RESET:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_strokeDashPhaseReset = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_TILE_FILL_COLOR:
+ if(count != 4 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputTileFillColor.set(paramToFloat(values, floats, count, 0),
+ paramToFloat(values, floats, count, 1),
+ paramToFloat(values, floats, count, 2),
+ paramToFloat(values, floats, count, 3),
+ Color::sRGBA);
+ context->m_tileFillColor = inputColor(context->m_inputTileFillColor);
+ break;
+
+ case VG_GLYPH_ORIGIN:
+ if(count != 2 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputGlyphOrigin.x = paramToFloat(values, floats, count, 0);
+ context->m_inputGlyphOrigin.y = paramToFloat(values, floats, count, 1);
+ context->m_glyphOrigin = inputVector2(context->m_inputGlyphOrigin);
+ break;
+
+ case VG_CLEAR_COLOR:
+ if(count != 4 || !values) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_inputClearColor.set(paramToFloat(values, floats, count, 0),
+ paramToFloat(values, floats, count, 1),
+ paramToFloat(values, floats, count, 2),
+ paramToFloat(values, floats, count, 3),
+ Color::sRGBA);
+ context->m_clearColor = inputColor(context->m_inputClearColor);
+ break;
+
+ case VG_MASKING:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_masking = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_SCISSORING:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_scissoring = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_PIXEL_LAYOUT:
+ if(count != 1 || ivalue < VG_PIXEL_LAYOUT_UNKNOWN || ivalue > VG_PIXEL_LAYOUT_BGR_HORIZONTAL) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_pixelLayout = (VGPixelLayout)ivalue;
+ break;
+
+ case VG_SCREEN_LAYOUT:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ break; //setting read-only values has no effect
+
+ case VG_FILTER_FORMAT_LINEAR:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_filterFormatLinear = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_FILTER_FORMAT_PREMULTIPLIED:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ context->m_filterFormatPremultiplied = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_FILTER_CHANNEL_MASK:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ //undefined bits are ignored
+ context->m_filterChannelMask = (VGbitfield)ivalue;
+ break;
+
+ case VG_MAX_SCISSOR_RECTS:
+ case VG_MAX_DASH_COUNT:
+ case VG_MAX_KERNEL_SIZE:
+ case VG_MAX_SEPARABLE_KERNEL_SIZE:
+ case VG_MAX_COLOR_RAMP_STOPS:
+ case VG_MAX_IMAGE_WIDTH:
+ case VG_MAX_IMAGE_HEIGHT:
+ case VG_MAX_IMAGE_PIXELS:
+ case VG_MAX_IMAGE_BYTES:
+ case VG_MAX_FLOAT:
+ case VG_MAX_GAUSSIAN_STD_DEVIATION:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ break; //setting read-only values has no effect
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetf(VGParamType type, VGfloat value)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(type == VG_SCISSOR_RECTS || type == VG_STROKE_DASH_PATTERN || type == VG_TILE_FILL_COLOR ||
+ type == VG_CLEAR_COLOR, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //vector type value
+ VGfloat values[1] = {value};
+ setifv(context, type, 1, values, true);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSeti(VGParamType type, VGint value)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(type == VG_SCISSOR_RECTS || type == VG_STROKE_DASH_PATTERN || type == VG_TILE_FILL_COLOR ||
+ type == VG_CLEAR_COLOR, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //vector type value
+ VGint values[1] = {value};
+ setifv(context, type, 1, values, false);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetiv(VGParamType type, VGint count, const VGint * values)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(count < 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR((!values && count > 0) || (values && !isAligned(values,4)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ setifv(context, type, count, values, false);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetfv(VGParamType type, VGint count, const VGfloat * values)
+{
+ OSAcquireMutex();
+ VGContext* context = (VGContext*)eglvgGetCurrentVGContext();
+ if(!context)
+ {
+ OSReleaseMutex();
+ return RI_NO_RETVAL;
+ }
+// RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(count < 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR((!values && count > 0) || (values && !isAligned(values,4)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ setifv(context, type, count, values, true);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static void getifv(VGContext* context, VGParamType type, VGint count, void* values, bool floats)
+{
+ switch(type)
+ {
+ case VG_MATRIX_MODE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_matrixMode);
+ break;
+
+ case VG_FILL_RULE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_fillRule);
+ break;
+
+ case VG_IMAGE_QUALITY:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_imageQuality);
+ break;
+
+ case VG_RENDERING_QUALITY:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_renderingQuality);
+ break;
+
+ case VG_BLEND_MODE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_blendMode);
+ break;
+
+ case VG_IMAGE_MODE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_imageMode);
+ break;
+
+ case VG_SCISSOR_RECTS:
+ {
+ if(count > context->m_scissor.size()*4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ for(int i=0;i<context->m_scissor.size();i++)
+ {
+ intToParam(values, floats, count, i*4+0, context->m_scissor[i].x);
+ intToParam(values, floats, count, i*4+1, context->m_scissor[i].y);
+ intToParam(values, floats, count, i*4+2, context->m_scissor[i].width);
+ intToParam(values, floats, count, i*4+3, context->m_scissor[i].height);
+ }
+ break;
+ }
+
+ case VG_COLOR_TRANSFORM:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_colorTransform);
+ break;
+
+ case VG_COLOR_TRANSFORM_VALUES:
+ if(count > 8) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ {
+ for(int i=0;i<count;i++)
+ {
+ floatToParam(values, floats, count, i, context->m_inputColorTransformValues[i]);
+ }
+ }
+ break;
+
+ case VG_STROKE_LINE_WIDTH:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, context->m_inputStrokeLineWidth);
+ break;
+
+ case VG_STROKE_CAP_STYLE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_strokeCapStyle);
+ break;
+
+ case VG_STROKE_JOIN_STYLE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_strokeJoinStyle);
+ break;
+
+ case VG_STROKE_MITER_LIMIT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, context->m_inputStrokeMiterLimit);
+ break;
+
+ case VG_STROKE_DASH_PATTERN:
+ {
+ if(count > context->m_inputStrokeDashPattern.size()) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ for(int i=0;i<context->m_inputStrokeDashPattern.size();i++)
+ floatToParam(values, floats, count, i, context->m_inputStrokeDashPattern[i]);
+ break;
+ }
+
+ case VG_STROKE_DASH_PHASE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, context->m_inputStrokeDashPhase);
+ break;
+
+ case VG_STROKE_DASH_PHASE_RESET:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_strokeDashPhaseReset);
+ break;
+
+ case VG_TILE_FILL_COLOR:
+ if(count > 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, context->m_inputTileFillColor.r);
+ floatToParam(values, floats, count, 1, context->m_inputTileFillColor.g);
+ floatToParam(values, floats, count, 2, context->m_inputTileFillColor.b);
+ floatToParam(values, floats, count, 3, context->m_inputTileFillColor.a);
+ break;
+
+ case VG_CLEAR_COLOR:
+ if(count > 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, context->m_inputClearColor.r);
+ floatToParam(values, floats, count, 1, context->m_inputClearColor.g);
+ floatToParam(values, floats, count, 2, context->m_inputClearColor.b);
+ floatToParam(values, floats, count, 3, context->m_inputClearColor.a);
+ break;
+
+ case VG_GLYPH_ORIGIN:
+ if(count > 2) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, context->m_inputGlyphOrigin.x);
+ floatToParam(values, floats, count, 1, context->m_inputGlyphOrigin.y);
+ break;
+
+ case VG_MASKING:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_masking);
+ break;
+
+ case VG_SCISSORING:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_scissoring);
+ break;
+
+ case VG_PIXEL_LAYOUT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_pixelLayout);
+ break;
+
+ case VG_SCREEN_LAYOUT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, VG_PIXEL_LAYOUT_UNKNOWN);
+ break;
+
+ case VG_FILTER_FORMAT_LINEAR:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_filterFormatLinear);
+ break;
+
+ case VG_FILTER_FORMAT_PREMULTIPLIED:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_filterFormatPremultiplied);
+ break;
+
+ case VG_FILTER_CHANNEL_MASK:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, context->m_filterChannelMask);
+ break;
+
+ case VG_MAX_SCISSOR_RECTS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, RI_MAX_SCISSOR_RECTANGLES);
+ break;
+
+ case VG_MAX_DASH_COUNT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, RI_MAX_DASH_COUNT);
+ break;
+
+ case VG_MAX_KERNEL_SIZE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, RI_MAX_KERNEL_SIZE);
+ break;
+
+ case VG_MAX_SEPARABLE_KERNEL_SIZE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, RI_MAX_SEPARABLE_KERNEL_SIZE);
+ break;
+
+ case VG_MAX_COLOR_RAMP_STOPS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, RI_MAX_COLOR_RAMP_STOPS);
+ break;
+
+ case VG_MAX_IMAGE_WIDTH:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, RI_MAX_IMAGE_WIDTH);
+ break;
+
+ case VG_MAX_IMAGE_HEIGHT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, RI_MAX_IMAGE_HEIGHT);
+ break;
+
+ case VG_MAX_IMAGE_PIXELS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, RI_MAX_IMAGE_PIXELS);
+ break;
+
+ case VG_MAX_IMAGE_BYTES:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, RI_MAX_IMAGE_BYTES);
+ break;
+
+ case VG_MAX_FLOAT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, RI_FLOAT_MAX);
+ break;
+
+ case VG_MAX_GAUSSIAN_STD_DEVIATION:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, RI_MAX_GAUSSIAN_STD_DEVIATION);
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGfloat RI_APIENTRY vgGetf(VGParamType type)
+{
+ RI_GET_CONTEXT(0.0f);
+ RI_IF_ERROR(type == VG_SCISSOR_RECTS || type == VG_STROKE_DASH_PATTERN || type == VG_TILE_FILL_COLOR ||
+ type == VG_CLEAR_COLOR, VG_ILLEGAL_ARGUMENT_ERROR, 0.0f); //vector type value
+ RIfloat ret = 0.0f;
+ getifv(context, type, 1, &ret, true);
+ RI_RETURN(ret);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGint RI_APIENTRY vgGeti(VGParamType type)
+{
+ RI_GET_CONTEXT(0);
+ RI_IF_ERROR(type == VG_SCISSOR_RECTS || type == VG_STROKE_DASH_PATTERN || type == VG_TILE_FILL_COLOR ||
+ type == VG_CLEAR_COLOR, VG_ILLEGAL_ARGUMENT_ERROR, 0); //vector type value
+ VGint ret = 0;
+ getifv(context, type, 1, &ret, false);
+ RI_RETURN(ret);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgGetiv(VGParamType type, VGint count, VGint * values)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(count <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!values || !isAligned(values,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ getifv(context, type, count, values, false);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgGetfv(VGParamType type, VGint count, VGfloat * values)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(count <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!values || !isAligned(values,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ getifv(context, type, count, values, true);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGint RI_APIENTRY vgGetVectorSize(VGParamType type)
+{
+ RI_GET_CONTEXT(0);
+ VGint ret = 0;
+ switch(type)
+ {
+ case VG_MATRIX_MODE:
+ case VG_FILL_RULE:
+ case VG_IMAGE_QUALITY:
+ case VG_RENDERING_QUALITY:
+ case VG_BLEND_MODE:
+ case VG_IMAGE_MODE:
+ ret = 1;
+ break;
+
+ case VG_SCISSOR_RECTS:
+ ret = 4*context->m_scissor.size();
+ break;
+
+ case VG_COLOR_TRANSFORM:
+ ret = 1;
+ break;
+
+ case VG_COLOR_TRANSFORM_VALUES:
+ ret = 8;
+ break;
+
+ case VG_STROKE_LINE_WIDTH:
+ case VG_STROKE_CAP_STYLE:
+ case VG_STROKE_JOIN_STYLE:
+ case VG_STROKE_MITER_LIMIT:
+ ret = 1;
+ break;
+
+ case VG_STROKE_DASH_PATTERN:
+ ret = context->m_inputStrokeDashPattern.size();
+ break;
+
+ case VG_STROKE_DASH_PHASE:
+ case VG_STROKE_DASH_PHASE_RESET:
+ ret = 1;
+ break;
+
+ case VG_TILE_FILL_COLOR:
+ case VG_CLEAR_COLOR:
+ ret = 4;
+ break;
+
+ case VG_GLYPH_ORIGIN:
+ ret = 2;
+ break;
+
+ case VG_MASKING:
+ case VG_SCISSORING:
+ case VG_PIXEL_LAYOUT:
+ case VG_SCREEN_LAYOUT:
+ case VG_FILTER_FORMAT_LINEAR:
+ case VG_FILTER_FORMAT_PREMULTIPLIED:
+ case VG_FILTER_CHANNEL_MASK:
+ case VG_MAX_SCISSOR_RECTS:
+ case VG_MAX_DASH_COUNT:
+ case VG_MAX_KERNEL_SIZE:
+ case VG_MAX_SEPARABLE_KERNEL_SIZE:
+ case VG_MAX_COLOR_RAMP_STOPS:
+ case VG_MAX_IMAGE_WIDTH:
+ case VG_MAX_IMAGE_HEIGHT:
+ case VG_MAX_IMAGE_PIXELS:
+ case VG_MAX_IMAGE_BYTES:
+ case VG_MAX_FLOAT:
+ case VG_MAX_GAUSSIAN_STD_DEVIATION:
+ ret = 1;
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+ RI_RETURN(ret);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static void setPaintParameterifv(VGContext* context, Paint* paint, VGPaintParamType paramType, VGint count, const void* values, bool floats)
+{
+ RI_ASSERT(context);
+ RI_ASSERT(paint);
+
+ int ivalue = paramToInt(values, floats, count, 0);
+
+ switch(paramType)
+ {
+ case VG_PAINT_TYPE:
+ if(count != 1 || ivalue < VG_PAINT_TYPE_COLOR || ivalue > VG_PAINT_TYPE_PATTERN) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ paint->m_paintType = (VGPaintType)ivalue;
+ break;
+
+ case VG_PAINT_COLOR:
+ if(count != 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ paint->m_inputPaintColor.set(paramToFloat(values, floats, count, 0),
+ paramToFloat(values, floats, count, 1),
+ paramToFloat(values, floats, count, 2),
+ paramToFloat(values, floats, count, 3),
+ Color::sRGBA);
+ paint->m_paintColor = inputColor(paint->m_inputPaintColor);
+ paint->m_paintColor.clamp();
+ paint->m_paintColor.premultiply();
+ break;
+
+ case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+ if(count != 1 || ivalue < VG_COLOR_RAMP_SPREAD_PAD || ivalue > VG_COLOR_RAMP_SPREAD_REFLECT) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ paint->m_colorRampSpreadMode = (VGColorRampSpreadMode)ivalue;
+ break;
+
+ case VG_PAINT_COLOR_RAMP_STOPS:
+ {
+ int numStops = count/5;
+ if(count != numStops*5) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; } //count must be a multiple of five
+ try
+ {
+ Array<Paint::GradientStop> colorRampStops;
+ Array<Paint::GradientStop> inputColorRampStops;
+ RIfloat prevOffset = -RI_FLOAT_MAX;
+ bool valid = true;
+ for(int i=0;i<RI_INT_MIN(numStops, RI_MAX_COLOR_RAMP_STOPS);i++) //NOTE: ignores the final stop if there is not enough parameters
+ {
+ Paint::GradientStop gs;
+ gs.offset = paramToFloat(values, floats, count, i*5);
+ gs.color.set(paramToFloat(values, floats, count, i*5+1),
+ paramToFloat(values, floats, count, i*5+2),
+ paramToFloat(values, floats, count, i*5+3),
+ paramToFloat(values, floats, count, i*5+4),
+ Color::sRGBA);
+ inputColorRampStops.push_back(gs);
+
+ if(gs.offset < prevOffset)
+ valid = false; //decreasing sequence, ignore it
+
+ if(gs.offset >= 0.0f && gs.offset <= 1.0f)
+ {
+ gs.color.clamp();
+
+ if(!colorRampStops.size() && gs.offset > 0.0f)
+ { //the first valid stop is not at 0, replicate the first one
+ RIfloat tmp = gs.offset;
+ gs.offset = 0.0f;
+ colorRampStops.push_back(gs); //throws bad_alloc
+ gs.offset = tmp;
+ }
+ colorRampStops.push_back(gs); //throws bad_alloc
+ }
+ prevOffset = gs.offset;
+ }
+ if(valid && colorRampStops.size() && colorRampStops[colorRampStops.size()-1].offset < 1.0f)
+ { //there is at least one stop, but the last one is not at 1, replicate the last one
+ Paint::GradientStop gs = colorRampStops[colorRampStops.size()-1];
+ gs.offset = 1.0f;
+ colorRampStops.push_back(gs); //throws bad_alloc
+ }
+ if(!valid || !colorRampStops.size())
+ { //there are no valid stops, add implicit stops
+ colorRampStops.clear();
+ Paint::GradientStop gs;
+ gs.offset = 0.0f;
+ gs.color.set(0,0,0,1,Color::sRGBA);
+ colorRampStops.push_back(gs); //throws bad_alloc
+ gs.offset = 1.0f;
+ gs.color.set(1,1,1,1,Color::sRGBA);
+ colorRampStops.push_back(gs); //throws bad_alloc
+ }
+ RI_ASSERT(colorRampStops.size() >= 2 && colorRampStops.size() <= RI_MAX_COLOR_RAMP_STOPS);
+ paint->m_colorRampStops.swap(colorRampStops); //set paint array
+ paint->m_inputColorRampStops.swap(inputColorRampStops); //set paint array
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ break;
+ }
+
+ case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
+ if(count != 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ paint->m_colorRampPremultiplied = ivalue ? VG_TRUE : VG_FALSE;
+ break;
+
+ case VG_PAINT_LINEAR_GRADIENT:
+ if(count != 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ paint->m_inputLinearGradientPoint0.set(paramToFloat(values, floats, count, 0),
+ paramToFloat(values, floats, count, 1));
+ paint->m_inputLinearGradientPoint1.set(paramToFloat(values, floats, count, 2),
+ paramToFloat(values, floats, count, 3));
+ paint->m_linearGradientPoint0 = inputVector2(paint->m_inputLinearGradientPoint0);
+ paint->m_linearGradientPoint1 = inputVector2(paint->m_inputLinearGradientPoint1);
+ break;
+
+ case VG_PAINT_RADIAL_GRADIENT:
+ if(count != 5) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ paint->m_inputRadialGradientCenter.set(paramToFloat(values, floats, count, 0),
+ paramToFloat(values, floats, count, 1));
+ paint->m_inputRadialGradientFocalPoint.set(paramToFloat(values, floats, count, 2),
+ paramToFloat(values, floats, count, 3));
+ paint->m_inputRadialGradientRadius = paramToFloat(values, floats, count, 4);
+ paint->m_radialGradientCenter = inputVector2(paint->m_inputRadialGradientCenter);
+ paint->m_radialGradientFocalPoint = inputVector2(paint->m_inputRadialGradientFocalPoint);
+ paint->m_radialGradientRadius = inputFloat(paint->m_inputRadialGradientRadius);
+ break;
+
+ case VG_PAINT_PATTERN_TILING_MODE:
+ if(count != 1 || ivalue < VG_TILE_FILL || ivalue > VG_TILE_REFLECT) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ paint->m_patternTilingMode = (VGTilingMode)ivalue;
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetParameterf(VGHandle object, VGint paramType, VGfloat value)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isMaskLayer = context->isValidMaskLayer(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isMaskLayer && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
+ RI_IF_ERROR(paramType == VG_PAINT_COLOR || paramType == VG_PAINT_COLOR_RAMP_STOPS || paramType == VG_PAINT_LINEAR_GRADIENT ||
+ paramType == VG_PAINT_RADIAL_GRADIENT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //vector valued parameter
+ VGfloat values[1] = {value};
+ if(isImage)
+ { //read only, the function does nothing
+ RI_ASSERT(!isPath && !isPaint && !isMaskLayer && !isFont);
+ if(paramType < VG_IMAGE_FORMAT || paramType > VG_IMAGE_HEIGHT)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else if(isPath)
+ { //read only, the function does nothing
+ RI_ASSERT(!isImage && !isPaint && !isMaskLayer && !isFont);
+ if(paramType < VG_PATH_FORMAT || paramType > VG_PATH_NUM_COORDS)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else if(isPaint)
+ {
+ RI_ASSERT(!isImage && !isPath && !isMaskLayer && !isFont);
+ setPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, 1, values, true);
+ }
+ else if(isMaskLayer)
+ {
+ RI_ASSERT(!isImage && !isPath && !isPaint && !isFont);
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else
+ { //read only, the function does nothing
+ RI_ASSERT(!isImage && !isPath && !isPaint && !isMaskLayer && isFont);
+ if (paramType != VG_FONT_NUM_GLYPHS)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetParameteri(VGHandle object, VGint paramType, VGint value)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isMaskLayer = context->isValidMaskLayer(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isMaskLayer && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
+ RI_IF_ERROR(paramType == VG_PAINT_COLOR || paramType == VG_PAINT_COLOR_RAMP_STOPS || paramType == VG_PAINT_LINEAR_GRADIENT ||
+ paramType == VG_PAINT_RADIAL_GRADIENT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //vector valued parameter
+ VGint values[1] = {value};
+ if(isImage)
+ { //read only, the function does nothing
+ RI_ASSERT(!isPath && !isPaint && !isMaskLayer && !isFont);
+ if(paramType < VG_IMAGE_FORMAT || paramType > VG_IMAGE_HEIGHT)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else if(isPath)
+ { //read only, the function does nothing
+ RI_ASSERT(!isImage && !isPaint && !isMaskLayer && !isFont);
+ if(paramType < VG_PATH_FORMAT || paramType > VG_PATH_NUM_COORDS)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else if(isPaint)
+ {
+ RI_ASSERT(!isImage && !isPath && !isMaskLayer && !isFont);
+ setPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, 1, values, false);
+ }
+ else if(isMaskLayer)
+ {
+ RI_ASSERT(!isImage && !isPath && !isPaint && !isFont);
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else
+ { //read only, the function does nothing
+ RI_ASSERT(!isImage && !isPath && !isPaint && !isMaskLayer && isFont);
+ if (paramType != VG_FONT_NUM_GLYPHS)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetParameterfv(VGHandle object, VGint paramType, VGint count, const VGfloat * values)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(count < 0 || (!values && count > 0) || (values && !isAligned(values,4)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isMaskLayer = context->isValidMaskLayer(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isMaskLayer && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
+ if(isImage)
+ { //read only, the function does nothing
+ RI_ASSERT(!isPath && !isPaint && !isMaskLayer && !isFont);
+ if(paramType < VG_IMAGE_FORMAT || paramType > VG_IMAGE_HEIGHT)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else if(isPath)
+ { //read only, the function does nothing
+ RI_ASSERT(!isImage && !isPaint && !isMaskLayer && !isFont);
+ if(paramType < VG_PATH_FORMAT || paramType > VG_PATH_NUM_COORDS)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else if(isPaint)
+ {
+ RI_ASSERT(!isImage && !isPath && !isMaskLayer && !isFont);
+ setPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, count, values, true);
+ }
+ else if(isMaskLayer)
+ {
+ RI_ASSERT(!isImage && !isPath && !isPaint && !isFont);
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else
+ { //read only, the function does nothing
+ RI_ASSERT(!isImage && !isPath && !isPaint && !isMaskLayer && isFont);
+ if (paramType != VG_FONT_NUM_GLYPHS)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetParameteriv(VGHandle object, VGint paramType, VGint count, const VGint * values)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(count < 0 || (!values && count > 0) || (values && !isAligned(values,4)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isMaskLayer = context->isValidMaskLayer(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isMaskLayer && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
+ if(isImage)
+ { //read only, the function does nothing
+ RI_ASSERT(!isPath && !isPaint && !isMaskLayer && !isFont);
+ if(paramType < VG_IMAGE_FORMAT || paramType > VG_IMAGE_HEIGHT)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else if(isPath)
+ { //read only, the function does nothing
+ RI_ASSERT(!isImage && !isPaint && !isMaskLayer && !isFont);
+ if(paramType < VG_PATH_FORMAT || paramType > VG_PATH_NUM_COORDS)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else if(isPaint)
+ {
+ RI_ASSERT(!isImage && !isPath && !isMaskLayer && !isFont);
+ setPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, count, values, false);
+ }
+ else if(isMaskLayer)
+ {
+ RI_ASSERT(!isImage && !isPath && !isPaint && !isFont);
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ else
+ { //read only, the function does nothing
+ RI_ASSERT(!isImage && !isPath && !isPaint && !isMaskLayer && isFont);
+ if (paramType != VG_FONT_NUM_GLYPHS)
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static void getPaintParameterifv(VGContext* context, Paint* paint, VGPaintParamType type, VGint count, void* values, bool floats)
+{
+ switch(type)
+ {
+ case VG_PAINT_TYPE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, paint->m_paintType);
+ break;
+
+ case VG_PAINT_COLOR:
+ if(count > 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, paint->m_inputPaintColor.r);
+ floatToParam(values, floats, count, 1, paint->m_inputPaintColor.g);
+ floatToParam(values, floats, count, 2, paint->m_inputPaintColor.b);
+ floatToParam(values, floats, count, 3, paint->m_inputPaintColor.a);
+ break;
+
+ case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, paint->m_colorRampSpreadMode);
+ break;
+
+ case VG_PAINT_COLOR_RAMP_STOPS:
+ {
+ if(count > paint->m_inputColorRampStops.size()*5) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ int j = 0;
+ for(int i=0;i<paint->m_inputColorRampStops.size();i++)
+ {
+ floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].offset);
+ floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.r);
+ floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.g);
+ floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.b);
+ floatToParam(values, floats, count, j++, paint->m_inputColorRampStops[i].color.a);
+ }
+ break;
+ }
+
+ case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, paint->m_colorRampPremultiplied);
+ break;
+
+ case VG_PAINT_LINEAR_GRADIENT:
+ if(count > 4) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, paint->m_inputLinearGradientPoint0.x);
+ floatToParam(values, floats, count, 1, paint->m_inputLinearGradientPoint0.y);
+ floatToParam(values, floats, count, 2, paint->m_inputLinearGradientPoint1.x);
+ floatToParam(values, floats, count, 3, paint->m_inputLinearGradientPoint1.y);
+ break;
+
+ case VG_PAINT_RADIAL_GRADIENT:
+ if(count > 5) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, paint->m_inputRadialGradientCenter.x);
+ floatToParam(values, floats, count, 1, paint->m_inputRadialGradientCenter.y);
+ floatToParam(values, floats, count, 2, paint->m_inputRadialGradientFocalPoint.x);
+ floatToParam(values, floats, count, 3, paint->m_inputRadialGradientFocalPoint.y);
+ floatToParam(values, floats, count, 4, paint->m_inputRadialGradientRadius);
+ break;
+
+ case VG_PAINT_PATTERN_TILING_MODE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, paint->m_patternTilingMode);
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static void getPathParameterifv(VGContext* context, Path* path, VGPathParamType type, VGint count, void* values, bool floats)
+{
+ switch(type)
+ {
+ case VG_PATH_FORMAT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, path->getFormat());
+ break;
+
+ case VG_PATH_DATATYPE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, path->getDatatype());
+ break;
+
+ case VG_PATH_SCALE:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, path->getScale());
+ break;
+
+ case VG_PATH_BIAS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ floatToParam(values, floats, count, 0, path->getBias());
+ break;
+
+ case VG_PATH_NUM_SEGMENTS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, path->getNumSegments());
+ break;
+
+ case VG_PATH_NUM_COORDS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, path->getNumCoordinates());
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static void getImageParameterifv(VGContext* context, Image* image, VGImageParamType type, VGint count, void* values, bool floats)
+{
+ switch(type)
+ {
+ case VG_IMAGE_FORMAT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ RI_ASSERT(isValidImageFormat(image->getDescriptor().format));
+ intToParam(values, floats, count, 0, image->getDescriptor().format);
+ break;
+
+ case VG_IMAGE_WIDTH:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, image->getWidth());
+ break;
+
+ case VG_IMAGE_HEIGHT:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, image->getHeight());
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static void getFontParameterifv(VGContext* context, Font* font, VGFontParamType type, VGint count, void* values, bool floats)
+{
+ switch(type)
+ {
+ case VG_FONT_NUM_GLYPHS:
+ if(count > 1) { context->setError(VG_ILLEGAL_ARGUMENT_ERROR); return; }
+ intToParam(values, floats, count, 0, font->getNumGlyphs());
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid VGParamType
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGfloat RI_APIENTRY vgGetParameterf(VGHandle object, VGint paramType)
+{
+ RI_GET_CONTEXT(0.0f);
+ RI_IF_ERROR(paramType == VG_PAINT_COLOR || paramType == VG_PAINT_COLOR_RAMP_STOPS || paramType == VG_PAINT_LINEAR_GRADIENT ||
+ paramType == VG_PAINT_RADIAL_GRADIENT, VG_ILLEGAL_ARGUMENT_ERROR, 0.0f); //vector valued parameter
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, 0.0f); //invalid object handle
+ VGfloat ret = 0.0f;
+ if(isImage)
+ {
+ RI_ASSERT(!isPath && !isPaint && !isFont);
+ getImageParameterifv(context, (Image*)object, (VGImageParamType)paramType, 1, &ret, true);
+ }
+ else if(isPath)
+ {
+ RI_ASSERT(!isImage && !isPaint && !isFont);
+ getPathParameterifv(context, (Path*)object, (VGPathParamType)paramType, 1, &ret, true);
+ }
+ else if(isPaint)
+ {
+ RI_ASSERT(!isImage && !isPath && !isFont);
+ getPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, 1, &ret, true);
+ }
+ else
+ {
+ RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
+ getFontParameterifv(context, (Font*)object, (VGFontParamType)paramType, 1, &ret, true);
+ }
+ RI_RETURN(ret);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGint RI_APIENTRY vgGetParameteri(VGHandle object, VGint paramType)
+{
+ RI_GET_CONTEXT(0);
+ RI_IF_ERROR(paramType == VG_PAINT_COLOR || paramType == VG_PAINT_COLOR_RAMP_STOPS || paramType == VG_PAINT_LINEAR_GRADIENT ||
+ paramType == VG_PAINT_RADIAL_GRADIENT, VG_ILLEGAL_ARGUMENT_ERROR, 0); //vector valued parameter
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, 0); //invalid object handle
+ VGint ret = 0;
+ if(isImage)
+ {
+ RI_ASSERT(!isPath && !isPaint && !isFont);
+ getImageParameterifv(context, (Image*)object, (VGImageParamType)paramType, 1, &ret, false);
+ }
+ else if(isPath)
+ {
+ RI_ASSERT(!isImage && !isPaint && !isFont);
+ getPathParameterifv(context, (Path*)object, (VGPathParamType)paramType, 1, &ret, false);
+ }
+ else if(isPaint)
+ {
+ RI_ASSERT(!isImage && !isPath && !isFont);
+ getPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, 1, &ret, false);
+ }
+ else
+ {
+ RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
+ getFontParameterifv(context, (Font*)object, (VGFontParamType)paramType, 1, &ret, false);
+ }
+ RI_RETURN(ret);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgGetParameterfv(VGHandle object, VGint paramType, VGint count, VGfloat * values)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(count <= 0 || !values || !isAligned(values,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
+ if(isImage)
+ {
+ RI_ASSERT(!isPath && !isPaint && !isFont);
+ getImageParameterifv(context, (Image*)object, (VGImageParamType)paramType, count, values, true);
+ }
+ else if(isPath)
+ {
+ RI_ASSERT(!isImage && !isPaint && !isFont);
+ getPathParameterifv(context, (Path*)object, (VGPathParamType)paramType, count, values, true);
+ }
+ else if(isPaint)
+ {
+ RI_ASSERT(!isImage && !isPath && !isFont);
+ getPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, count, values, true);
+ }
+ else
+ {
+ RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
+ getFontParameterifv(context, (Font*)object, (VGFontParamType)paramType, count, values, true);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgGetParameteriv(VGHandle object, VGint paramType, VGint count, VGint * values)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(count <= 0 || !values || !isAligned(values,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid object handle
+ if(isImage)
+ {
+ RI_ASSERT(!isPath && !isPaint && !isFont);
+ getImageParameterifv(context, (Image*)object, (VGImageParamType)paramType, count, values, false);
+ }
+ else if(isPath)
+ {
+ RI_ASSERT(!isImage && !isPaint && !isFont);
+ getPathParameterifv(context, (Path*)object, (VGPathParamType)paramType, count, values, false);
+ }
+ else if(isPaint)
+ {
+ RI_ASSERT(!isImage && !isPath && !isFont);
+ getPaintParameterifv(context, (Paint*)object, (VGPaintParamType)paramType, count, values, false);
+ }
+ else
+ {
+ RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
+ getFontParameterifv(context, (Font*)object, (VGFontParamType)paramType, count, values, false);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGint RI_APIENTRY vgGetParameterVectorSize(VGHandle object, VGint paramType)
+{
+ RI_GET_CONTEXT(0);
+ bool isImage = context->isValidImage(object);
+ bool isPath = context->isValidPath(object);
+ bool isPaint = context->isValidPaint(object);
+ bool isFont = context->isValidFont(object);
+ RI_IF_ERROR(!isImage && !isPath && !isPaint && !isFont, VG_BAD_HANDLE_ERROR, 0); //invalid object handle
+ int ret = 0;
+ if(isImage)
+ {
+ RI_ASSERT(!isPath && !isPaint && !isFont);
+ switch(paramType)
+ {
+ case VG_IMAGE_FORMAT:
+ case VG_IMAGE_WIDTH:
+ case VG_IMAGE_HEIGHT:
+ ret = 1;
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid paramType
+ break;
+ }
+ }
+ else if(isPath)
+ {
+ RI_ASSERT(!isImage && !isPaint && !isFont);
+ switch(paramType)
+ {
+ case VG_PATH_FORMAT:
+ case VG_PATH_DATATYPE:
+ case VG_PATH_SCALE:
+ case VG_PATH_BIAS:
+ case VG_PATH_NUM_SEGMENTS:
+ case VG_PATH_NUM_COORDS:
+ ret = 1;
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid paramType
+ break;
+ }
+ }
+ else if(isPaint)
+ {
+ RI_ASSERT(!isImage && !isPath && !isFont);
+ switch(paramType)
+ {
+ case VG_PAINT_TYPE:
+ case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+ case VG_PAINT_PATTERN_TILING_MODE:
+ ret = 1;
+ break;
+
+ case VG_PAINT_COLOR:
+ case VG_PAINT_LINEAR_GRADIENT:
+ ret = 4;
+ break;
+
+ case VG_PAINT_COLOR_RAMP_STOPS:
+ ret = ((Paint*)object)->m_inputColorRampStops.size() * 5;
+ break;
+
+ case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
+ ret = 1;
+ break;
+
+ case VG_PAINT_RADIAL_GRADIENT:
+ ret = 5;
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid paramType
+ break;
+ }
+ }
+ else
+ {
+ RI_ASSERT(!isImage && !isPath && !isPaint && isFont);
+ switch(paramType)
+ {
+ case VG_FONT_NUM_GLYPHS:
+ ret = 1;
+ break;
+
+ default:
+ context->setError(VG_ILLEGAL_ARGUMENT_ERROR); //invalid paramType
+ break;
+ }
+ }
+ RI_RETURN(ret);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static Matrix3x3* getCurrentMatrix(VGContext* context)
+{
+ RI_ASSERT(context);
+ switch(context->m_matrixMode)
+ {
+ case VG_MATRIX_PATH_USER_TO_SURFACE:
+ return &context->m_pathUserToSurface;
+
+ case VG_MATRIX_IMAGE_USER_TO_SURFACE:
+ return &context->m_imageUserToSurface;
+
+ case VG_MATRIX_FILL_PAINT_TO_USER:
+ return &context->m_fillPaintToUser;
+
+ case VG_MATRIX_STROKE_PAINT_TO_USER:
+ return &context->m_strokePaintToUser;
+
+ default:
+ RI_ASSERT(context->m_matrixMode == VG_MATRIX_GLYPH_USER_TO_SURFACE);
+ return &context->m_glyphUserToSurface;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgLoadIdentity(void)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ Matrix3x3* d = getCurrentMatrix(context);
+ d->identity();
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgLoadMatrix(const VGfloat * m)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!m || !isAligned(m,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Matrix3x3* d = getCurrentMatrix(context);
+ d->set(inputFloat(m[0]), inputFloat(m[3]), inputFloat(m[6]),
+ inputFloat(m[1]), inputFloat(m[4]), inputFloat(m[7]),
+ inputFloat(m[2]), inputFloat(m[5]), inputFloat(m[8]));
+ if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
+ {
+ (*d)[2].set(0,0,1);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgGetMatrix(VGfloat * m)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!m || !isAligned(m,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Matrix3x3* d = getCurrentMatrix(context);
+ m[0] = (*d)[0][0];
+ m[1] = (*d)[1][0];
+ m[2] = (*d)[2][0];
+ m[3] = (*d)[0][1];
+ m[4] = (*d)[1][1];
+ m[5] = (*d)[2][1];
+ m[6] = (*d)[0][2];
+ m[7] = (*d)[1][2];
+ m[8] = (*d)[2][2];
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgMultMatrix(const VGfloat * m)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!m || !isAligned(m,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Matrix3x3 n(inputFloat(m[0]), inputFloat(m[3]), inputFloat(m[6]),
+ inputFloat(m[1]), inputFloat(m[4]), inputFloat(m[7]),
+ inputFloat(m[2]), inputFloat(m[5]), inputFloat(m[8]));
+ if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
+ n[2].set(0,0,1);
+
+ Matrix3x3* d = getCurrentMatrix(context);
+ *d *= n;
+ if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
+ {
+ (*d)[2].set(0,0,1); //force affinity
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgTranslate(VGfloat tx, VGfloat ty)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ Matrix3x3 n(1, 0, inputFloat(tx),
+ 0, 1, inputFloat(ty),
+ 0, 0, 1 );
+ Matrix3x3* d = getCurrentMatrix(context);
+ *d *= n;
+ if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
+ {
+ (*d)[2].set(0,0,1); //force affinity
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgScale(VGfloat sx, VGfloat sy)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ Matrix3x3 n(inputFloat(sx), 0, 0,
+ 0, inputFloat(sy), 0,
+ 0, 0, 1 );
+ Matrix3x3* d = getCurrentMatrix(context);
+ *d *= n;
+ if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
+ {
+ (*d)[2].set(0,0,1); //force affinity
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgShear(VGfloat shx, VGfloat shy)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ Matrix3x3 n(1, inputFloat(shx), 0,
+ inputFloat(shy), 1, 0,
+ 0, 0, 1);
+ Matrix3x3* d = getCurrentMatrix(context);
+ *d *= n;
+ if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
+ {
+ (*d)[2].set(0,0,1); //force affinity
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgRotate(VGfloat angle)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RIfloat a = RI_DEG_TO_RAD(inputFloat(angle));
+ Matrix3x3 n((RIfloat)cos(a), -(RIfloat)sin(a), 0,
+ (RIfloat)sin(a), (RIfloat)cos(a), 0,
+ 0, 0, 1 );
+ Matrix3x3* d = getCurrentMatrix(context);
+ *d *= n;
+ if(context->m_matrixMode != VG_MATRIX_IMAGE_USER_TO_SURFACE)
+ {
+ (*d)[2].set(0,0,1); //force affinity
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgMask(VGHandle mask, VGMaskOperation operation, VGint x, VGint y, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ bool isImage = context->isValidImage(mask);
+ bool isMaskLayer = context->isValidMaskLayer(mask);
+ RI_IF_ERROR(operation != VG_CLEAR_MASK && operation != VG_FILL_MASK && !isImage && !isMaskLayer, VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(operation != VG_CLEAR_MASK && operation != VG_FILL_MASK && isImage && eglvgIsInUse((Image*)mask), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(operation < VG_CLEAR_MASK || operation > VG_SUBTRACT_MASK, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Drawable* drawable = context->getCurrentDrawable();
+ RI_IF_ERROR(isMaskLayer && drawable->getNumSamples() != ((Surface*)mask)->getNumSamples(), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ if(!drawable || !drawable->getMaskBuffer())
+ {
+ RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment or context has no mask buffer
+ }
+ if(isImage)
+ drawable->getMaskBuffer()->mask((Image*)mask, operation, x, y, width, height);
+ else
+ drawable->getMaskBuffer()->mask((Surface*)mask, operation, x, y, width, height);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static void renderStroke(const VGContext* context, int w, int h, int numSamples, Path* path, Rasterizer& rasterizer, const PixelPipe* pixelPipe, const Matrix3x3& userToSurface)
+{
+ RI_ASSERT(context);
+ RI_ASSERT(w > 0 && h > 0 && numSamples >= 1 && numSamples <= 32);
+
+ RIuint32* covBuffer = RI_NEW_ARRAY(RIuint32, w*h);
+ memset(covBuffer, 0, w*h*sizeof(RIuint32));
+
+ rasterizer.setup(0, 0, w, h, VG_NON_ZERO, NULL, covBuffer);
+ path->stroke(userToSurface, rasterizer, context->m_strokeDashPattern, context->m_strokeDashPhase, context->m_strokeDashPhaseReset ? true : false,
+ context->m_strokeLineWidth, context->m_strokeCapStyle, context->m_strokeJoinStyle, RI_MAX(context->m_strokeMiterLimit, 1.0f)); //throws bad_alloc
+
+ int sx,sy,ex,ey;
+ rasterizer.getBBox(sx,sy,ex,ey);
+ RI_ASSERT(sx >= 0 && sx <= w);
+ RI_ASSERT(sy >= 0 && sy <= h);
+ RI_ASSERT(ex >= 0 && ex <= w);
+ RI_ASSERT(ey >= 0 && ey <= h);
+
+ for(int j=sy;j<ey;j++)
+ {
+ for(int i=sx;i<ex;i++)
+ {
+ unsigned int c = covBuffer[j*w+i];
+ if(c)
+ {
+ int coverage = 0;
+ for(int k=0;k<numSamples;k++)
+ {
+ if(c & (1<<k))
+ coverage++;
+ }
+ pixelPipe->pixelPipe(i, j, (RIfloat)coverage/(RIfloat)numSamples, c);
+ }
+ }
+ }
+ RI_DELETE_ARRAY(covBuffer);
+}
+
+void RI_APIENTRY vgRenderToMask(VGPath path, VGbitfield paintModes, VGMaskOperation operation)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ RI_IF_ERROR(!paintModes || (paintModes & ~(VG_FILL_PATH | VG_STROKE_PATH)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid paint mode
+ RI_IF_ERROR(operation < VG_CLEAR_MASK || operation > VG_SUBTRACT_MASK, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Drawable* curr = context->getCurrentDrawable();
+ if(!curr || !curr->getMaskBuffer())
+ {
+ RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment or context has no mask buffer
+ }
+
+ if(operation == VG_CLEAR_MASK || operation == VG_FILL_MASK)
+ {
+ Surface* dummy = NULL;
+ curr->getMaskBuffer()->mask(dummy, operation, 0, 0, curr->getWidth(), curr->getHeight());
+ RI_RETURN(RI_NO_RETVAL);
+ }
+
+ try
+ {
+ Drawable drawable(Color::formatToDescriptor(VG_A_8), curr->getWidth(), curr->getHeight(), curr->getNumSamples(), 1); //TODO 0 mask bits (mask buffer is not used)
+
+ Rasterizer rasterizer;
+ if(context->m_scissoring)
+ rasterizer.setScissor(context->m_scissor); //throws bad_alloc
+ int numSamples = rasterizer.setupSamplingPattern(context->m_renderingQuality, drawable.getNumSamples());
+
+ PixelPipe pixelPipe;
+ pixelPipe.setDrawable(&drawable);
+ pixelPipe.setMask(false);
+ pixelPipe.setPaint(NULL); //use default paint (solid color alpha = 1)
+ pixelPipe.setBlendMode(VG_BLEND_SRC); //write solid color * coverage to dest
+
+ Matrix3x3 userToSurface = context->m_pathUserToSurface;
+ userToSurface[2].set(0,0,1); //force affinity
+
+ if(paintModes & VG_FILL_PATH)
+ {
+ drawable.getColorBuffer()->clear(Color(0,0,0,0,drawable.getColorBuffer()->getDescriptor().internalFormat), 0, 0, drawable.getWidth(), drawable.getHeight());
+ ((Path*)path)->fill(userToSurface, rasterizer); //throws bad_alloc
+ rasterizer.setup(0, 0, drawable.getWidth(), drawable.getHeight(), context->m_fillRule, &pixelPipe, NULL);
+ rasterizer.fill(); //throws bad_alloc
+ curr->getMaskBuffer()->mask(drawable.getColorBuffer(), operation, 0, 0, drawable.getWidth(), drawable.getHeight());
+ }
+
+ if(paintModes & VG_STROKE_PATH && context->m_strokeLineWidth > 0.0f)
+ {
+ drawable.getColorBuffer()->clear(Color(0,0,0,0,drawable.getColorBuffer()->getDescriptor().internalFormat), 0, 0, drawable.getWidth(), drawable.getHeight());
+ renderStroke(context, drawable.getWidth(), drawable.getHeight(), numSamples, (Path*)path, rasterizer, &pixelPipe, userToSurface);
+ curr->getMaskBuffer()->mask(drawable.getColorBuffer(), operation, 0, 0, drawable.getWidth(), drawable.getHeight());
+ }
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGMaskLayer RI_APIENTRY vgCreateMaskLayer(VGint width, VGint height)
+{
+ RI_GET_CONTEXT(VG_INVALID_HANDLE);
+ RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
+ RI_IF_ERROR(width > RI_MAX_IMAGE_WIDTH || height > RI_MAX_IMAGE_HEIGHT || width*height > RI_MAX_IMAGE_PIXELS ||
+ width*height > RI_MAX_IMAGE_BYTES, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
+ Drawable* curr = context->getCurrentDrawable();
+ if(!curr || !curr->getMaskBuffer())
+ RI_RETURN(VG_INVALID_HANDLE); //no current drawing surface
+
+ Surface* layer = NULL;
+ try
+ {
+ layer = RI_NEW(Surface, (Color::formatToDescriptor(VG_A_8), width, height, curr->getNumSamples())); //throws bad_alloc
+ RI_ASSERT(layer);
+ context->m_maskLayerManager->addResource(layer, context); //throws bad_alloc
+ layer->clear(Color(1,1,1,1,Color::sRGBA), 0, 0, width, height);
+ RI_RETURN((VGMaskLayer)layer);
+ }
+ catch(std::bad_alloc)
+ {
+ RI_DELETE(layer);
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ RI_RETURN(VG_INVALID_HANDLE);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgDestroyMaskLayer(VGMaskLayer maskLayer)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidMaskLayer(maskLayer), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid handle
+
+ context->m_maskLayerManager->removeResource((Surface*)maskLayer);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgFillMaskLayer(VGMaskLayer maskLayer, VGint x, VGint y, VGint width, VGint height, VGfloat value)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidMaskLayer(maskLayer), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid handle
+ RI_IF_ERROR(value < 0.0f || value > 1.0f, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Surface* layer = (Surface*)maskLayer;
+ RI_IF_ERROR(width <= 0 || height <= 0 || x < 0 || y < 0 || x > layer->getWidth()-width || y > layer->getHeight()-height, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ layer->clear(Color(1,1,1,value,Color::sRGBA), x, y, width, height);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgCopyMask(VGMaskLayer maskLayer, VGint dx, VGint dy, VGint sx, VGint sy, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidMaskLayer(maskLayer), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid handle
+ Drawable* drawable = context->getCurrentDrawable();
+ if(!drawable || !drawable->getMaskBuffer())
+ {
+ RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment or context has no mask buffer
+ }
+ Surface* layer = (Surface*)maskLayer;
+ RI_IF_ERROR(width <= 0 || height <= 0 || drawable->getNumSamples() != layer->getNumSamples(), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ try
+ { //copy drawing surface mask to mask layer
+ layer->blit(drawable->getMaskBuffer(), sx, sy, dx, dy, width, height); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgClear(VGint x, VGint y, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Drawable* drawable = context->getCurrentDrawable();
+ if(!drawable)
+ {
+ RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
+ }
+
+ try
+ {
+ if(context->m_scissoring)
+ drawable->getColorBuffer()->clear(context->m_clearColor, x, y, width, height, context->m_scissor); //throws bad_alloc
+ else
+ drawable->getColorBuffer()->clear(context->m_clearColor, x, y, width, height);
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGPath RI_APIENTRY vgCreatePath(VGint pathFormat, VGPathDatatype datatype, VGfloat scale, VGfloat bias, VGint segmentCapacityHint, VGint coordCapacityHint, VGbitfield capabilities)
+{
+ RI_GET_CONTEXT(VG_INVALID_HANDLE);
+ RI_IF_ERROR(pathFormat != VG_PATH_FORMAT_STANDARD, VG_UNSUPPORTED_PATH_FORMAT_ERROR, VG_INVALID_HANDLE);
+ RI_IF_ERROR(datatype < VG_PATH_DATATYPE_S_8 || datatype > VG_PATH_DATATYPE_F, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
+ RIfloat s = inputFloat(scale);
+ RIfloat b = inputFloat(bias);
+ RI_IF_ERROR(s == 0.0f, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
+ capabilities &= VG_PATH_CAPABILITY_ALL; //undefined bits are ignored
+
+ Path* path = NULL;
+ try
+ {
+ path = RI_NEW(Path, (pathFormat, datatype, s, b, segmentCapacityHint, coordCapacityHint, capabilities)); //throws bad_alloc
+ RI_ASSERT(path);
+ context->m_pathManager->addResource(path, context); //throws bad_alloc
+ RI_RETURN((VGPath)path);
+ }
+ catch(std::bad_alloc)
+ {
+ RI_DELETE(path);
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ RI_RETURN(VG_INVALID_HANDLE);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgClearPath(VGPath path, VGbitfield capabilities)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ capabilities &= VG_PATH_CAPABILITY_ALL; //undefined bits are ignored
+ ((Path*)path)->clear(capabilities);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgDestroyPath(VGPath path)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+
+ context->m_pathManager->removeResource((Path*)path);
+
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgRemovePathCapabilities(VGPath path, VGbitfield capabilities)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ capabilities &= VG_PATH_CAPABILITY_ALL; //undefined bits are ignored
+
+ VGbitfield caps = ((Path*)path)->getCapabilities();
+ caps &= ~capabilities;
+ ((Path*)path)->setCapabilities(caps);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGbitfield RI_APIENTRY vgGetPathCapabilities(VGPath path)
+{
+ RI_GET_CONTEXT(0);
+ RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, 0); //invalid path handle
+ VGbitfield ret = ((Path*)path)->getCapabilities();
+ RI_RETURN(ret);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgAppendPathData(VGPath dstPath, VGint numSegments, const VGubyte * pathSegments, const void * pathData)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(dstPath), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ Path* p = (Path*)dstPath;
+ RI_IF_ERROR(!(p->getCapabilities() & VG_PATH_CAPABILITY_APPEND_TO), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //no append cap
+ RI_IF_ERROR(numSegments <= 0 || !pathSegments || !pathData, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //no segments or data
+ RI_IF_ERROR((p->getDatatype() == VG_PATH_DATATYPE_S_16 && !isAligned(pathData,2)) ||
+ ((p->getDatatype() == VG_PATH_DATATYPE_S_32 || p->getDatatype() == VG_PATH_DATATYPE_F) && !isAligned(pathData,4)),
+ VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid alignment
+ for(int i=0;i<numSegments;i++)
+ {
+ VGPathSegment c = (VGPathSegment)(pathSegments[i] & 0x1e);
+ RI_IF_ERROR(c < VG_CLOSE_PATH || c > VG_LCWARC_TO, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid segment
+ RI_IF_ERROR(c & ~0x1f, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //reserved bits are nonzero
+ }
+
+ try
+ {
+ p->appendData((const RIuint8*)pathSegments, numSegments, (const RIuint8*)pathData); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgModifyPathCoords(VGPath dstPath, VGint startIndex, VGint numSegments, const void * pathData)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(dstPath), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ Path* p = (Path*)dstPath;
+ RI_IF_ERROR(!(p->getCapabilities() & VG_PATH_CAPABILITY_MODIFY), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //no modify cap
+ RI_IF_ERROR(!pathData || startIndex < 0 || numSegments <= 0 || RI_INT_ADDSATURATE(startIndex, numSegments) > p->getNumSegments(), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //no segments
+ RI_IF_ERROR((p->getDatatype() == VG_PATH_DATATYPE_S_16 && !isAligned(pathData,2)) ||
+ ((p->getDatatype() == VG_PATH_DATATYPE_S_32 || p->getDatatype() == VG_PATH_DATATYPE_F) && !isAligned(pathData,4)),
+ VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid alignment
+ p->modifyCoords(startIndex, numSegments, (const RIuint8*)pathData);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgAppendPath(VGPath dstPath, VGPath srcPath)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(dstPath) || !context->isValidPath(srcPath), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ RI_IF_ERROR(!(((Path*)dstPath)->getCapabilities() & VG_PATH_CAPABILITY_APPEND_TO) ||
+ !(((Path*)srcPath)->getCapabilities() & VG_PATH_CAPABILITY_APPEND_FROM), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //invalid caps
+
+ try
+ {
+ ((Path*)dstPath)->append((Path*)srcPath); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgTransformPath(VGPath dstPath, VGPath srcPath)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(dstPath) || !context->isValidPath(srcPath), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ RI_IF_ERROR(!(((Path*)dstPath)->getCapabilities() & VG_PATH_CAPABILITY_TRANSFORM_TO) ||
+ !(((Path*)srcPath)->getCapabilities() & VG_PATH_CAPABILITY_TRANSFORM_FROM), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //invalid caps
+ try
+ {
+ ((Path*)dstPath)->transform((Path*)srcPath, context->m_pathUserToSurface); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static bool drawPath(VGContext* context, VGPath path, const Matrix3x3& userToSurfaceMatrix, VGbitfield paintModes)
+{
+ //set up rendering surface and mask buffer
+ Drawable* drawable = context->getCurrentDrawable();
+ if(!drawable)
+ return false; //no EGL surface is current at the moment
+
+ Rasterizer rasterizer;
+ if(context->m_scissoring)
+ rasterizer.setScissor(context->m_scissor); //throws bad_alloc
+ int numSamples = rasterizer.setupSamplingPattern(context->m_renderingQuality, drawable->getNumSamples());
+
+ PixelPipe pixelPipe;
+ pixelPipe.setDrawable(drawable);
+ pixelPipe.setMask(context->m_masking ? true : false);
+ pixelPipe.setBlendMode(context->m_blendMode);
+ pixelPipe.setTileFillColor(context->m_tileFillColor);
+ pixelPipe.setImageQuality(context->m_imageQuality);
+ pixelPipe.setColorTransform(context->m_colorTransform ? true : false, context->m_colorTransformValues);
+
+ Matrix3x3 userToSurface = userToSurfaceMatrix;
+ userToSurface[2].set(0,0,1); //force affinity
+
+ if(paintModes & VG_FILL_PATH)
+ {
+ pixelPipe.setPaint((Paint*)context->m_fillPaint);
+
+ Matrix3x3 surfaceToPaintMatrix = userToSurface * context->m_fillPaintToUser;
+ if(surfaceToPaintMatrix.invert())
+ {
+ surfaceToPaintMatrix[2].set(0,0,1); //force affinity
+ pixelPipe.setSurfaceToPaintMatrix(surfaceToPaintMatrix);
+
+ rasterizer.setup(0, 0, drawable->getWidth(), drawable->getHeight(), context->m_fillRule, &pixelPipe, NULL);
+ ((Path*)path)->fill(userToSurface, rasterizer); //throws bad_alloc
+ rasterizer.fill(); //throws bad_alloc
+ }
+ }
+
+ if(paintModes & VG_STROKE_PATH && context->m_strokeLineWidth > 0.0f)
+ {
+ pixelPipe.setPaint((Paint*)context->m_strokePaint);
+
+ Matrix3x3 surfaceToPaintMatrix = userToSurface * context->m_strokePaintToUser;
+ if(surfaceToPaintMatrix.invert())
+ {
+ surfaceToPaintMatrix[2].set(0,0,1); //force affinity
+ pixelPipe.setSurfaceToPaintMatrix(surfaceToPaintMatrix);
+
+ renderStroke(context, drawable->getWidth(), drawable->getHeight(), numSamples, (Path*)path, rasterizer, &pixelPipe, userToSurface);
+ }
+ }
+ return true;
+}
+
+void RI_APIENTRY vgDrawPath(VGPath path, VGbitfield paintModes)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ RI_IF_ERROR(!paintModes || (paintModes & ~(VG_FILL_PATH | VG_STROKE_PATH)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid paint mode
+
+ try
+ {
+ if(!drawPath(context, path, context->m_pathUserToSurface, paintModes))
+ {
+ RI_RETURN(RI_NO_RETVAL);
+ }
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGfloat RI_APIENTRY vgPathLength(VGPath path, VGint startSegment, VGint numSegments)
+{
+ RI_GET_CONTEXT(-1.0f);
+ RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, -1.0f); //invalid path handle
+ Path* p = (Path*)path;
+ RI_IF_ERROR(!(p->getCapabilities() & VG_PATH_CAPABILITY_PATH_LENGTH), VG_PATH_CAPABILITY_ERROR, -1.0f); //invalid caps
+ RI_IF_ERROR(startSegment < 0 || numSegments <= 0 || RI_INT_ADDSATURATE(startSegment, numSegments) > p->getNumSegments(), VG_ILLEGAL_ARGUMENT_ERROR, -1.0f);
+ RIfloat pathLength = -1.0f;
+ try
+ {
+ pathLength = p->getPathLength(startSegment, numSegments); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(pathLength);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgPointAlongPath(VGPath path, VGint startSegment, VGint numSegments, VGfloat distance, VGfloat * x, VGfloat * y, VGfloat * tangentX, VGfloat * tangentY)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ Path* p = (Path*)path;
+ RI_IF_ERROR((x && y && !(p->getCapabilities() & VG_PATH_CAPABILITY_POINT_ALONG_PATH)) ||
+ (tangentX && tangentY && !(p->getCapabilities() & VG_PATH_CAPABILITY_TANGENT_ALONG_PATH)), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //invalid caps
+ RI_IF_ERROR(startSegment < 0 || numSegments <= 0 || RI_INT_ADDSATURATE(startSegment, numSegments) > p->getNumSegments(), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!isAligned(x,4) || !isAligned(y,4) || !isAligned(tangentX,4) || !isAligned(tangentY,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ try
+ {
+ Vector2 point, tangent;
+ p->getPointAlong(startSegment, numSegments, distance, point, tangent); //throws bad_alloc
+ if(x && y)
+ {
+ *x = point.x;
+ *y = point.y;
+ }
+ if(tangentX && tangentY)
+ {
+ tangent.normalize();
+ *tangentX = tangent.x;
+ *tangentY = tangent.y;
+ }
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgPathBounds(VGPath path, VGfloat * minx, VGfloat * miny, VGfloat * width, VGfloat * height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ RI_IF_ERROR(!(((Path*)path)->getCapabilities() & VG_PATH_CAPABILITY_PATH_BOUNDS), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //invalid caps
+ RI_IF_ERROR(!minx || !miny || !width || !height, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!isAligned(minx,4) || !isAligned(miny,4) || !isAligned(width,4) || !isAligned(height,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ try
+ {
+ RIfloat pminx,pminy,pmaxx,pmaxy;
+ ((Path*)path)->getPathBounds(pminx, pminy, pmaxx, pmaxy); //throws bad_alloc
+ *minx = pminx;
+ *miny = pminy;
+ *width = pmaxx - pminx;
+ *height = pmaxy - pminy;
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgPathTransformedBounds(VGPath path, VGfloat * minx, VGfloat * miny, VGfloat * width, VGfloat * height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ RI_IF_ERROR(!(((Path*)path)->getCapabilities() & VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS), VG_PATH_CAPABILITY_ERROR, RI_NO_RETVAL); //invalid caps
+ RI_IF_ERROR(!minx || !miny || !width || !height, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!isAligned(minx,4) || !isAligned(miny,4) || !isAligned(width,4) || !isAligned(height,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ try
+ {
+ RIfloat pminx, pminy, pmaxx, pmaxy;
+ ((Path*)path)->getPathTransformedBounds(context->m_pathUserToSurface, pminx, pminy, pmaxx, pmaxy); //throws bad_alloc
+ *minx = pminx;
+ *miny = pminy;
+ *width = pmaxx - pminx;
+ *height = pmaxy - pminy;
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGboolean RI_APIENTRY vgInterpolatePath(VGPath dstPath, VGPath startPath, VGPath endPath, VGfloat amount)
+{
+ RI_GET_CONTEXT(VG_FALSE);
+ RI_IF_ERROR(!context->isValidPath(dstPath) || !context->isValidPath(startPath) || !context->isValidPath(endPath), VG_BAD_HANDLE_ERROR, VG_FALSE); //invalid path handle
+ RI_IF_ERROR(!(((Path*)dstPath)->getCapabilities() & VG_PATH_CAPABILITY_INTERPOLATE_TO) ||
+ !(((Path*)startPath)->getCapabilities() & VG_PATH_CAPABILITY_INTERPOLATE_FROM) ||
+ !(((Path*)endPath)->getCapabilities() & VG_PATH_CAPABILITY_INTERPOLATE_FROM), VG_PATH_CAPABILITY_ERROR, VG_FALSE); //invalid caps
+ VGboolean ret = VG_FALSE;
+ try
+ {
+ if(((Path*)dstPath)->interpolate((const Path*)startPath, (const Path*)endPath, inputFloat(amount))) //throws bad_alloc
+ ret = VG_TRUE;
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(ret);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGPaint RI_APIENTRY vgCreatePaint(void)
+{
+// RI_GET_CONTEXT(VG_INVALID_HANDLE);
+ OSAcquireMutex();
+ VGContext* context = (VGContext*)eglvgGetCurrentVGContext();
+ if(!context)
+ {
+ OSReleaseMutex();
+ return VG_INVALID_HANDLE;
+ }
+ Paint* paint = NULL;
+ try
+ {
+ paint = RI_NEW(Paint, ()); //throws bad_alloc
+ RI_ASSERT(paint);
+ context->m_paintManager->addResource(paint, context); //throws bad_alloc
+ RI_RETURN((VGPaint)paint);
+ }
+ catch(std::bad_alloc)
+ {
+ RI_DELETE(paint);
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ RI_RETURN(VG_INVALID_HANDLE);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgDestroyPaint(VGPaint paint)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPaint(paint), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid paint handle
+
+ context->m_paintManager->removeResource((Paint*)paint);
+
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetPaint(VGPaint paint, VGbitfield paintModes)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(paint && !context->isValidPaint(paint), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid paint handle
+ RI_IF_ERROR(!paintModes || paintModes & ~(VG_FILL_PATH | VG_STROKE_PATH), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid paint mode
+
+ context->releasePaint(paintModes);
+
+ if(paintModes & VG_FILL_PATH)
+ {
+ if(paint)
+ ((Paint*)paint)->addReference();
+ context->m_fillPaint = paint;
+ }
+ if(paintModes & VG_STROKE_PATH)
+ {
+ if(paint)
+ ((Paint*)paint)->addReference();
+ context->m_strokePaint = paint;
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetColor(VGPaint paint, VGuint rgba)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPaint(paint), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid paint handle
+ Paint* p = (Paint*)paint;
+ p->m_inputPaintColor.unpack(rgba, Color::formatToDescriptor(VG_sRGBA_8888));
+ p->m_paintColor = inputColor(p->m_inputPaintColor);
+ p->m_paintColor.clamp();
+ p->m_paintColor.premultiply();
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGuint RI_APIENTRY vgGetColor(VGPaint paint)
+{
+ RI_GET_CONTEXT(0);
+ RI_IF_ERROR(!context->isValidPaint(paint), VG_BAD_HANDLE_ERROR, 0); //invalid paint handle
+ unsigned int ret = ((Paint*)paint)->m_inputPaintColor.pack(Color::formatToDescriptor(VG_sRGBA_8888));
+ RI_RETURN(ret);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGPaint RI_APIENTRY vgGetPaint(VGPaintMode paintMode)
+{
+ RI_GET_CONTEXT(VG_INVALID_HANDLE);
+ RI_IF_ERROR(paintMode != VG_FILL_PATH && paintMode != VG_STROKE_PATH, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE); //invalid paint mode
+
+ if(paintMode == VG_FILL_PATH)
+ {
+ RI_RETURN(context->m_fillPaint);
+ }
+ RI_RETURN(context->m_strokePaint);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgPaintPattern(VGPaint paint, VGImage image)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidPaint(paint) || (image != VG_INVALID_HANDLE && !context->isValidImage(image)), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid handle
+ Image* img = (Image*)image;
+ Paint* pnt = (Paint*)paint;
+ RI_IF_ERROR(image != VG_INVALID_HANDLE && eglvgIsInUse(img), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ Image* pattern = pnt->m_pattern;
+ if(pattern)
+ {
+ pattern->removeInUse();
+ if(!pattern->removeReference())
+ RI_DELETE(pattern);
+ }
+ pnt->m_pattern = img;
+ if(img)
+ {
+ img->addReference();
+ img->addInUse();
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGImage RI_APIENTRY vgCreateImage(VGImageFormat format, VGint width, VGint height, VGbitfield allowedQuality)
+{
+ RI_GET_CONTEXT(VG_INVALID_HANDLE);
+ RI_IF_ERROR(!isValidImageFormat(format), VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, VG_INVALID_HANDLE);
+ RI_IF_ERROR(width <= 0 || height <= 0 || !allowedQuality ||
+ (allowedQuality & ~(VG_IMAGE_QUALITY_NONANTIALIASED | VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_BETTER)), VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
+ RI_IF_ERROR(width > RI_MAX_IMAGE_WIDTH || height > RI_MAX_IMAGE_HEIGHT || width*height > RI_MAX_IMAGE_PIXELS ||
+ ((width*Color::formatToDescriptor(format).bitsPerPixel+7)/8)*height > RI_MAX_IMAGE_BYTES, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
+
+ Image* image = NULL;
+ try
+ {
+ image = RI_NEW(Image, (Color::formatToDescriptor(format), width, height, allowedQuality)); //throws bad_alloc
+ RI_ASSERT(image);
+ context->m_imageManager->addResource(image, context); //throws bad_alloc
+ RI_RETURN((VGImage)image);
+ }
+ catch(std::bad_alloc)
+ {
+ RI_DELETE(image);
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ RI_RETURN(VG_INVALID_HANDLE);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgDestroyImage(VGImage image)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid image handle
+
+ context->m_imageManager->removeResource((Image*)image);
+
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgClearImage(VGImage image, VGint x, VGint y, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ Image* img = (Image*)image;
+ RI_IF_ERROR(eglvgIsInUse(img), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ img->clear(context->m_clearColor, x, y, width, height);
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgImageSubData(VGImage image, const void * data, VGint dataStride, VGImageFormat dataFormat, VGint x, VGint y, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ Image* img = (Image*)image;
+ RI_IF_ERROR(eglvgIsInUse(img), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!isValidImageFormat(dataFormat), VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!data || !isAligned(data, dataFormat) || width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ {
+ Image input(Color::formatToDescriptor(dataFormat), width, height, dataStride, const_cast<RIuint8*>((const RIuint8*)data));
+ input.addReference();
+ try
+ {
+ img->blit(input, 0, 0, x, y, width, height, false); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ input.removeReference();
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgGetImageSubData(VGImage image, void * data, VGint dataStride, VGImageFormat dataFormat, VGint x, VGint y, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ Image* img = (Image*)image;
+ RI_IF_ERROR(eglvgIsInUse(img), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!isValidImageFormat(dataFormat), VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!data || !isAligned(data, dataFormat) || width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ {
+ Image output(Color::formatToDescriptor(dataFormat), width, height, dataStride, (RIuint8*)data);
+ output.addReference();
+ try
+ {
+ output.blit(*img, x, y, 0, 0, width, height, false); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ output.removeReference();
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGImage RI_APIENTRY vgChildImage(VGImage parent, VGint x, VGint y, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(VG_INVALID_HANDLE);
+ RI_IF_ERROR(!context->isValidImage(parent), VG_BAD_HANDLE_ERROR, VG_INVALID_HANDLE);
+ Image* p = (Image*)parent;
+ RI_IF_ERROR(eglvgIsInUse((Image*)parent), VG_IMAGE_IN_USE_ERROR, VG_INVALID_HANDLE);
+ RI_IF_ERROR(x < 0 || x >= p->getWidth() || y < 0 || y >= p->getHeight() ||
+ width <= 0 || height <= 0 || RI_INT_ADDSATURATE(x, width) > p->getWidth() || RI_INT_ADDSATURATE(y, height) > p->getHeight(), VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
+
+ Image* child = NULL;
+ try
+ {
+ child = RI_NEW(Image, (p, x, y, width, height)); //throws bad_alloc
+ RI_ASSERT(child);
+ context->m_imageManager->addResource(child, context); //throws bad_alloc
+ RI_RETURN((VGImage)child);
+ }
+ catch(std::bad_alloc)
+ {
+ RI_DELETE(child);
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ RI_RETURN(VG_INVALID_HANDLE);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGImage RI_APIENTRY vgGetParent(VGImage image)
+{
+ RI_GET_CONTEXT(VG_INVALID_HANDLE);
+ RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, VG_INVALID_HANDLE);
+ VGImage ret = image; //if image has no ancestors, image is returned.
+
+ //The vgGetParent function returns the closest valid ancestor (i.e., one that has not been the target of a vgDestroyImage call)
+ // of the given image.
+ Image* im = ((Image*)image)->getParent();
+ for(;im;im = im->getParent())
+ {
+ if(context->isValidImage((VGImage)im))
+ { //the parent is valid and alive
+ ret = (VGImage)im;
+ break;
+ }
+ }
+ RI_RETURN(ret);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgCopyImage(VGImage dst, VGint dx, VGint dy, VGImage src, VGint sx, VGint sy, VGint width, VGint height, VGboolean dither)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(eglvgIsInUse((Image*)dst) || eglvgIsInUse((Image*)src), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ try
+ {
+ ((Image*)dst)->blit(*(Image*)src, sx, sy, dx, dy, width, height, dither ? true : false); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static bool drawImage(VGContext* context, VGImage image, const Matrix3x3& userToSurfaceMatrix)
+{
+ Drawable* drawable = context->getCurrentDrawable();
+ if(!drawable)
+ return false; //no EGL surface is current at the moment
+
+ Image* img = (Image*)image;
+ //transform image corners into the surface space
+ Vector3 p0(0, 0, 1);
+ Vector3 p1(0, (RIfloat)img->getHeight(), 1);
+ Vector3 p2((RIfloat)img->getWidth(), (RIfloat)img->getHeight(), 1);
+ Vector3 p3((RIfloat)img->getWidth(), 0, 1);
+ p0 = userToSurfaceMatrix * p0;
+ p1 = userToSurfaceMatrix * p1;
+ p2 = userToSurfaceMatrix * p2;
+ p3 = userToSurfaceMatrix * p3;
+ if(p0.z <= 0.0f || p1.z <= 0.0f || p2.z <= 0.0f || p3.z <= 0.0f)
+ return false;
+
+ //projection
+ p0 *= 1.0f/p0.z;
+ p1 *= 1.0f/p1.z;
+ p2 *= 1.0f/p2.z;
+ p3 *= 1.0f/p3.z;
+
+ Rasterizer rasterizer;
+ if(context->m_scissoring)
+ rasterizer.setScissor(context->m_scissor); //throws bad_alloc
+ rasterizer.setupSamplingPattern(context->m_renderingQuality, drawable->getNumSamples());
+
+ PixelPipe pixelPipe;
+ pixelPipe.setTileFillColor(context->m_tileFillColor);
+ pixelPipe.setPaint((Paint*)context->m_fillPaint);
+ pixelPipe.setImageQuality(context->m_imageQuality);
+ pixelPipe.setBlendMode(context->m_blendMode);
+ pixelPipe.setDrawable(drawable);
+ pixelPipe.setMask(context->m_masking ? true : false);
+ pixelPipe.setColorTransform(context->m_colorTransform ? true : false, context->m_colorTransformValues);
+
+ Matrix3x3 surfaceToImageMatrix = userToSurfaceMatrix;
+ Matrix3x3 surfaceToPaintMatrix = userToSurfaceMatrix * context->m_fillPaintToUser;
+ if(surfaceToImageMatrix.invert() && surfaceToPaintMatrix.invert())
+ {
+ VGImageMode imode = context->m_imageMode;
+ if(!surfaceToPaintMatrix.isAffine())
+ imode = VG_DRAW_IMAGE_NORMAL; //if paint matrix is not affine, always use normal image mode
+ surfaceToPaintMatrix[2].set(0,0,1); //force affine
+
+ pixelPipe.setImage(img, imode);
+ pixelPipe.setSurfaceToPaintMatrix(surfaceToPaintMatrix);
+ pixelPipe.setSurfaceToImageMatrix(surfaceToImageMatrix);
+
+ rasterizer.addEdge(Vector2(p0.x,p0.y), Vector2(p1.x,p1.y)); //throws bad_alloc
+ rasterizer.addEdge(Vector2(p1.x,p1.y), Vector2(p2.x,p2.y)); //throws bad_alloc
+ rasterizer.addEdge(Vector2(p2.x,p2.y), Vector2(p3.x,p3.y)); //throws bad_alloc
+ rasterizer.addEdge(Vector2(p3.x,p3.y), Vector2(p0.x,p0.y)); //throws bad_alloc
+ rasterizer.setup(0, 0, drawable->getWidth(), drawable->getHeight(), VG_EVEN_ODD, &pixelPipe, NULL);
+ rasterizer.fill(); //throws bad_alloc
+ }
+ return true;
+}
+
+void RI_APIENTRY vgDrawImage(VGImage image)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ Image* img = (Image*)image;
+ RI_IF_ERROR(eglvgIsInUse(img), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+
+ try
+ {
+ if(!drawImage(context, image, context->m_imageUserToSurface))
+ {
+ RI_RETURN(RI_NO_RETVAL);
+ }
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetPixels(VGint dx, VGint dy, VGImage src, VGint sx, VGint sy, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(eglvgIsInUse((Image*)src), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Drawable* drawable = context->getCurrentDrawable();
+ if(!drawable)
+ {
+ RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
+ }
+ try
+ {
+ if(context->m_scissoring)
+ drawable->getColorBuffer()->blit(*(Image*)src, sx, sy, dx, dy, width, height, context->m_scissor); //throws bad_alloc
+ else
+ drawable->getColorBuffer()->blit(*(Image*)src, sx, sy, dx, dy, width, height); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgWritePixels(const void * data, VGint dataStride, VGImageFormat dataFormat, VGint dx, VGint dy, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!isValidImageFormat(dataFormat), VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!data || !isAligned(data, dataFormat) || width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Drawable* drawable = context->getCurrentDrawable();
+ if(!drawable)
+ {
+ RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
+ }
+ {
+ Image input(Color::formatToDescriptor(dataFormat), width, height, dataStride, const_cast<RIuint8*>((const RIuint8*)data));
+ input.addReference();
+ try
+ {
+ if(context->m_scissoring)
+ drawable->getColorBuffer()->blit(input, 0, 0, dx, dy, width, height, context->m_scissor); //throws bad_alloc
+ else
+ drawable->getColorBuffer()->blit(input, 0, 0, dx, dy, width, height); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ input.removeReference();
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgGetPixels(VGImage dst, VGint dx, VGint dy, VGint sx, VGint sy, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(dst), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(eglvgIsInUse((Image*)dst), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Drawable* drawable = context->getCurrentDrawable();
+ if(!drawable)
+ {
+ RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
+ }
+ try
+ {
+ ((Image*)dst)->blit(drawable->getColorBuffer(), sx, sy, dx, dy, width, height); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgReadPixels(void* data, VGint dataStride, VGImageFormat dataFormat, VGint sx, VGint sy, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!isValidImageFormat(dataFormat), VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!data || !isAligned(data, dataFormat) || width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Drawable* drawable = context->getCurrentDrawable();
+ if(!drawable)
+ {
+ RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
+ }
+ {
+ Image output(Color::formatToDescriptor(dataFormat), width, height, dataStride, (RIuint8*)data);
+ output.addReference();
+ try
+ {
+ output.blit(drawable->getColorBuffer(), sx, sy, 0, 0, width, height); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ output.removeReference();
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgCopyPixels(VGint dx, VGint dy, VGint sx, VGint sy, VGint width, VGint height)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(width <= 0 || height <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Drawable* drawable = context->getCurrentDrawable();
+ if(!drawable)
+ {
+ RI_RETURN(RI_NO_RETVAL); //no EGL surface is current at the moment
+ }
+ try
+ {
+ if(context->m_scissoring)
+ drawable->getColorBuffer()->blit(drawable->getColorBuffer(), sx, sy, dx, dy, width, height, context->m_scissor); //throws bad_alloc
+ else
+ drawable->getColorBuffer()->blit(drawable->getColorBuffer(), sx, sy, dx, dy, width, height); //throws bad_alloc
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgColorMatrix(VGImage dst, VGImage src, const VGfloat * matrix)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ Image* d = (Image*)dst;
+ Image* s = (Image*)src;
+ RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!matrix || !isAligned(matrix,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
+
+ RIfloat m[20];
+ for(int i=0;i<20;i++)
+ {
+ m[i] = inputFloat(matrix[i]);
+ }
+ try
+ {
+ d->colorMatrix(*s, m, context->m_filterFormatLinear ? true : false, context->m_filterFormatPremultiplied ? true : false, channelMask);
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgConvolve(VGImage dst, VGImage src, VGint kernelWidth, VGint kernelHeight, VGint shiftX, VGint shiftY, const VGshort * kernel, VGfloat scale, VGfloat bias, VGTilingMode tilingMode)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ Image* d = (Image*)dst;
+ Image* s = (Image*)src;
+ RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!kernel || !isAligned(kernel,2) || kernelWidth <= 0 || kernelHeight <= 0 || kernelWidth > RI_MAX_KERNEL_SIZE || kernelHeight > RI_MAX_KERNEL_SIZE, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(tilingMode < VG_TILE_FILL || tilingMode > VG_TILE_REFLECT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
+ try
+ {
+ d->convolve(*s, kernelWidth, kernelHeight, shiftX, shiftY, (const RIint16*)kernel, inputFloat(scale), inputFloat(bias), tilingMode, context->m_tileFillColor, context->m_filterFormatLinear ? true : false, context->m_filterFormatPremultiplied ? true : false, channelMask);
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSeparableConvolve(VGImage dst, VGImage src, VGint kernelWidth, VGint kernelHeight, VGint shiftX, VGint shiftY, const VGshort * kernelX, const VGshort * kernelY, VGfloat scale, VGfloat bias, VGTilingMode tilingMode)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ Image* d = (Image*)dst;
+ Image* s = (Image*)src;
+ RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!kernelX || !kernelY || !isAligned(kernelX,2) || !isAligned(kernelY,2) || kernelWidth <= 0 || kernelHeight <= 0 || kernelWidth > RI_MAX_SEPARABLE_KERNEL_SIZE || kernelHeight > RI_MAX_SEPARABLE_KERNEL_SIZE, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(tilingMode < VG_TILE_FILL || tilingMode > VG_TILE_REFLECT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
+ try
+ {
+ d->separableConvolve(*s, kernelWidth, kernelHeight, shiftX, shiftY, (const RIint16*)kernelX, (const RIint16*)kernelY,
+ inputFloat(scale), inputFloat(bias), tilingMode, context->m_tileFillColor, context->m_filterFormatLinear ? true : false,
+ context->m_filterFormatPremultiplied ? true : false, channelMask);
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgGaussianBlur(VGImage dst, VGImage src, VGfloat stdDeviationX, VGfloat stdDeviationY, VGTilingMode tilingMode)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ Image* d = (Image*)dst;
+ Image* s = (Image*)src;
+ RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RIfloat sx = inputFloat(stdDeviationX);
+ RIfloat sy = inputFloat(stdDeviationY);
+ RI_IF_ERROR(sx <= 0.0f || sy <= 0.0f || sx > (RIfloat)RI_MAX_GAUSSIAN_STD_DEVIATION || sy > (RIfloat)RI_MAX_GAUSSIAN_STD_DEVIATION, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(tilingMode < VG_TILE_FILL || tilingMode > VG_TILE_REFLECT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
+ try
+ {
+ d->gaussianBlur(*s, sx, sy, tilingMode, context->m_tileFillColor, context->m_filterFormatLinear ? true : false,
+ context->m_filterFormatPremultiplied ? true : false, channelMask);
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgLookup(VGImage dst, VGImage src, const VGubyte * redLUT, const VGubyte * greenLUT, const VGubyte * blueLUT, const VGubyte * alphaLUT, VGboolean outputLinear, VGboolean outputPremultiplied)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ Image* d = (Image*)dst;
+ Image* s = (Image*)src;
+ RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!redLUT || !greenLUT || !blueLUT || !alphaLUT, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
+ try
+ {
+ d->lookup(*s, (const RIuint8*)redLUT, (const RIuint8*)greenLUT, (const RIuint8*)blueLUT, (const RIuint8*)alphaLUT,
+ outputLinear ? true : false, outputPremultiplied ? true : false, context->m_filterFormatLinear ? true : false,
+ context->m_filterFormatPremultiplied ? true : false, channelMask);
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgLookupSingle(VGImage dst, VGImage src, const VGuint * lookupTable, VGImageChannel sourceChannel, VGboolean outputLinear, VGboolean outputPremultiplied)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidImage(dst) || !context->isValidImage(src), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL);
+ Image* d = (Image*)dst;
+ Image* s = (Image*)src;
+ RI_IF_ERROR(eglvgIsInUse(d) || eglvgIsInUse(s), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(d->overlaps(s), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(!lookupTable || !isAligned(lookupTable,4), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ const Color::Descriptor& desc = s->getDescriptor();
+ RI_ASSERT(Color::isValidDescriptor(desc));
+ //give an error if src is in rgb format and the source channel is not valid
+ RI_IF_ERROR((!desc.isLuminance() && !desc.isAlphaOnly()) && (sourceChannel != VG_RED && sourceChannel != VG_GREEN && sourceChannel != VG_BLUE && sourceChannel != VG_ALPHA), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ unsigned int channelMask = context->m_filterChannelMask & (VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA); //undefined bits are ignored
+ try
+ {
+ d->lookupSingle(*s, (const RIuint32*)lookupTable, sourceChannel, outputLinear ? true : false, outputPremultiplied ? true : false,
+ context->m_filterFormatLinear ? true : false, context->m_filterFormatPremultiplied ? true : false, channelMask);
+ }
+ catch(std::bad_alloc)
+ {
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGHardwareQueryResult RI_APIENTRY vgHardwareQuery(VGHardwareQueryType key, VGint setting)
+{
+ RI_GET_CONTEXT(VG_HARDWARE_UNACCELERATED);
+ RI_IF_ERROR(key != VG_IMAGE_FORMAT_QUERY && key != VG_PATH_DATATYPE_QUERY, VG_ILLEGAL_ARGUMENT_ERROR, VG_HARDWARE_UNACCELERATED);
+ RI_IF_ERROR(key == VG_IMAGE_FORMAT_QUERY && !isValidImageFormat(setting), VG_ILLEGAL_ARGUMENT_ERROR, VG_HARDWARE_UNACCELERATED);
+ RI_IF_ERROR(key == VG_PATH_DATATYPE_QUERY && (setting < VG_PATH_DATATYPE_S_8 || setting > VG_PATH_DATATYPE_F), VG_ILLEGAL_ARGUMENT_ERROR, VG_HARDWARE_UNACCELERATED);
+ RI_RETURN(VG_HARDWARE_UNACCELERATED);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+const VGubyte * RI_APIENTRY vgGetString(VGStringID name)
+{
+ static const VGubyte vendor[] = "Khronos Group";
+ static const VGubyte renderer[] = {"OpenVG 1.1 Reference Implementation May 13 2008"};
+ static const VGubyte version[] = "1.1";
+ static const VGubyte extensions[] = "";
+ const VGubyte* r = NULL;
+ RI_GET_CONTEXT(NULL);
+ switch(name)
+ {
+ case VG_VENDOR:
+ r = vendor;
+ break;
+ case VG_RENDERER:
+ r = renderer;
+ break;
+ case VG_VERSION:
+ r = version;
+ break;
+ case VG_EXTENSIONS:
+ r = extensions;
+ break;
+ default:
+ break;
+ }
+ RI_RETURN(r);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+VGFont RI_APIENTRY vgCreateFont(VGint glyphCapacityHint)
+{
+ RI_GET_CONTEXT(VG_INVALID_HANDLE);
+ RI_IF_ERROR(glyphCapacityHint < 0, VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
+
+ Font* font = NULL;
+ try
+ {
+ font = RI_NEW(Font, (glyphCapacityHint)); //throws bad_alloc
+ RI_ASSERT(font);
+ context->m_fontManager->addResource(font, context); //throws bad_alloc
+ RI_RETURN((VGFont)font);
+ }
+ catch(std::bad_alloc)
+ {
+ RI_DELETE(font);
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ RI_RETURN(VG_INVALID_HANDLE);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgDestroyFont(VGFont font)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
+
+ context->m_fontManager->removeResource((Font*)font);
+
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetGlyphToPath(VGFont font, VGuint glyphIndex, VGPath path, VGboolean isHinted, VGfloat glyphOrigin[2], VGfloat escapement[2])
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
+ RI_IF_ERROR(path != VG_INVALID_HANDLE && !context->isValidPath(path), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid path handle
+ RI_IF_ERROR(!glyphOrigin || !escapement || !isAligned(glyphOrigin,sizeof(VGfloat)) || !isAligned(escapement,sizeof(VGfloat)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Font* f = (Font*)font;
+
+ try
+ {
+ f->setGlyphToPath(glyphIndex, path, isHinted ? true : false, Vector2(inputFloat(glyphOrigin[0]), inputFloat(glyphOrigin[1])), Vector2(inputFloat(escapement[0]), inputFloat(escapement[1])));
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgSetGlyphToImage(VGFont font, VGuint glyphIndex, VGImage image, VGfloat glyphOrigin[2], VGfloat escapement[2])
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
+ if(image != VG_INVALID_HANDLE)
+ {
+ RI_IF_ERROR(!context->isValidImage(image), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid image handle
+ RI_IF_ERROR(eglvgIsInUse((Image*)image), VG_IMAGE_IN_USE_ERROR, RI_NO_RETVAL); //image in use
+ }
+ RI_IF_ERROR(!glyphOrigin || !escapement || !isAligned(glyphOrigin,sizeof(VGfloat)) || !isAligned(escapement,sizeof(VGfloat)), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ Font* f = (Font*)font;
+
+ try
+ {
+ f->setGlyphToImage(glyphIndex, image, Vector2(inputFloat(glyphOrigin[0]), inputFloat(glyphOrigin[1])), Vector2(inputFloat(escapement[0]), inputFloat(escapement[1])));
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgClearGlyph(VGFont font, VGuint glyphIndex)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
+ Font* f = (Font*)font;
+ Font::Glyph* g = f->findGlyph(glyphIndex);
+ RI_IF_ERROR(!g, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //glyphIndex not defined
+
+ f->clearGlyph(g);
+
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgDrawGlyph(VGFont font, VGuint glyphIndex, VGbitfield paintModes, VGboolean allowAutoHinting)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
+ RI_IF_ERROR(paintModes & ~(VG_FILL_PATH | VG_STROKE_PATH), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid paint mode
+ Font* f = (Font*)font;
+ Font::Glyph* g = f->findGlyph(glyphIndex);
+ RI_IF_ERROR(!g, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //glyphIndex not defined
+ RI_UNREF(allowAutoHinting); //RI doesn't implement autohinting
+
+ try
+ {
+ if(paintModes)
+ {
+ Matrix3x3 userToSurfaceMatrix = context->m_glyphUserToSurface;
+ Vector2 t = context->m_glyphOrigin - g->m_origin;
+ Matrix3x3 n(1, 0, t.x,
+ 0, 1, t.y,
+ 0, 0, 1 );
+ userToSurfaceMatrix *= n;
+ userToSurfaceMatrix[2].set(0,0,1); //force affinity
+
+ bool ret = true;
+ if(g->m_image != VG_INVALID_HANDLE)
+ ret = drawImage(context, g->m_image, userToSurfaceMatrix);
+ else if(g->m_path != VG_INVALID_HANDLE)
+ ret = drawPath(context, g->m_path, userToSurfaceMatrix, paintModes);
+ if(!ret)
+ {
+ RI_RETURN(RI_NO_RETVAL);
+ }
+ }
+
+ context->m_glyphOrigin += g->m_escapement;
+ context->m_inputGlyphOrigin = context->m_glyphOrigin;
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+
+ RI_RETURN(RI_NO_RETVAL);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void RI_APIENTRY vgDrawGlyphs(VGFont font, VGint glyphCount, VGuint *glyphIndices, VGfloat *adjustments_x, VGfloat *adjustments_y, VGbitfield paintModes, VGboolean allowAutoHinting)
+{
+ RI_GET_CONTEXT(RI_NO_RETVAL);
+ RI_IF_ERROR(!context->isValidFont(font), VG_BAD_HANDLE_ERROR, RI_NO_RETVAL); //invalid font handle
+ RI_IF_ERROR(!glyphIndices || !isAligned(glyphIndices, sizeof(VGuint)) || glyphCount <= 0, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR((adjustments_x && !isAligned(adjustments_x, sizeof(VGfloat))) || (adjustments_y && !isAligned(adjustments_y, sizeof(VGfloat))), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL);
+ RI_IF_ERROR(paintModes & ~(VG_FILL_PATH | VG_STROKE_PATH), VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //invalid paint mode
+ Font* f = (Font*)font;
+ for(int i=0;i<glyphCount;i++)
+ {
+ Font::Glyph* g = f->findGlyph(glyphIndices[i]);
+ RI_IF_ERROR(!g, VG_ILLEGAL_ARGUMENT_ERROR, RI_NO_RETVAL); //glyphIndex not defined
+ }
+ RI_UNREF(allowAutoHinting); //RI doesn't implement autohinting
+
+ try
+ {
+ for(int i=0;i<glyphCount;i++)
+ {
+ Font::Glyph* g = f->findGlyph(glyphIndices[i]);
+
+ if(paintModes)
+ {
+ Matrix3x3 userToSurfaceMatrix = context->m_glyphUserToSurface;
+ Vector2 t = context->m_glyphOrigin - g->m_origin;
+ Matrix3x3 n(1, 0, t.x,
+ 0, 1, t.y,
+ 0, 0, 1 );
+ userToSurfaceMatrix *= n;
+ userToSurfaceMatrix[2].set(0,0,1); //force affinity
+
+ bool ret = true;
+ if(g->m_image != VG_INVALID_HANDLE)
+ ret = drawImage(context, g->m_image, userToSurfaceMatrix);
+ else if(g->m_path != VG_INVALID_HANDLE)
+ ret = drawPath(context, g->m_path, userToSurfaceMatrix, paintModes);
+ if(!ret)
+ {
+ RI_RETURN(RI_NO_RETVAL);
+ }
+ }
+
+ context->m_glyphOrigin += g->m_escapement;
+ if(adjustments_x)
+ context->m_glyphOrigin.x += inputFloat(adjustments_x[i]);
+ if(adjustments_y)
+ context->m_glyphOrigin.y += inputFloat(adjustments_y[i]);
+ context->m_inputGlyphOrigin = context->m_glyphOrigin;
+ }
+ }
+ catch(std::bad_alloc)
+ {
+ context->setError(VG_OUT_OF_MEMORY_ERROR);
+ }
+
+ RI_RETURN(RI_NO_RETVAL);
+}
diff --git a/src/vg/Image.cpp b/src/vg/Image.cpp
index 1d3c407..489b1e3 100644
--- a/src/vg/Image.cpp
+++ b/src/vg/Image.cpp
@@ -32,9 +32,14 @@
#include "Image.h"
#include "Rasterizer.h"
+#include <cairo/cairo-svg.h>
+
//==============================================================================================
+cairo_t *cr;
+cairo_surface_t *surface;
+
namespace tgOpenVG
{
@@ -1976,63 +1981,16 @@ void Surface::clear(const Color& clearColor, int x, int y, int w, int h, const A
if(!r.width || !r.height)
return; //intersection is empty or one of the rectangles is invalid
- Array<ScissorEdge> scissorEdges;
- for(int i=0;i<scissors.size();i++)
- {
- if(scissors[i].width > 0 && scissors[i].height > 0)
- {
- ScissorEdge e;
- e.miny = scissors[i].y;
- e.maxy = RI_INT_ADDSATURATE(scissors[i].y, scissors[i].height);
-
- e.x = scissors[i].x;
- e.direction = 1;
- scissorEdges.push_back(e); //throws bad_alloc
- e.x = RI_INT_ADDSATURATE(scissors[i].x, scissors[i].width);
- e.direction = -1;
- scissorEdges.push_back(e); //throws bad_alloc
- }
- }
- if(!scissorEdges.size())
- return; //there are no scissor rectangles => nothing is visible
-
- //sort scissor edges by edge x
- scissorEdges.sort();
-
- //clear the image
- Color col = clearColor;
- col.clamp();
- col.convert(m_image->getDescriptor().internalFormat);
+ cairo_set_source_rgb (cr, clearColor.r, clearColor.g, clearColor.b);
- Array<ScissorEdge> scissorAet;
- for(int j=r.y;j<r.y + r.height;j++)
- {
- //gather scissor edges intersecting this scanline
- scissorAet.clear();
- for(int e=0;e<scissorEdges.size();e++)
- {
- const ScissorEdge& se = scissorEdges[e];
- if(j >= se.miny && j < se.maxy)
- scissorAet.push_back(scissorEdges[e]); //throws bad_alloc
- }
- if(!scissorAet.size())
- continue; //scissoring is on, but there are no scissor rectangles on this scanline
-
- //clear a scanline
- int scissorWinding = 0;
- int scissorIndex = 0;
- for(int i=r.x;i<r.x + r.width;i++)
- {
- while(scissorIndex < scissorAet.size() && scissorAet[scissorIndex].x <= i)
- scissorWinding += scissorAet[scissorIndex++].direction;
- RI_ASSERT(scissorWinding >= 0);
+ cairo_new_path(cr);
- if(scissorWinding)
- {
- for(int s=0;s<m_numSamples;s++)
- writeSample(i, j, s, col);
- }
+ for(int i=0;i<scissors.size();i++) {
+ if(scissors[i].width > 0 && scissors[i].height > 0) {
+ cairo_rectangle(cr, (double) scissors[i].x, (double) scissors[i].y,
+ (double)scissors[i].width, (double)scissors[i].height);
}
+ cairo_fill(cr);
}
}
diff --git a/src/vg/Image.cpp.orig b/src/vg/Image.cpp.orig
new file mode 100644
index 0000000..5201757
--- /dev/null
+++ b/src/vg/Image.cpp.orig
@@ -0,0 +1,2680 @@
+/*------------------------------------------------------------------------
+ *
+ * OpenVG 1.1 Reference Implementation
+ * -----------------------------------
+ *
+ * Copyright (c) 2007 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and /or associated documentation files
+ * (the "Materials "), to deal in the Materials without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Materials,
+ * and to permit persons to whom the Materials are furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//**
+ * \file
+ * \brief Implementation of Color and Image functions.
+ * \note
+ *//*-------------------------------------------------------------------*/
+
+#include "Image.h"
+#include "Rasterizer.h"
+#include <cairo/cairo-svg.h>
+
+
+//==============================================================================================
+
+cairo_t *cr;
+cairo_surface_t *surface;
+
+namespace tgOpenVG
+{
+
+
+/*-------------------------------------------------------------------*//*!
+* \brief Converts from numBits into a shifted mask
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static unsigned int bitsToMask(unsigned int bits, unsigned int shift)
+{
+ return ((1<<bits)-1) << shift;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Converts from color (RIfloat) to an int with 1.0f mapped to the
+* given maximum with round-to-nearest semantics.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static unsigned int colorToInt(RIfloat c, int maxc)
+{
+ return RI_INT_MIN(RI_INT_MAX((int)floor(c * (RIfloat)maxc + 0.5f), 0), maxc);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Converts from int to color (RIfloat) with the given maximum
+* mapped to 1.0f.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static inline RIfloat intToColor(unsigned int i, unsigned int maxi)
+{
+ return (RIfloat)(i & maxi) / (RIfloat)maxi;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Converts from packed integer in a given format to a Color.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Color::unpack(unsigned int inputData, const Color::Descriptor& inputDesc)
+{
+ int rb = inputDesc.redBits;
+ int gb = inputDesc.greenBits;
+ int bb = inputDesc.blueBits;
+ int ab = inputDesc.alphaBits;
+ int lb = inputDesc.luminanceBits;
+ int rs = inputDesc.redShift;
+ int gs = inputDesc.greenShift;
+ int bs = inputDesc.blueShift;
+ int as = inputDesc.alphaShift;
+ int ls = inputDesc.luminanceShift;
+
+ m_format = inputDesc.internalFormat;
+ if(lb)
+ { //luminance
+ r = g = b = intToColor(inputData >> ls, (1<<lb)-1);
+ a = 1.0f;
+ }
+ else
+ { //rgba
+ r = rb ? intToColor(inputData >> rs, (1<<rb)-1) : (RIfloat)1.0f;
+ g = gb ? intToColor(inputData >> gs, (1<<gb)-1) : (RIfloat)1.0f;
+ b = bb ? intToColor(inputData >> bs, (1<<bb)-1) : (RIfloat)1.0f;
+ a = ab ? intToColor(inputData >> as, (1<<ab)-1) : (RIfloat)1.0f;
+
+ if(isPremultiplied())
+ { //clamp premultiplied color to alpha to enforce consistency
+ r = RI_MIN(r, a);
+ g = RI_MIN(g, a);
+ b = RI_MIN(b, a);
+ }
+ }
+
+ assertConsistency();
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Converts from Color to a packed integer in a given format.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+unsigned int Color::pack(const Color::Descriptor& outputDesc) const
+{
+ assertConsistency();
+
+ int rb = outputDesc.redBits;
+ int gb = outputDesc.greenBits;
+ int bb = outputDesc.blueBits;
+ int ab = outputDesc.alphaBits;
+ int lb = outputDesc.luminanceBits;
+ int rs = outputDesc.redShift;
+ int gs = outputDesc.greenShift;
+ int bs = outputDesc.blueShift;
+ int as = outputDesc.alphaShift;
+ int ls = outputDesc.luminanceShift;
+
+ if(lb)
+ { //luminance
+ RI_ASSERT(isLuminance());
+ return colorToInt(r, (1<<lb)-1) << ls;
+ }
+ else
+ { //rgb
+ RI_ASSERT(!isLuminance());
+ unsigned int cr = rb ? colorToInt(r, (1<<rb)-1) : 0;
+ unsigned int cg = gb ? colorToInt(g, (1<<gb)-1) : 0;
+ unsigned int cb = bb ? colorToInt(b, (1<<bb)-1) : 0;
+ unsigned int ca = ab ? colorToInt(a, (1<<ab)-1) : 0;
+ return (cr << rs) | (cg << gs) | (cb << bs) | (ca << as);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Converts from the current internal format to another.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static RIfloat gamma(RIfloat c)
+{
+ if( c <= 0.00304f )
+ c *= 12.92f;
+ else
+ c = 1.0556f * (RIfloat)pow(c, 1.0f/2.4f) - 0.0556f;
+ return c;
+}
+
+static RIfloat invgamma(RIfloat c)
+{
+ if( c <= 0.03928f )
+ c /= 12.92f;
+ else
+ c = (RIfloat)pow((c + 0.0556f)/1.0556f, 2.4f);
+ return c;
+}
+
+static RIfloat lRGBtoL(RIfloat r, RIfloat g, RIfloat b)
+{
+ return 0.2126f*r + 0.7152f*g + 0.0722f*b;
+}
+
+void Color::convert(InternalFormat outputFormat)
+{
+ assertConsistency();
+
+ if( m_format == outputFormat )
+ return;
+
+ if(isPremultiplied())
+ { //unpremultiply
+ RIfloat ooa = (a != 0.0f) ? 1.0f / a : (RIfloat)0.0f;
+ r *= ooa;
+ g *= ooa;
+ b *= ooa;
+ }
+
+ //From Section 3.4.2 of OpenVG spec
+ //1: sRGB = gamma(lRGB)
+ //2: lRGB = invgamma(sRGB)
+ //3: lL = 0.2126 lR + 0.7152 lG + 0.0722 lB
+ //4: lRGB = lL
+ //5: sL = gamma(lL)
+ //6: lL = invgamma(sL)
+ //7: sRGB = sL
+
+ //Source/Dest lRGB sRGB lL sL
+ //lRGB - 1 3 3,5
+ //sRGB 2 - 2,3 2,3,5
+ //lL 4 4,1 - 5
+ //sL 7,2 7 6 -
+
+ const unsigned int shift = 3;
+ unsigned int conversion = (m_format & (NONLINEAR | LUMINANCE)) | ((outputFormat & (NONLINEAR | LUMINANCE)) << shift);
+
+ switch(conversion)
+ {
+ case lRGBA | (sRGBA << shift): r = gamma(r); g = gamma(g); b = gamma(b); break; //1
+ case lRGBA | (lLA << shift) : r = g = b = lRGBtoL(r, g, b); break; //3
+ case lRGBA | (sLA << shift) : r = g = b = gamma(lRGBtoL(r, g, b)); break; //3,5
+ case sRGBA | (lRGBA << shift): r = invgamma(r); g = invgamma(g); b = invgamma(b); break; //2
+ case sRGBA | (lLA << shift) : r = g = b = lRGBtoL(invgamma(r), invgamma(g), invgamma(b)); break; //2,3
+ case sRGBA | (sLA << shift) : r = g = b = gamma(lRGBtoL(invgamma(r), invgamma(g), invgamma(b))); break;//2,3,5
+ case lLA | (lRGBA << shift): break; //4
+ case lLA | (sRGBA << shift): r = g = b = gamma(r); break; //4,1
+ case lLA | (sLA << shift) : r = g = b = gamma(r); break; //5
+ case sLA | (lRGBA << shift): r = g = b = invgamma(r); break; //7,2
+ case sLA | (sRGBA << shift): break; //7
+ case sLA | (lLA << shift) : r = g = b = invgamma(r); break; //6
+ default: RI_ASSERT((m_format & (LUMINANCE | NONLINEAR)) == (outputFormat & (LUMINANCE | NONLINEAR))); break; //nop
+ }
+
+ if(outputFormat & PREMULTIPLIED)
+ { //premultiply
+ r *= a;
+ g *= a;
+ b *= a;
+ }
+ m_format = outputFormat;
+
+ assertConsistency();
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Creates a pixel format descriptor out of VGImageFormat
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Color::Descriptor Color::formatToDescriptor(VGImageFormat format)
+{
+ Descriptor desc;
+ memset(&desc, 0, sizeof(Descriptor));
+ RI_ASSERT(isValidImageFormat(format));
+
+ int baseFormat = (int)format & 15;
+ const int numBaseFormats = 15;
+ RI_ASSERT(baseFormat >= 0 && baseFormat < numBaseFormats);
+ int swizzleBits = ((int)format >> 6) & 3;
+
+ /* base formats
+ VG_sRGBX_8888 = 0,
+ VG_sRGBA_8888 = 1,
+ VG_sRGBA_8888_PRE = 2,
+ VG_sRGB_565 = 3,
+ VG_sRGBA_5551 = 4,
+ VG_sRGBA_4444 = 5,
+ VG_sL_8 = 6,
+ VG_lRGBX_8888 = 7,
+ VG_lRGBA_8888 = 8,
+ VG_lRGBA_8888_PRE = 9,
+ VG_lL_8 = 10,
+ VG_A_8 = 11,
+ VG_BW_1 = 12,
+ VG_A_1 = 13,
+ VG_A_4 = 14,
+ */
+
+ static const int redBits[numBaseFormats] = {8, 8, 8, 5, 5, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0};
+ static const int greenBits[numBaseFormats] = {8, 8, 8, 6, 5, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0};
+ static const int blueBits[numBaseFormats] = {8, 8, 8, 5, 5, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0};
+ static const int alphaBits[numBaseFormats] = {0, 8, 8, 0, 1, 4, 0, 0, 8, 8, 0, 8, 0, 1, 4};
+ static const int luminanceBits[numBaseFormats] = {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 1, 0, 0};
+
+ static const int redShifts[4*numBaseFormats] = {24, 24, 24, 11, 11, 12, 0, 24, 24, 24, 0, 0, 0, 0, 0, //RGBA
+ 16, 16, 16, 11, 10, 8, 0, 16, 16, 16, 0, 0, 0, 0, 0, //ARGB
+ 8, 8, 8, 0, 1, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0, //BGRA
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //ABGR
+
+ static const int greenShifts[4*numBaseFormats] = {16, 16, 16, 5, 6, 8, 0, 16, 16, 16, 0, 0, 0, 0, 0, //RGBA
+ 8, 8, 8, 5, 5, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0, //ARGB
+ 16, 16, 16, 5, 6, 8, 0, 16, 16, 16, 0, 0, 0, 0, 0, //BGRA
+ 8, 8, 8, 5, 5, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0};//ABGR
+
+ static const int blueShifts[4*numBaseFormats] = {8, 8, 8, 0, 1, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0, //RGBA
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //ARGB
+ 24, 24, 24, 11, 11, 12, 0, 24, 24, 24, 0, 0, 0, 0, 0, //BGRA
+ 16, 16, 16, 11, 10, 8, 0, 16, 16, 16, 0, 0, 0, 0, 0};//ABGR
+
+ static const int alphaShifts[4*numBaseFormats] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //RGBA
+ 0, 24, 24, 0, 15, 12, 0, 0, 24, 24, 0, 0, 0, 0, 0, //ARGB
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //BGRA
+ 0, 24, 24, 0, 15, 12, 0, 0, 24, 24, 0, 0, 0, 0, 0};//ABGR
+
+ static const int bpps[numBaseFormats] = {32, 32, 32, 16, 16, 16, 8, 32, 32, 32, 8, 8, 1, 1, 4};
+
+ static const InternalFormat internalFormats[numBaseFormats] = {sRGBA, sRGBA, sRGBA_PRE, sRGBA, sRGBA, sRGBA, sLA, lRGBA, lRGBA, lRGBA_PRE, lLA, lRGBA, lLA, lRGBA, lRGBA};
+
+ desc.redBits = redBits[baseFormat];
+ desc.greenBits = greenBits[baseFormat];
+ desc.blueBits = blueBits[baseFormat];
+ desc.alphaBits = alphaBits[baseFormat];
+ desc.luminanceBits = luminanceBits[baseFormat];
+
+ desc.redShift = redShifts[swizzleBits * numBaseFormats + baseFormat];
+ desc.greenShift = greenShifts[swizzleBits * numBaseFormats + baseFormat];
+ desc.blueShift = blueShifts[swizzleBits * numBaseFormats + baseFormat];
+ desc.alphaShift = alphaShifts[swizzleBits * numBaseFormats + baseFormat];
+ desc.luminanceShift = 0; //always zero
+
+ desc.format = format;
+ desc.bitsPerPixel = bpps[baseFormat];
+ desc.internalFormat = internalFormats[baseFormat];
+
+ return desc;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Checks if the pixel format descriptor is valid (i.e. all the
+* values are supported by the RI)
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+bool Color::isValidDescriptor(const Color::Descriptor& desc)
+{
+ //A valid descriptor has 1, 2, 4, 8, 16, or 32 bits per pixel, and either luminance or rgba channels, but not both.
+ //Any of the rgba channels can be missing, and not all bits need to be used. Maximum channel bit depth is 8.
+ int rb = desc.redBits;
+ int gb = desc.greenBits;
+ int bb = desc.blueBits;
+ int ab = desc.alphaBits;
+ int lb = desc.luminanceBits;
+ int rs = desc.redShift;
+ int gs = desc.greenShift;
+ int bs = desc.blueShift;
+ int as = desc.alphaShift;
+ int ls = desc.luminanceShift;
+ int bpp = desc.bitsPerPixel;
+
+ int rgbaBits = rb + gb + bb + ab;
+ if(rb < 0 || rb > 8 || rs < 0 || rs + rb > bpp || !(rb || !rs))
+ return false; //invalid channel description
+ if(gb < 0 || gb > 8 || gs < 0 || gs + gb > bpp || !(gb || !gs))
+ return false; //invalid channel description
+ if(bb < 0 || bb > 8 || bs < 0 || bs + bb > bpp || !(bb || !bs))
+ return false; //invalid channel description
+ if(ab < 0 || ab > 8 || as < 0 || as + ab > bpp || !(ab || !as))
+ return false; //invalid channel description
+ if(lb < 0 || lb > 8 || ls < 0 || ls + lb > bpp || !(lb || !ls))
+ return false; //invalid channel description
+
+ if(rgbaBits && lb)
+ return false; //can't have both rgba and luminance
+ if(!rgbaBits && !lb)
+ return false; //must have either rgba or luminance
+ if(rgbaBits)
+ { //rgba
+ if(rb+gb+bb == 0)
+ { //alpha only
+ if(rs || gs || bs || as || ls)
+ return false; //wrong shifts (even alpha shift must be zero)
+ if((ab != 1 && ab != 2 && ab != 4 && ab != 8) || bpp != ab)
+ return false; //alpha size must be 1, 2, 4, or, 8, bpp must match
+ }
+ else
+ { //rgba
+ if(rgbaBits > bpp)
+ return false; //bpp must be greater than or equal to the sum of rgba bits
+ if(!(bpp == 32 || bpp == 16 || bpp == 8))
+ return false; //only 1, 2, and 4 byte formats are supported for rgba
+
+ unsigned int rm = bitsToMask((unsigned int)rb, (unsigned int)rs);
+ unsigned int gm = bitsToMask((unsigned int)gb, (unsigned int)gs);
+ unsigned int bm = bitsToMask((unsigned int)bb, (unsigned int)bs);
+ unsigned int am = bitsToMask((unsigned int)ab, (unsigned int)as);
+ if((rm & gm) || (rm & bm) || (rm & am) || (gm & bm) || (gm & am) || (bm & am))
+ return false; //channels overlap
+ }
+ }
+ else
+ { //luminance
+ if(rs || gs || bs || as || ls)
+ return false; //wrong shifts (even luminance shift must be zero)
+ if(!(lb == 1 || lb == 8) || bpp != lb)
+ return false; //luminance size must be either 1 or 8, bpp must match
+ }
+
+ if(desc.format != -1)
+ {
+ if(!isValidImageFormat(desc.format))
+ return false; //invalid image format
+
+ Descriptor d = formatToDescriptor(desc.format);
+ if(d.redBits != rb || d.greenBits != gb || d.blueBits != bb || d.alphaBits != ab || d.luminanceBits != lb ||
+ d.redShift != rs || d.greenShift != gs || d.blueShift != bs || d.alphaShift != as || d.luminanceShift != ls ||
+ d.bitsPerPixel != bpp)
+ return false; //if the descriptor has a VGImageFormat, it must match the bits, shifts, and bpp
+ }
+
+ if((unsigned int)desc.internalFormat & ~(Color::PREMULTIPLIED | Color::NONLINEAR | Color::LUMINANCE))
+ return false; //invalid internal format
+
+ return true;
+}
+
+//==============================================================================================
+
+
+
+
+//==============================================================================================
+
+/*-------------------------------------------------------------------*//*!
+* \brief Constructs a blank image.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Image::Image(const Color::Descriptor& desc, int width, int height, VGbitfield allowedQuality) :
+ m_desc(desc),
+ m_width(width),
+ m_height(height),
+ m_allowedQuality(allowedQuality),
+ m_inUse(0),
+ m_stride(0),
+ m_data(NULL),
+ m_referenceCount(0),
+ m_ownsData(true),
+ m_parent(NULL),
+ m_storageOffsetX(0),
+ m_storageOffsetY(0),
+ m_mipmapsValid(false),
+ m_mipmaps()
+{
+ RI_ASSERT(Color::isValidDescriptor(m_desc));
+ RI_ASSERT(width > 0 && height > 0);
+
+ m_stride = (m_width*m_desc.bitsPerPixel+7)/8;
+
+ m_data = RI_NEW_ARRAY(RIuint8, m_stride*m_height); //throws bad_alloc
+ memset(m_data, 0, m_stride*m_height); //clear image
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Constructs an image that uses an external array for its data
+* storage.
+* \param
+* \return
+* \note this is meant for internal use to make blitting easier
+*//*-------------------------------------------------------------------*/
+
+Image::Image(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data) :
+ m_desc(desc),
+ m_width(width),
+ m_height(height),
+ m_allowedQuality(0),
+ m_inUse(0),
+ m_stride(stride),
+ m_data(data),
+ m_referenceCount(0),
+ m_ownsData(false),
+ m_parent(NULL),
+ m_storageOffsetX(0),
+ m_storageOffsetY(0),
+ m_mipmapsValid(false),
+ m_mipmaps()
+{
+ RI_ASSERT(Color::isValidDescriptor(m_desc));
+ RI_ASSERT(width > 0 && height > 0);
+ RI_ASSERT(data);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Construcs a child image.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Image::Image(Image* parent, int x, int y, int width, int height) :
+ m_desc(Color::formatToDescriptor(VG_sRGBA_8888)), //dummy initialization, will be overwritten below (can't read from parent->m_desc before knowing the pointer is valid)
+ m_width(width),
+ m_height(height),
+ m_allowedQuality(0),
+ m_inUse(0),
+ m_stride(0),
+ m_data(NULL),
+ m_referenceCount(0),
+ m_ownsData(false),
+ m_parent(parent),
+ m_storageOffsetX(0),
+ m_storageOffsetY(0),
+ m_mipmapsValid(false),
+ m_mipmaps()
+{
+ RI_ASSERT(parent);
+ RI_ASSERT(x >= 0 && y >= 0 && width > 0 && height > 0);
+ RI_ASSERT(RI_INT_ADDSATURATE(x,width) <= parent->m_width && RI_INT_ADDSATURATE(y,height) <= parent->m_height); //child image must be contained in parent
+
+ m_desc = parent->m_desc;
+ RI_ASSERT(Color::isValidDescriptor(m_desc));
+ m_allowedQuality = parent->m_allowedQuality;
+ m_stride = parent->m_stride;
+ m_data = parent->m_data;
+ m_storageOffsetX = parent->m_storageOffsetX + x;
+ m_storageOffsetY = parent->m_storageOffsetY + y;
+
+ //increase the reference and use count of the parent
+ addInUse();
+ parent->addInUse();
+ parent->addReference();
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Image destructor.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Image::~Image()
+{
+ RI_ASSERT(m_referenceCount == 0);
+
+ if(m_parent)
+ {
+ //decrease the reference and use count of the parent
+ removeInUse();
+ m_parent->removeInUse();
+ if(!m_parent->removeReference())
+ RI_DELETE(m_parent);
+ }
+ RI_ASSERT(m_inUse == 0);
+
+ for(int i=0;i<m_mipmaps.size();i++)
+ {
+ if(!m_mipmaps[i]->removeReference())
+ RI_DELETE(m_mipmaps[i]);
+ else
+ {
+ RI_ASSERT(0); //there can't be any other references to the mipmap levels
+ }
+ }
+ m_mipmaps.clear();
+
+ if(m_ownsData)
+ {
+ RI_ASSERT(!m_parent); //can't have parent if owns the data
+ RI_DELETE_ARRAY(m_data); //delete image data if we own it
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Returns true if the two images share pixels.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+bool Image::overlaps(const Image* src) const
+{
+ RI_ASSERT(src);
+
+ if(m_data != src->m_data)
+ return false; //images don't share data
+
+ //check if the image storage regions overlap
+ Rectangle r(m_storageOffsetX, m_storageOffsetY, m_width, m_height);
+ r.intersect(Rectangle(src->m_storageOffsetX, src->m_storageOffsetY, src->m_width, src->m_height));
+ if(!r.width || !r.height)
+ return false; //intersection is empty, images don't overlap
+
+ return true;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Clears a rectangular portion of an image with the given clear color.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Image::clear(const Color& clearColor, int x, int y, int w, int h)
+{
+ RI_ASSERT(m_data);
+ RI_ASSERT(m_referenceCount > 0);
+
+ //intersect clear region with image bounds
+ Rectangle r(0,0,m_width,m_height);
+ r.intersect(Rectangle(x,y,w,h));
+ if(!r.width || !r.height)
+ return; //intersection is empty or one of the rectangles is invalid
+
+ Color col = clearColor;
+ col.clamp();
+ col.convert(m_desc.internalFormat);
+
+ for(int j=r.y;j<r.y + r.height;j++)
+ {
+ for(int i=r.x;i<r.x + r.width;i++)
+ {
+ writePixel(i, j, col);
+ }
+ }
+
+ m_mipmapsValid = false;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Blits a source region to destination. Source and destination
+* can overlap.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static RIfloat ditherChannel(RIfloat c, int bits, RIfloat m)
+{
+ RIfloat fc = c * (RIfloat)((1<<bits)-1);
+ RIfloat ic = (RIfloat)floor(fc);
+ if(fc - ic > m) ic += 1.0f;
+ return RI_MIN(ic / (RIfloat)((1<<bits)-1), 1.0f);
+}
+
+static void computeBlitRegion(int& sx, int& sy, int& dx, int& dy, int& w, int& h, int srcWidth, int srcHeight, int dstWidth, int dstHeight)
+{
+ RI_ASSERT(w > 0 && h > 0);
+ sx = RI_INT_MIN(RI_INT_MAX(sx, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
+ sy = RI_INT_MIN(RI_INT_MAX(sy, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
+ dx = RI_INT_MIN(RI_INT_MAX(dx, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
+ dy = RI_INT_MIN(RI_INT_MAX(dy, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
+ w = RI_INT_MIN(w, (int)(RI_INT32_MAX>>2));
+ h = RI_INT_MIN(h, (int)(RI_INT32_MAX>>2));
+ int srcsx = sx, srcex = sx + w, dstsx = dx, dstex = dx + w;
+ if(srcsx < 0)
+ {
+ dstsx -= srcsx;
+ srcsx = 0;
+ }
+ if(srcex > srcWidth)
+ {
+ dstex -= srcex - srcWidth;
+ srcex = srcWidth;
+ }
+ if(dstsx < 0)
+ {
+ srcsx -= dstsx;
+ dstsx = 0;
+ }
+ if(dstex > dstWidth)
+ {
+ srcex -= dstex - dstWidth;
+ dstex = dstWidth;
+ }
+ RI_ASSERT(srcsx >= 0 && dstsx >= 0 && srcex <= srcWidth && dstex <= dstWidth);
+ w = srcex - srcsx;
+ RI_ASSERT(w == dstex - dstsx);
+
+ int srcsy = sy, srcey = sy + h, dstsy = dy, dstey = dy + h;
+ if(srcsy < 0)
+ {
+ dstsy -= srcsy;
+ srcsy = 0;
+ }
+ if(srcey > srcHeight)
+ {
+ dstey -= srcey - srcHeight;
+ srcey = srcHeight;
+ }
+ if(dstsy < 0)
+ {
+ srcsy -= dstsy;
+ dstsy = 0;
+ }
+ if(dstey > dstHeight)
+ {
+ srcey -= dstey - dstHeight;
+ dstey = dstHeight;
+ }
+ RI_ASSERT(srcsy >= 0 && dstsy >= 0 && srcey <= srcHeight && dstey <= dstHeight);
+ h = srcey - srcsy;
+ RI_ASSERT(h == dstey - dstsy);
+ sx = srcsx;
+ sy = srcsy;
+ dx = dstsx;
+ dy = dstsy;
+}
+
+void Image::blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h, bool dither)
+{
+ //img=>img: vgCopyImage
+ //img=>user: vgGetImageSubData
+ //user=>img: vgImageSubData
+ RI_ASSERT(src.m_data); //source exists
+ RI_ASSERT(m_data); //destination exists
+ RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
+
+ computeBlitRegion(sx, sy, dx, dy, w, h, src.m_width, src.m_height, m_width, m_height);
+ if(w <= 0 || h <= 0)
+ return; //zero area
+
+ Array<Color> tmp;
+ tmp.resize(w*h); //throws bad_alloc
+
+ //copy source region to tmp
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ Color c = src.readPixel(sx + i, sy + j);
+ c.convert(m_desc.internalFormat);
+ tmp[j*w+i] = c;
+ }
+ }
+
+ int rbits = m_desc.redBits, gbits = m_desc.greenBits, bbits = m_desc.blueBits, abits = m_desc.alphaBits;
+ if(m_desc.isLuminance())
+ {
+ rbits = gbits = bbits = m_desc.luminanceBits;
+ abits = 0;
+ }
+
+ //write tmp to destination region
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ Color col = tmp[j*w+i];
+
+ if(dither)
+ {
+ static const int matrix[16] = {
+ 0, 8, 2, 10,
+ 12, 4, 14, 6,
+ 3, 11, 1, 9,
+ 15, 7, 13, 5};
+ int x = i & 3;
+ int y = j & 3;
+ RIfloat m = matrix[y*4+x] / 16.0f;
+
+ if(rbits) col.r = ditherChannel(col.r, rbits, m);
+ if(gbits) col.g = ditherChannel(col.g, gbits, m);
+ if(bbits) col.b = ditherChannel(col.b, bbits, m);
+ if(abits) col.a = ditherChannel(col.a, abits, m);
+ }
+
+ writePixel(dx + i, dy + j, col);
+ }
+ }
+ m_mipmapsValid = false;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Converts from multisampled format to display format.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Image::blit(const Surface* src, int sx, int sy, int dx, int dy, int w, int h)
+{
+ //fb=>img: vgGetPixels
+ //fb=>user: vgReadPixels
+ RI_ASSERT(!src->isInUse(this));
+
+ computeBlitRegion(sx, sy, dx, dy, w, h, src->getWidth(), src->getHeight(), m_width, m_height);
+ if(w <= 0 || h <= 0)
+ return; //zero area
+
+ for(int y=0;y<h;y++)
+ {
+ for(int x=0;x<w;x++)
+ {
+ Color r = src->FSAAResolve(sx + x, sy + y);
+ r.convert(getDescriptor().internalFormat);
+ writePixel(dx + x, dy + y, r);
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Returns the color at pixel (x,y).
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Color Image::readPixel(int x, int y) const
+{
+ RI_ASSERT(m_data);
+ RI_ASSERT(x >= 0 && x < m_width);
+ RI_ASSERT(y >= 0 && y < m_height);
+ RI_ASSERT(m_referenceCount > 0);
+ x += m_storageOffsetX;
+ y += m_storageOffsetY;
+
+ unsigned int p = 0;
+ RIuint8* scanline = m_data + y * m_stride;
+ switch(m_desc.bitsPerPixel)
+ {
+ case 32:
+ {
+ RIuint32* s = (((RIuint32*)scanline) + x);
+ p = (unsigned int)*s;
+ break;
+ }
+
+ case 16:
+ {
+ RIuint16* s = ((RIuint16*)scanline) + x;
+ p = (unsigned int)*s;
+ break;
+ }
+
+ case 8:
+ {
+ RIuint8* s = ((RIuint8*)scanline) + x;
+ p = (unsigned int)*s;
+ break;
+ }
+
+ case 4:
+ {
+ RIuint8* s = ((RIuint8*)scanline) + (x>>1);
+ p = (unsigned int)(*s >> ((x&1)<<2)) & 0xf;
+ break;
+ }
+
+ case 2:
+ {
+ RIuint8* s = ((RIuint8*)scanline) + (x>>2);
+ p = (unsigned int)(*s >> ((x&3)<<1)) & 0x3;
+ break;
+ }
+
+ default:
+ {
+ RI_ASSERT(m_desc.bitsPerPixel == 1);
+ RIuint8* s = ((RIuint8*)scanline) + (x>>3);
+ p = (unsigned int)(*s >> (x&7)) & 0x1;
+ break;
+ }
+ }
+ Color c;
+ c.unpack(p, m_desc);
+ return c;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Writes the color to pixel (x,y). Internal color formats must
+* match.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Image::writePixel(int x, int y, const Color& c)
+{
+ RI_ASSERT(m_data);
+ RI_ASSERT(x >= 0 && x < m_width);
+ RI_ASSERT(y >= 0 && y < m_height);
+ RI_ASSERT(m_referenceCount > 0);
+ RI_ASSERT(c.getInternalFormat() == m_desc.internalFormat);
+ x += m_storageOffsetX;
+ y += m_storageOffsetY;
+
+ unsigned int p = c.pack(m_desc);
+ RIuint8* scanline = m_data + y * m_stride;
+ switch(m_desc.bitsPerPixel)
+ {
+ case 32:
+ {
+ RIuint32* s = ((RIuint32*)scanline) + x;
+ *s = (RIuint32)p;
+ break;
+ }
+
+ case 16:
+ {
+ RIuint16* s = ((RIuint16*)scanline) + x;
+ *s = (RIuint16)p;
+ break;
+ }
+
+ case 8:
+ {
+ RIuint8* s = ((RIuint8*)scanline) + x;
+ *s = (RIuint8)p;
+ break;
+ }
+ case 4:
+ {
+ RIuint8* s = ((RIuint8*)scanline) + (x>>1);
+ *s = (RIuint8)((p << ((x&1)<<2)) | ((unsigned int)*s & ~(0xf << ((x&1)<<2))));
+ break;
+ }
+
+ case 2:
+ {
+ RIuint8* s = ((RIuint8*)scanline) + (x>>2);
+ *s = (RIuint8)((p << ((x&3)<<1)) | ((unsigned int)*s & ~(0x3 << ((x&3)<<1))));
+ break;
+ }
+
+ default:
+ {
+ RI_ASSERT(m_desc.bitsPerPixel == 1);
+ RIuint8* s = ((RIuint8*)scanline) + (x>>3);
+ *s = (RIuint8)((p << (x&7)) | ((unsigned int)*s & ~(0x1 << (x&7))));
+ break;
+ }
+ }
+ m_mipmapsValid = false;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Writes a filtered color to destination surface
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Image::writeFilteredPixel(int i, int j, const Color& color, VGbitfield channelMask)
+{
+ //section 3.4.4: before color space conversion, premultiplied colors are
+ //clamped to alpha, and the color is converted to nonpremultiplied format
+ //section 11.2: how to deal with channel mask
+ //step 1
+ Color f = color;
+ f.clamp(); //vgColorMatrix and vgLookups can produce colors that exceed alpha or [0,1] range
+
+ //step 2: color space conversion
+ f.convert((Color::InternalFormat)(m_desc.internalFormat & (Color::NONLINEAR | Color::LUMINANCE)));
+
+ //step 3: read the destination color and convert it to nonpremultiplied
+ Color d = readPixel(i,j);
+ d.unpremultiply();
+ RI_ASSERT(d.getInternalFormat() == f.getInternalFormat());
+
+ //step 4: replace the destination channels specified by the channelMask (channelmask is ignored for luminance formats)
+ if(!m_desc.isLuminance())
+ { //rgba format => use channelmask
+ if(channelMask & VG_RED)
+ d.r = f.r;
+ if(channelMask & VG_GREEN)
+ d.g = f.g;
+ if(channelMask & VG_BLUE)
+ d.b = f.b;
+ if(channelMask & VG_ALPHA)
+ d.a = f.a;
+ }
+ else d = f;
+
+ //step 5: if destination is premultiplied, convert to premultiplied format
+ if(m_desc.isPremultiplied())
+ d.premultiply();
+ //write the color to destination
+ writePixel(i,j,d);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Reads the pixel (x,y) and converts it into an alpha mask value.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+RIfloat Image::readMaskPixel(int x, int y) const
+{
+ RI_ASSERT(m_data);
+ RI_ASSERT(x >= 0 && x < m_width);
+ RI_ASSERT(y >= 0 && y < m_height);
+ RI_ASSERT(m_referenceCount > 0);
+
+ Color c = readPixel(x,y);
+ if(m_desc.isLuminance())
+ {
+ return c.r;
+ }
+ else
+ { //rgba
+ if(m_desc.alphaBits)
+ return c.a;
+ return c.r;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Writes the alpha mask to pixel (x,y).
+* \param
+* \return
+* \note Overwrites color.
+*//*-------------------------------------------------------------------*/
+
+void Image::writeMaskPixel(int x, int y, RIfloat m)
+{
+ RI_ASSERT(m_data);
+ RI_ASSERT(x >= 0 && x < m_width);
+ RI_ASSERT(y >= 0 && y < m_height);
+ RI_ASSERT(m_referenceCount > 0);
+
+ //if luminance or no alpha, red channel will be used, otherwise alpha channel will be used
+ writePixel(x, y, Color(m,m,m,m,m_desc.internalFormat));
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Reads a texel (u,v) at the given mipmap level. Tiling modes and
+* color space conversion are applied. Outputs color in premultiplied
+* format.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Color Image::readTexel(int u, int v, int level, VGTilingMode tilingMode, const Color& tileFillColor) const
+{
+ const Image* image = this;
+ if( level > 0 )
+ {
+ RI_ASSERT(level <= m_mipmaps.size());
+ image = m_mipmaps[level-1];
+ }
+ RI_ASSERT(image);
+
+ Color p;
+ if(tilingMode == VG_TILE_FILL)
+ {
+ if(u < 0 || v < 0 || u >= image->m_width || v >= image->m_height)
+ p = tileFillColor;
+ else
+ p = image->readPixel(u, v);
+ }
+ else if(tilingMode == VG_TILE_PAD)
+ {
+ u = RI_INT_MIN(RI_INT_MAX(u,0),image->m_width-1);
+ v = RI_INT_MIN(RI_INT_MAX(v,0),image->m_height-1);
+ p = image->readPixel(u, v);
+ }
+ else if(tilingMode == VG_TILE_REPEAT)
+ {
+ u = RI_INT_MOD(u, image->m_width);
+ v = RI_INT_MOD(v, image->m_height);
+ p = image->readPixel(u, v);
+ }
+ else
+ {
+ RI_ASSERT(tilingMode == VG_TILE_REFLECT);
+
+ u = RI_INT_MOD(u, image->m_width*2);
+ v = RI_INT_MOD(v, image->m_height*2);
+ if( u >= image->m_width ) u = image->m_width*2-1 - u;
+ if( v >= image->m_height ) v = image->m_height*2-1 - v;
+ p = image->readPixel(u, v);
+ }
+
+ p.premultiply(); //interpolate in premultiplied format
+ return p;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Maps point (x,y) to an image and returns a filtered,
+* premultiplied color value.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Color Image::resample(RIfloat x, RIfloat y, const Matrix3x3& surfaceToImage, VGImageQuality quality, VGTilingMode tilingMode, const Color& tileFillColor) //throws bad_alloc
+{
+ RI_ASSERT(m_referenceCount > 0);
+
+ VGbitfield aq = getAllowedQuality();
+ aq &= (VGbitfield)quality;
+
+ Vector3 uvw(x,y,1.0f);
+ uvw = surfaceToImage * uvw;
+ RIfloat oow = 1.0f / uvw.z;
+ uvw *= oow;
+
+ if(aq & VG_IMAGE_QUALITY_BETTER)
+ { //EWA on mipmaps
+ makeMipMaps(); //throws bad_alloc
+
+ Color::InternalFormat procFormat = (Color::InternalFormat)(m_desc.internalFormat | Color::PREMULTIPLIED);
+
+ RIfloat m_pixelFilterRadius = 1.25f;
+ RIfloat m_resamplingFilterRadius = 1.25f;
+
+ RIfloat Ux = (surfaceToImage[0][0] - uvw.x * surfaceToImage[2][0]) * oow * m_pixelFilterRadius;
+ RIfloat Vx = (surfaceToImage[1][0] - uvw.y * surfaceToImage[2][0]) * oow * m_pixelFilterRadius;
+ RIfloat Uy = (surfaceToImage[0][1] - uvw.x * surfaceToImage[2][1]) * oow * m_pixelFilterRadius;
+ RIfloat Vy = (surfaceToImage[1][1] - uvw.y * surfaceToImage[2][1]) * oow * m_pixelFilterRadius;
+ RIfloat U0 = uvw.x;
+ RIfloat V0 = uvw.y;
+
+ //calculate mip level
+ int level = 0;
+ RIfloat axis1sq = Ux*Ux + Vx*Vx;
+ RIfloat axis2sq = Uy*Uy + Vy*Vy;
+ RIfloat minorAxissq = RI_MIN(axis1sq,axis2sq);
+ while(minorAxissq > 9.0f && level < m_mipmaps.size()) //half the minor axis must be at least three texels
+ {
+ level++;
+ minorAxissq *= 0.25f;
+ }
+
+ RIfloat sx = 1.0f;
+ RIfloat sy = 1.0f;
+ if(level > 0)
+ {
+ sx = (RIfloat)m_mipmaps[level-1]->m_width / (RIfloat)m_width;
+ sy = (RIfloat)m_mipmaps[level-1]->m_height / (RIfloat)m_height;
+ }
+ Ux *= sx;
+ Vx *= sx;
+ U0 *= sx;
+ Uy *= sy;
+ Vy *= sy;
+ V0 *= sy;
+
+ //clamp filter size so that filtering doesn't take excessive amount of time (clamping results in aliasing)
+ RIfloat lim = 100.0f;
+ axis1sq = Ux*Ux + Vx*Vx;
+ axis2sq = Uy*Uy + Vy*Vy;
+ if( axis1sq > lim*lim )
+ {
+ RIfloat s = lim / (RIfloat)sqrt(axis1sq);
+ Ux *= s;
+ Vx *= s;
+ }
+ if( axis2sq > lim*lim )
+ {
+ RIfloat s = lim / (RIfloat)sqrt(axis2sq);
+ Uy *= s;
+ Vy *= s;
+ }
+
+
+ //form elliptic filter by combining texel and pixel filters
+ RIfloat A = Vx*Vx + Vy*Vy + 1.0f;
+ RIfloat B = -2.0f*(Ux*Vx + Uy*Vy);
+ RIfloat C = Ux*Ux + Uy*Uy + 1.0f;
+ //scale by the user-defined size of the kernel
+ A *= m_resamplingFilterRadius;
+ B *= m_resamplingFilterRadius;
+ C *= m_resamplingFilterRadius;
+
+ //calculate bounding box in texture space
+ RIfloat usize = (RIfloat)sqrt(C);
+ RIfloat vsize = (RIfloat)sqrt(A);
+ int u1 = (int)floor(U0 - usize + 0.5f);
+ int u2 = (int)floor(U0 + usize + 0.5f);
+ int v1 = (int)floor(V0 - vsize + 0.5f);
+ int v2 = (int)floor(V0 + vsize + 0.5f);
+ if( u1 == u2 || v1 == v2 )
+ return Color(0,0,0,0,procFormat);
+
+ //scale the filter so that Q = 1 at the cutoff radius
+ RIfloat F = A*C - 0.25f * B*B;
+ if( F <= 0.0f )
+ return Color(0,0,0,0,procFormat); //invalid filter shape due to numerical inaccuracies => return black
+ RIfloat ooF = 1.0f / F;
+ A *= ooF;
+ B *= ooF;
+ C *= ooF;
+
+ //evaluate filter by using forward differences to calculate Q = A*U^2 + B*U*V + C*V^2
+ Color color(0,0,0,0,procFormat);
+ RIfloat sumweight = 0.0f;
+ RIfloat DDQ = 2.0f * A;
+ RIfloat U = (RIfloat)u1 - U0 + 0.5f;
+ for(int v=v1;v<v2;v++)
+ {
+ RIfloat V = (RIfloat)v - V0 + 0.5f;
+ RIfloat DQ = A*(2.0f*U+1.0f) + B*V;
+ RIfloat Q = (C*V+B*U)*V + A*U*U;
+ for(int u=u1;u<u2;u++)
+ {
+ if( Q >= 0.0f && Q < 1.0f )
+ { //Q = r^2, fit gaussian to the range [0,1]
+ RIfloat weight = (RIfloat)exp(-0.5f * 10.0f * Q); //gaussian at radius 10 equals 0.0067
+ color += weight * readTexel(u, v, level, tilingMode, tileFillColor);
+ sumweight += weight;
+ }
+ Q += DQ;
+ DQ += DDQ;
+ }
+ }
+ if( sumweight == 0.0f )
+ return Color(0,0,0,0,procFormat);
+ RI_ASSERT(sumweight > 0.0f);
+ sumweight = 1.0f / sumweight;
+ return color * sumweight;
+ }
+ else if(aq & VG_IMAGE_QUALITY_FASTER)
+ { //bilinear
+ uvw.x -= 0.5f;
+ uvw.y -= 0.5f;
+ int u = (int)floor(uvw.x);
+ int v = (int)floor(uvw.y);
+ Color c00 = readTexel(u,v, 0, tilingMode, tileFillColor);
+ Color c10 = readTexel(u+1,v, 0, tilingMode, tileFillColor);
+ Color c01 = readTexel(u,v+1, 0, tilingMode, tileFillColor);
+ Color c11 = readTexel(u+1,v+1, 0, tilingMode, tileFillColor);
+ RIfloat fu = uvw.x - (RIfloat)u;
+ RIfloat fv = uvw.y - (RIfloat)v;
+ Color c0 = c00 * (1.0f - fu) + c10 * fu;
+ Color c1 = c01 * (1.0f - fu) + c11 * fu;
+ return c0 * (1.0f - fv) + c1 * fv;
+ }
+ else
+ { //point sampling
+ return readTexel((int)floor(uvw.x), (int)floor(uvw.y), 0, tilingMode, tileFillColor);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Generates mip maps for an image.
+* \param
+* \return
+* \note Downsampling is done in the input color space. We use a box
+* filter for downsampling.
+*//*-------------------------------------------------------------------*/
+
+void Image::makeMipMaps()
+{
+ RI_ASSERT(m_data);
+ RI_ASSERT(m_referenceCount > 0);
+
+ if(m_mipmapsValid)
+ return;
+
+ //delete existing mipmaps
+ for(int i=0;i<m_mipmaps.size();i++)
+ {
+ if(!m_mipmaps[i]->removeReference())
+ RI_DELETE(m_mipmaps[i]);
+ else
+ {
+ RI_ASSERT(0); //there can't be any other references to the mipmap levels
+ }
+ }
+ m_mipmaps.clear();
+
+ try
+ {
+ Color::InternalFormat procFormat = m_desc.internalFormat;
+ procFormat = (Color::InternalFormat)(procFormat | Color::PREMULTIPLIED); //premultiplied
+
+ //generate mipmaps until width and height are one
+ Image* prev = this;
+ while( prev->m_width > 1 || prev->m_height > 1 )
+ {
+ int nextw = (int)ceil(prev->m_width*0.5f);
+ int nexth = (int)ceil(prev->m_height*0.5f);
+ RI_ASSERT(nextw >= 1 && nexth >= 1);
+ RI_ASSERT(nextw < prev->m_width || nexth < prev->m_height);
+
+ m_mipmaps.resize(m_mipmaps.size()+1); //throws bad_alloc
+ m_mipmaps[m_mipmaps.size()-1] = NULL;
+
+ Image* next = RI_NEW(Image, (m_desc, nextw, nexth, m_allowedQuality)); //throws bad_alloc
+ next->addReference();
+ for(int j=0;j<next->m_height;j++)
+ {
+ for(int i=0;i<next->m_width;i++)
+ {
+ RIfloat u0 = (RIfloat)i / (RIfloat)next->m_width;
+ RIfloat u1 = (RIfloat)(i+1) / (RIfloat)next->m_width;
+ RIfloat v0 = (RIfloat)j / (RIfloat)next->m_height;
+ RIfloat v1 = (RIfloat)(j+1) / (RIfloat)next->m_height;
+
+ u0 *= prev->m_width;
+ u1 *= prev->m_width;
+ v0 *= prev->m_height;
+ v1 *= prev->m_height;
+
+ int su = (int)floor(u0);
+ int eu = (int)ceil(u1);
+ int sv = (int)floor(v0);
+ int ev = (int)ceil(v1);
+
+ Color c(0,0,0,0,procFormat);
+ int samples = 0;
+ for(int y=sv;y<ev;y++)
+ {
+ for(int x=su;x<eu;x++)
+ {
+ Color p = prev->readPixel(x, y);
+ p.convert(procFormat);
+ c += p;
+ samples++;
+ }
+ }
+ c *= (1.0f/samples);
+ c.convert(m_desc.internalFormat);
+ next->writePixel(i,j,c);
+ }
+ }
+ m_mipmaps[m_mipmaps.size()-1] = next;
+ prev = next;
+ }
+ RI_ASSERT(prev->m_width == 1 && prev->m_height == 1);
+ m_mipmapsValid = true;
+ }
+ catch(std::bad_alloc)
+ {
+ //delete existing mipmaps
+ for(int i=0;i<m_mipmaps.size();i++)
+ {
+ if(m_mipmaps[i])
+ {
+ if(!m_mipmaps[i]->removeReference())
+ RI_DELETE(m_mipmaps[i]);
+ else
+ {
+ RI_ASSERT(0); //there can't be any other references to the mipmap levels
+ }
+ }
+ }
+ m_mipmaps.clear();
+ m_mipmapsValid = false;
+ throw;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Applies color matrix filter.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Image::colorMatrix(const Image& src, const RIfloat* matrix, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
+{
+ RI_ASSERT(src.m_data); //source exists
+ RI_ASSERT(m_data); //destination exists
+ RI_ASSERT(matrix);
+ RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
+
+ int w = RI_INT_MIN(m_width, src.m_width);
+ int h = RI_INT_MIN(m_height, src.m_height);
+ RI_ASSERT(w > 0 && h > 0);
+
+ Color::InternalFormat srcFormat = src.m_desc.internalFormat;
+ Color::InternalFormat procFormat = (Color::InternalFormat)(srcFormat & ~Color::LUMINANCE); //process in RGB, not luminance
+ if(filterFormatLinear)
+ procFormat = (Color::InternalFormat)(procFormat & ~Color::NONLINEAR);
+ else
+ procFormat = (Color::InternalFormat)(procFormat | Color::NONLINEAR);
+
+ if(filterFormatPremultiplied)
+ procFormat = (Color::InternalFormat)(procFormat | Color::PREMULTIPLIED);
+ else
+ procFormat = (Color::InternalFormat)(procFormat & ~Color::PREMULTIPLIED);
+
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ Color s = src.readPixel(i,j); //convert to RGBA [0,1]
+ s.convert(procFormat);
+
+ Color d(0,0,0,0,procFormat);
+ d.r = matrix[0+4*0] * s.r + matrix[0+4*1] * s.g + matrix[0+4*2] * s.b + matrix[0+4*3] * s.a + matrix[0+4*4];
+ d.g = matrix[1+4*0] * s.r + matrix[1+4*1] * s.g + matrix[1+4*2] * s.b + matrix[1+4*3] * s.a + matrix[1+4*4];
+ d.b = matrix[2+4*0] * s.r + matrix[2+4*1] * s.g + matrix[2+4*2] * s.b + matrix[2+4*3] * s.a + matrix[2+4*4];
+ d.a = matrix[3+4*0] * s.r + matrix[3+4*1] * s.g + matrix[3+4*2] * s.b + matrix[3+4*3] * s.a + matrix[3+4*4];
+
+ writeFilteredPixel(i, j, d, channelMask);
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Reads a pixel from image with tiling mode applied.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static Color readTiledPixel(int x, int y, int w, int h, VGTilingMode tilingMode, const Array<Color>& image, const Color& edge)
+{
+ Color s;
+ if(x < 0 || x >= w || y < 0 || y >= h)
+ { //apply tiling mode
+ switch(tilingMode)
+ {
+ case VG_TILE_FILL:
+ s = edge;
+ break;
+ case VG_TILE_PAD:
+ x = RI_INT_MIN(RI_INT_MAX(x, 0), w-1);
+ y = RI_INT_MIN(RI_INT_MAX(y, 0), h-1);
+ RI_ASSERT(x >= 0 && x < w && y >= 0 && y < h);
+ s = image[y*w+x];
+ break;
+ case VG_TILE_REPEAT:
+ x = RI_INT_MOD(x, w);
+ y = RI_INT_MOD(y, h);
+ RI_ASSERT(x >= 0 && x < w && y >= 0 && y < h);
+ s = image[y*w+x];
+ break;
+ default:
+ RI_ASSERT(tilingMode == VG_TILE_REFLECT);
+ x = RI_INT_MOD(x, w*2);
+ y = RI_INT_MOD(y, h*2);
+ if(x >= w) x = w*2-1-x;
+ if(y >= h) y = h*2-1-y;
+ RI_ASSERT(x >= 0 && x < w && y >= 0 && y < h);
+ s = image[y*w+x];
+ break;
+ }
+ }
+ else
+ {
+ RI_ASSERT(x >= 0 && x < w && y >= 0 && y < h);
+ s = image[y*w+x];
+ }
+ return s;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Returns processing format for filtering.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static Color::InternalFormat getProcessingFormat(Color::InternalFormat srcFormat, bool filterFormatLinear, bool filterFormatPremultiplied)
+{
+ Color::InternalFormat procFormat = (Color::InternalFormat)(srcFormat & ~Color::LUMINANCE); //process in RGB, not luminance
+ if(filterFormatLinear)
+ procFormat = (Color::InternalFormat)(procFormat & ~Color::NONLINEAR);
+ else
+ procFormat = (Color::InternalFormat)(procFormat | Color::NONLINEAR);
+
+ if(filterFormatPremultiplied)
+ procFormat = (Color::InternalFormat)(procFormat | Color::PREMULTIPLIED);
+ else
+ procFormat = (Color::InternalFormat)(procFormat & ~Color::PREMULTIPLIED);
+ return procFormat;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Applies convolution filter.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Image::convolve(const Image& src, int kernelWidth, int kernelHeight, int shiftX, int shiftY, const RIint16* kernel, RIfloat scale, RIfloat bias, VGTilingMode tilingMode, const Color& edgeFillColor, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
+{
+ RI_ASSERT(src.m_data); //source exists
+ RI_ASSERT(m_data); //destination exists
+ RI_ASSERT(kernel && kernelWidth > 0 && kernelHeight > 0);
+ RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
+
+ //the area to be written is an intersection of source and destination image areas.
+ //lower-left corners of the images are aligned.
+ int w = RI_INT_MIN(m_width, src.m_width);
+ int h = RI_INT_MIN(m_height, src.m_height);
+ RI_ASSERT(w > 0 && h > 0);
+
+ Color::InternalFormat procFormat = getProcessingFormat(src.m_desc.internalFormat, filterFormatLinear, filterFormatPremultiplied);
+
+ Color edge = edgeFillColor;
+ edge.clamp();
+ edge.convert(procFormat);
+
+ Array<Color> tmp;
+ tmp.resize(src.m_width*src.m_height); //throws bad_alloc
+
+ //copy source region to tmp and do conversion
+ for(int j=0;j<src.m_height;j++)
+ {
+ for(int i=0;i<src.m_width;i++)
+ {
+ Color s = src.readPixel(i, j);
+ s.convert(procFormat);
+ tmp[j*src.m_width+i] = s;
+ }
+ }
+
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ Color sum(0,0,0,0,procFormat);
+
+ for(int kj=0;kj<kernelHeight;kj++)
+ {
+ for(int ki=0;ki<kernelWidth;ki++)
+ {
+ int x = i+ki-shiftX;
+ int y = j+kj-shiftY;
+ Color s = readTiledPixel(x, y, src.m_width, src.m_height, tilingMode, tmp, edge);
+
+ int kx = kernelWidth-ki-1;
+ int ky = kernelHeight-kj-1;
+ RI_ASSERT(kx >= 0 && kx < kernelWidth && ky >= 0 && ky < kernelHeight);
+
+ sum += (RIfloat)kernel[kx*kernelHeight+ky] * s;
+ }
+ }
+
+ sum *= scale;
+ sum.r += bias;
+ sum.g += bias;
+ sum.b += bias;
+ sum.a += bias;
+
+ writeFilteredPixel(i, j, sum, channelMask);
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Applies separable convolution filter.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Image::separableConvolve(const Image& src, int kernelWidth, int kernelHeight, int shiftX, int shiftY, const RIint16* kernelX, const RIint16* kernelY, RIfloat scale, RIfloat bias, VGTilingMode tilingMode, const Color& edgeFillColor, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
+{
+ RI_ASSERT(src.m_data); //source exists
+ RI_ASSERT(m_data); //destination exists
+ RI_ASSERT(kernelX && kernelY && kernelWidth > 0 && kernelHeight > 0);
+ RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
+
+ //the area to be written is an intersection of source and destination image areas.
+ //lower-left corners of the images are aligned.
+ int w = RI_INT_MIN(m_width, src.m_width);
+ int h = RI_INT_MIN(m_height, src.m_height);
+ RI_ASSERT(w > 0 && h > 0);
+
+ Color::InternalFormat procFormat = getProcessingFormat(src.m_desc.internalFormat, filterFormatLinear, filterFormatPremultiplied);
+
+ Color edge = edgeFillColor;
+ edge.clamp();
+ edge.convert(procFormat);
+
+ Array<Color> tmp;
+ tmp.resize(src.m_width*src.m_height); //throws bad_alloc
+
+ //copy source region to tmp and do conversion
+ for(int j=0;j<src.m_height;j++)
+ {
+ for(int i=0;i<src.m_width;i++)
+ {
+ Color s = src.readPixel(i, j);
+ s.convert(procFormat);
+ tmp[j*src.m_width+i] = s;
+ }
+ }
+
+ Array<Color> tmp2;
+ tmp2.resize(w*src.m_height); //throws bad_alloc
+ for(int j=0;j<src.m_height;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ Color sum(0,0,0,0,procFormat);
+ for(int ki=0;ki<kernelWidth;ki++)
+ {
+ int x = i+ki-shiftX;
+ Color s = readTiledPixel(x, j, src.m_width, src.m_height, tilingMode, tmp, edge);
+
+ int kx = kernelWidth-ki-1;
+ RI_ASSERT(kx >= 0 && kx < kernelWidth);
+
+ sum += (RIfloat)kernelX[kx] * s;
+ }
+ tmp2[j*w+i] = sum;
+ }
+ }
+
+ if(tilingMode == VG_TILE_FILL)
+ { //convolve the edge color
+ Color sum(0,0,0,0,procFormat);
+ for(int ki=0;ki<kernelWidth;ki++)
+ {
+ sum += (RIfloat)kernelX[ki] * edge;
+ }
+ edge = sum;
+ }
+
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ Color sum(0,0,0,0,procFormat);
+ for(int kj=0;kj<kernelHeight;kj++)
+ {
+ int y = j+kj-shiftY;
+ Color s = readTiledPixel(i, y, w, src.m_height, tilingMode, tmp2, edge);
+
+ int ky = kernelHeight-kj-1;
+ RI_ASSERT(ky >= 0 && ky < kernelHeight);
+
+ sum += (RIfloat)kernelY[ky] * s;
+ }
+
+ sum *= scale;
+ sum.r += bias;
+ sum.g += bias;
+ sum.b += bias;
+ sum.a += bias;
+
+ writeFilteredPixel(i, j, sum, channelMask);
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Applies Gaussian blur filter.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Image::gaussianBlur(const Image& src, RIfloat stdDeviationX, RIfloat stdDeviationY, VGTilingMode tilingMode, const Color& edgeFillColor, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
+{
+ RI_ASSERT(src.m_data); //source exists
+ RI_ASSERT(m_data); //destination exists
+ RI_ASSERT(stdDeviationX > 0.0f && stdDeviationY > 0.0f);
+ RI_ASSERT(stdDeviationX <= RI_MAX_GAUSSIAN_STD_DEVIATION && stdDeviationY <= RI_MAX_GAUSSIAN_STD_DEVIATION);
+ RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
+
+ //the area to be written is an intersection of source and destination image areas.
+ //lower-left corners of the images are aligned.
+ int w = RI_INT_MIN(m_width, src.m_width);
+ int h = RI_INT_MIN(m_height, src.m_height);
+ RI_ASSERT(w > 0 && h > 0);
+
+ Color::InternalFormat procFormat = getProcessingFormat(src.m_desc.internalFormat, filterFormatLinear, filterFormatPremultiplied);
+
+ Color edge = edgeFillColor;
+ edge.clamp();
+ edge.convert(procFormat);
+
+ Array<Color> tmp;
+ tmp.resize(src.m_width*src.m_height); //throws bad_alloc
+
+ //copy source region to tmp and do conversion
+ for(int j=0;j<src.m_height;j++)
+ {
+ for(int i=0;i<src.m_width;i++)
+ {
+ Color s = src.readPixel(i, j);
+ s.convert(procFormat);
+ tmp[j*src.m_width+i] = s;
+ }
+ }
+
+ RIfloat expScaleX = -1.0f / (2.0f*stdDeviationX*stdDeviationX);
+ RIfloat expScaleY = -1.0f / (2.0f*stdDeviationY*stdDeviationY);
+
+ int kernelWidth = (int)(stdDeviationX * 4.0f + 1.0f);
+ int kernelHeight = (int)(stdDeviationY * 4.0f + 1.0f);
+
+ //make a separable kernel
+ Array<RIfloat> kernelX;
+ kernelX.resize(kernelWidth*2+1);
+ int shiftX = kernelWidth;
+ RIfloat scaleX = 0.0f;
+ for(int i=0;i<kernelX.size();i++)
+ {
+ int x = i-shiftX;
+ kernelX[i] = (RIfloat)exp((RIfloat)x*(RIfloat)x * expScaleX);
+ scaleX += kernelX[i];
+ }
+ scaleX = 1.0f / scaleX; //NOTE: using the mathematical definition of the scaling term doesn't work since we cut the filter support early for performance
+
+ Array<RIfloat> kernelY;
+ kernelY.resize(kernelHeight*2+1);
+ int shiftY = kernelHeight;
+ RIfloat scaleY = 0.0f;
+ for(int i=0;i<kernelY.size();i++)
+ {
+ int y = i-shiftY;
+ kernelY[i] = (RIfloat)exp((RIfloat)y*(RIfloat)y * expScaleY);
+ scaleY += kernelY[i];
+ }
+ scaleY = 1.0f / scaleY; //NOTE: using the mathematical definition of the scaling term doesn't work since we cut the filter support early for performance
+
+ Array<Color> tmp2;
+ tmp2.resize(w*src.m_height); //throws bad_alloc
+ //horizontal pass
+ for(int j=0;j<src.m_height;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ Color sum(0,0,0,0,procFormat);
+ for(int ki=0;ki<kernelX.size();ki++)
+ {
+ int x = i+ki-shiftX;
+ sum += kernelX[ki] * readTiledPixel(x, j, src.m_width, src.m_height, tilingMode, tmp, edge);
+ }
+ tmp2[j*w+i] = sum * scaleX;
+ }
+ }
+ //vertical pass
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ Color sum(0,0,0,0,procFormat);
+ for(int kj=0;kj<kernelY.size();kj++)
+ {
+ int y = j+kj-shiftY;
+ sum += kernelY[kj] * readTiledPixel(i, y, w, src.m_height, tilingMode, tmp2, edge);
+ }
+ writeFilteredPixel(i, j, sum * scaleY, channelMask);
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Returns lookup table format for lookup filters.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static Color::InternalFormat getLUTFormat(bool outputLinear, bool outputPremultiplied)
+{
+ Color::InternalFormat lutFormat = Color::lRGBA;
+ if(outputLinear && outputPremultiplied)
+ lutFormat = Color::lRGBA_PRE;
+ else if(!outputLinear && !outputPremultiplied)
+ lutFormat = Color::sRGBA;
+ else if(!outputLinear && outputPremultiplied)
+ lutFormat = Color::sRGBA_PRE;
+ return lutFormat;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Applies multi-channel lookup table filter.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Image::lookup(const Image& src, const RIuint8 * redLUT, const RIuint8 * greenLUT, const RIuint8 * blueLUT, const RIuint8 * alphaLUT, bool outputLinear, bool outputPremultiplied, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
+{
+ RI_ASSERT(src.m_data); //source exists
+ RI_ASSERT(m_data); //destination exists
+ RI_ASSERT(redLUT && greenLUT && blueLUT && alphaLUT);
+ RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
+
+ //the area to be written is an intersection of source and destination image areas.
+ //lower-left corners of the images are aligned.
+ int w = RI_INT_MIN(m_width, src.m_width);
+ int h = RI_INT_MIN(m_height, src.m_height);
+ RI_ASSERT(w > 0 && h > 0);
+
+ Color::InternalFormat procFormat = getProcessingFormat(src.m_desc.internalFormat, filterFormatLinear, filterFormatPremultiplied);
+ Color::InternalFormat lutFormat = getLUTFormat(outputLinear, outputPremultiplied);
+
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ Color s = src.readPixel(i,j); //convert to RGBA [0,1]
+ s.convert(procFormat);
+
+ Color d(0,0,0,0,lutFormat);
+ d.r = intToColor( redLUT[colorToInt(s.r, 255)], 255);
+ d.g = intToColor(greenLUT[colorToInt(s.g, 255)], 255);
+ d.b = intToColor( blueLUT[colorToInt(s.b, 255)], 255);
+ d.a = intToColor(alphaLUT[colorToInt(s.a, 255)], 255);
+
+ writeFilteredPixel(i, j, d, channelMask);
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Applies single channel lookup table filter.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Image::lookupSingle(const Image& src, const RIuint32 * lookupTable, VGImageChannel sourceChannel, bool outputLinear, bool outputPremultiplied, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
+{
+ RI_ASSERT(src.m_data); //source exists
+ RI_ASSERT(m_data); //destination exists
+ RI_ASSERT(lookupTable);
+ RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
+
+ //the area to be written is an intersection of source and destination image areas.
+ //lower-left corners of the images are aligned.
+ int w = RI_INT_MIN(m_width, src.m_width);
+ int h = RI_INT_MIN(m_height, src.m_height);
+ RI_ASSERT(w > 0 && h > 0);
+
+ if(src.m_desc.isLuminance())
+ sourceChannel = VG_RED;
+ else if(src.m_desc.redBits + src.m_desc.greenBits + src.m_desc.blueBits == 0)
+ {
+ RI_ASSERT(src.m_desc.alphaBits);
+ sourceChannel = VG_ALPHA;
+ }
+
+ Color::InternalFormat procFormat = getProcessingFormat(src.m_desc.internalFormat, filterFormatLinear, filterFormatPremultiplied);
+ Color::InternalFormat lutFormat = getLUTFormat(outputLinear, outputPremultiplied);
+
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ Color s = src.readPixel(i,j); //convert to RGBA [0,1]
+ s.convert(procFormat);
+ int e;
+ switch(sourceChannel)
+ {
+ case VG_RED:
+ e = colorToInt(s.r, 255);
+ break;
+ case VG_GREEN:
+ e = colorToInt(s.g, 255);
+ break;
+ case VG_BLUE:
+ e = colorToInt(s.b, 255);
+ break;
+ default:
+ RI_ASSERT(sourceChannel == VG_ALPHA);
+ e = colorToInt(s.a, 255);
+ break;
+ }
+
+ RIuint32 l = ((const RIuint32*)lookupTable)[e];
+ Color d(0,0,0,0,lutFormat);
+ d.r = intToColor((l>>24), 255);
+ d.g = intToColor((l>>16), 255);
+ d.b = intToColor((l>> 8), 255);
+ d.a = intToColor((l ), 255);
+
+ writeFilteredPixel(i, j, d, channelMask);
+ }
+ }
+}
+
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Surface::Surface(const Color::Descriptor& desc, int width, int height, int numSamples) :
+ m_width(width),
+ m_height(height),
+ m_numSamples(numSamples),
+ m_referenceCount(0),
+ m_image(NULL)
+{
+ RI_ASSERT(width > 0 && height > 0 && numSamples > 0 && numSamples <= 32);
+ m_image = RI_NEW(Image, (desc, width*numSamples, height, 0)); //throws bad_alloc
+ m_image->addReference();
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Surface::Surface(Image* image) :
+ m_width(0),
+ m_height(0),
+ m_numSamples(1),
+ m_referenceCount(0),
+ m_image(image)
+{
+ RI_ASSERT(image);
+ m_width = image->getWidth();
+ m_height = image->getHeight();
+ m_image->addReference();
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Surface::Surface(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data) :
+ m_width(width),
+ m_height(height),
+ m_numSamples(1),
+ m_referenceCount(0),
+ m_image(NULL)
+{
+ RI_ASSERT(width > 0 && height > 0);
+ m_image = RI_NEW(Image, (desc, width, height, stride, data)); //throws bad_alloc
+ m_image->addReference();
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Surface::~Surface()
+{
+ RI_ASSERT(m_referenceCount == 0);
+ if(!m_image->removeReference())
+ RI_DELETE(m_image);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Surface::clear(const Color& clearColor, int x, int y, int w, int h)
+{
+ Rectangle rect;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = getWidth();
+ rect.height = getHeight();
+ Array<Rectangle> scissors;
+ scissors.push_back(rect);
+ clear(clearColor, x, y, w, h, scissors);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Surface::clear(const Color& clearColor, int x, int y, int w, int h, const Array<Rectangle>& scissors)
+{
+ RI_ASSERT(w > 0 && h > 0);
+
+ //intersect clear region with image bounds
+ Rectangle r(0,0,getWidth(),getHeight());
+ r.intersect(Rectangle(x,y,w,h));
+ if(!r.width || !r.height)
+ return; //intersection is empty or one of the rectangles is invalid
+
+ Array<ScissorEdge> scissorEdges;
+ for(int i=0;i<scissors.size();i++)
+ {
+ if(scissors[i].width > 0 && scissors[i].height > 0)
+ {
+ ScissorEdge e;
+ e.miny = scissors[i].y;
+ e.maxy = RI_INT_ADDSATURATE(scissors[i].y, scissors[i].height);
+
+ e.x = scissors[i].x;
+ e.direction = 1;
+ scissorEdges.push_back(e); //throws bad_alloc
+ e.x = RI_INT_ADDSATURATE(scissors[i].x, scissors[i].width);
+ e.direction = -1;
+ scissorEdges.push_back(e); //throws bad_alloc
+ }
+ }
+ if(!scissorEdges.size())
+ return; //there are no scissor rectangles => nothing is visible
+
+ //sort scissor edges by edge x
+ scissorEdges.sort();
+
+ //clear the image
+ Color col = clearColor;
+ col.clamp();
+ col.convert(m_image->getDescriptor().internalFormat);
+
+ Array<ScissorEdge> scissorAet;
+ for(int j=r.y;j<r.y + r.height;j++)
+ {
+ //gather scissor edges intersecting this scanline
+ scissorAet.clear();
+ for(int e=0;e<scissorEdges.size();e++)
+ {
+ const ScissorEdge& se = scissorEdges[e];
+ if(j >= se.miny && j < se.maxy)
+ scissorAet.push_back(scissorEdges[e]); //throws bad_alloc
+ }
+ if(!scissorAet.size())
+ continue; //scissoring is on, but there are no scissor rectangles on this scanline
+
+ //clear a scanline
+ int scissorWinding = 0;
+ int scissorIndex = 0;
+ for(int i=r.x;i<r.x + r.width;i++)
+ {
+ while(scissorIndex < scissorAet.size() && scissorAet[scissorIndex].x <= i)
+ scissorWinding += scissorAet[scissorIndex++].direction;
+ RI_ASSERT(scissorWinding >= 0);
+
+ if(scissorWinding)
+ {
+ for(int s=0;s<m_numSamples;s++)
+ writeSample(i, j, s, col);
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Surface::blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h)
+{
+ Rectangle rect;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = getWidth();
+ rect.height = getHeight();
+ Array<Rectangle> scissors;
+ scissors.push_back(rect);
+ blit(src, sx, sy, dx, dy, w, h, scissors);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note no overlap is possible. Single sample to single or multisample (replicate)
+*//*-------------------------------------------------------------------*/
+
+void Surface::blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h, const Array<Rectangle>& scissors)
+{
+ //img=>fb: vgSetPixels
+ //user=>fb: vgWritePixels
+ computeBlitRegion(sx, sy, dx, dy, w, h, src.getWidth(), src.getHeight(), getWidth(), getHeight());
+ if(w <= 0 || h <= 0)
+ return; //zero area
+
+ Array<ScissorEdge> scissorEdges;
+ for(int i=0;i<scissors.size();i++)
+ {
+ if(scissors[i].width > 0 && scissors[i].height > 0)
+ {
+ ScissorEdge e;
+ e.miny = scissors[i].y;
+ e.maxy = RI_INT_ADDSATURATE(scissors[i].y, scissors[i].height);
+
+ e.x = scissors[i].x;
+ e.direction = 1;
+ scissorEdges.push_back(e); //throws bad_alloc
+ e.x = RI_INT_ADDSATURATE(scissors[i].x, scissors[i].width);
+ e.direction = -1;
+ scissorEdges.push_back(e); //throws bad_alloc
+ }
+ }
+ if(!scissorEdges.size())
+ return; //there are no scissor rectangles => nothing is visible
+
+ //sort scissor edges by edge x
+ scissorEdges.sort();
+
+ Array<ScissorEdge> scissorAet;
+ for(int j=0;j<h;j++)
+ {
+ //gather scissor edges intersecting this scanline
+ scissorAet.clear();
+ for(int e=0;e<scissorEdges.size();e++)
+ {
+ const ScissorEdge& se = scissorEdges[e];
+ if(dy + j >= se.miny && dy + j < se.maxy)
+ scissorAet.push_back(scissorEdges[e]); //throws bad_alloc
+ }
+ if(!scissorAet.size())
+ continue; //scissoring is on, but there are no scissor rectangles on this scanline
+
+ //blit a scanline
+ int scissorWinding = 0;
+ int scissorIndex = 0;
+ for(int i=0;i<w;i++)
+ {
+ while(scissorIndex < scissorAet.size() && scissorAet[scissorIndex].x <= dx + i)
+ scissorWinding += scissorAet[scissorIndex++].direction;
+ RI_ASSERT(scissorWinding >= 0);
+
+ if(scissorWinding)
+ {
+ Color c = src.readPixel(sx + i, sy + j);
+ c.convert(getDescriptor().internalFormat);
+ for(int s=0;s<m_numSamples;s++)
+ writeSample(dx + i, dy + j, s, c);
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Surface::blit(const Surface* src, int sx, int sy, int dx, int dy, int w, int h)
+{
+ Rectangle rect;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = getWidth();
+ rect.height = getHeight();
+ Array<Rectangle> scissors;
+ scissors.push_back(rect);
+ blit(src, sx, sy, dx, dy, w, h, scissors);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Surface::blit(const Surface* src, int sx, int sy, int dx, int dy, int w, int h, const Array<Rectangle>& scissors)
+{
+ RI_ASSERT(m_numSamples == src->m_numSamples);
+
+ //fb=>fb: vgCopyPixels
+ computeBlitRegion(sx, sy, dx, dy, w, h, src->getWidth(), src->getHeight(), getWidth(), getHeight());
+ if(w <= 0 || h <= 0)
+ return; //zero area
+
+ Array<ScissorEdge> scissorEdges;
+ for(int i=0;i<scissors.size();i++)
+ {
+ if(scissors[i].width > 0 && scissors[i].height > 0)
+ {
+ ScissorEdge e;
+ e.miny = scissors[i].y;
+ e.maxy = RI_INT_ADDSATURATE(scissors[i].y, scissors[i].height);
+
+ e.x = scissors[i].x;
+ e.direction = 1;
+ scissorEdges.push_back(e); //throws bad_alloc
+ e.x = RI_INT_ADDSATURATE(scissors[i].x, scissors[i].width);
+ e.direction = -1;
+ scissorEdges.push_back(e); //throws bad_alloc
+ }
+ }
+ if(!scissorEdges.size())
+ return; //there are no scissor rectangles => nothing is visible
+
+ //sort scissor edges by edge x
+ scissorEdges.sort();
+
+ Array<Color> tmp;
+ tmp.resize(w*m_numSamples*h); //throws bad_alloc
+
+ //copy source region to tmp
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ int numSamples = m_numSamples;
+ for(int s=0;s<numSamples;s++)
+ {
+ Color c = src->m_image->readPixel((sx + i)*m_numSamples+s, sy + j);
+ c.convert(m_image->getDescriptor().internalFormat);
+ tmp[(j*w+i)*m_numSamples+s] = c;
+ }
+ }
+ }
+
+ Array<ScissorEdge> scissorAet;
+ for(int j=0;j<h;j++)
+ {
+ //gather scissor edges intersecting this scanline
+ scissorAet.clear();
+ for(int e=0;e<scissorEdges.size();e++)
+ {
+ const ScissorEdge& se = scissorEdges[e];
+ if(dy + j >= se.miny && dy + j < se.maxy)
+ scissorAet.push_back(scissorEdges[e]); //throws bad_alloc
+ }
+ if(!scissorAet.size())
+ continue; //scissoring is on, but there are no scissor rectangles on this scanline
+
+ //blit a scanline
+ int scissorWinding = 0;
+ int scissorIndex = 0;
+ for(int i=0;i<w;i++)
+ {
+ while(scissorIndex < scissorAet.size() && scissorAet[scissorIndex].x <= dx + i)
+ scissorWinding += scissorAet[scissorIndex++].direction;
+ RI_ASSERT(scissorWinding >= 0);
+
+ if(scissorWinding)
+ {
+ int numSamples = m_numSamples;
+ for(int s=0;s<numSamples;s++)
+ {
+ m_image->writePixel((dx + i)*m_numSamples+s, dy + j, tmp[(j*w+i)*m_numSamples+s]);
+ }
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Surface::mask(const Image* src, VGMaskOperation operation, int x, int y, int w, int h)
+{
+ RI_ASSERT(w > 0 && h > 0);
+
+ if(operation == VG_CLEAR_MASK || operation == VG_FILL_MASK)
+ {
+ //intersect clear region with image bounds
+ Rectangle r(0,0,getWidth(),getHeight());
+ r.intersect(Rectangle(x,y,w,h));
+ if(!r.width || !r.height)
+ return; //intersection is empty or one of the rectangles is invalid
+
+ if(m_numSamples == 1)
+ {
+ RIfloat m = 0.0f;
+ if(operation == VG_FILL_MASK)
+ m = 1.0f;
+ for(int j=r.y;j<r.y + r.height;j++)
+ {
+ for(int i=r.x;i<r.x + r.width;i++)
+ {
+ writeMaskCoverage(i, j, m);
+ }
+ }
+ }
+ else
+ {
+ unsigned int m = 0;
+ if(operation == VG_FILL_MASK)
+ m = (1<<m_numSamples)-1;
+ for(int j=r.y;j<r.y + r.height;j++)
+ {
+ for(int i=r.x;i<r.x + r.width;i++)
+ {
+ writeMaskMSAA(i, j, m);
+ }
+ }
+ }
+ }
+ else
+ {
+ RI_ASSERT(src);
+
+ int sx = 0, sy = 0, dx = x, dy = y;
+ computeBlitRegion(sx, sy, dx, dy, w, h, src->getWidth(), src->getHeight(), getWidth(), getHeight());
+ if(w <= 0 || h <= 0)
+ return; //zero area
+
+ if(m_numSamples == 1)
+ {
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ RIfloat amask = src->readMaskPixel(sx + i, sy + j);
+ if(operation == VG_SET_MASK)
+ writeMaskCoverage(dx + i, dy + j, amask);
+ else
+ {
+ RIfloat aprev = readMaskCoverage(dx + i, dy + j);
+ RIfloat anew = 0.0f;
+ switch(operation)
+ {
+ case VG_UNION_MASK: anew = 1.0f - (1.0f - amask)*(1.0f - aprev); break;
+ case VG_INTERSECT_MASK: anew = amask * aprev; break;
+ default: anew = aprev * (1.0f - amask); RI_ASSERT(operation == VG_SUBTRACT_MASK); break;
+ }
+ writeMaskCoverage(dx + i, dy + j, anew);
+ }
+ }
+ }
+ }
+ else
+ {
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ RIfloat fmask = src->readMaskPixel(sx + i, sy + j);
+ //TODO implement dithering?
+ unsigned int amask = fmask > 0.5f ? (1<<m_numSamples)-1 : 0;
+ if(operation == VG_SET_MASK)
+ writeMaskMSAA(dx + i, dy + j, amask);
+ else
+ {
+ unsigned int aprev = readMaskMSAA(dx + i, dy + j);
+ unsigned int anew = 0;
+ switch(operation)
+ {
+ case VG_UNION_MASK: anew = amask | aprev; break;
+ case VG_INTERSECT_MASK: anew = amask & aprev; break;
+ default: anew = ~amask & aprev; RI_ASSERT(operation == VG_SUBTRACT_MASK); break;
+ }
+ writeMaskMSAA(dx + i, dy + j, anew);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Surface::mask(const Surface* src, VGMaskOperation operation, int x, int y, int w, int h)
+{
+ RI_ASSERT(w > 0 && h > 0);
+
+ if(operation == VG_CLEAR_MASK || operation == VG_FILL_MASK)
+ {
+ //intersect clear region with image bounds
+ Rectangle r(0,0,getWidth(),getHeight());
+ r.intersect(Rectangle(x,y,w,h));
+ if(!r.width || !r.height)
+ return; //intersection is empty or one of the rectangles is invalid
+
+ if(m_numSamples == 1)
+ {
+ RIfloat m = 0.0f;
+ if(operation == VG_FILL_MASK)
+ m = 1.0f;
+ for(int j=r.y;j<r.y + r.height;j++)
+ {
+ for(int i=r.x;i<r.x + r.width;i++)
+ {
+ writeMaskCoverage(i, j, m);
+ }
+ }
+ }
+ else
+ {
+ unsigned int m = 0;
+ if(operation == VG_FILL_MASK)
+ m = (1<<m_numSamples)-1;
+ for(int j=r.y;j<r.y + r.height;j++)
+ {
+ for(int i=r.x;i<r.x + r.width;i++)
+ {
+ writeMaskMSAA(i, j, m);
+ }
+ }
+ }
+ }
+ else
+ {
+ RI_ASSERT(src);
+ RI_ASSERT(m_numSamples == src->m_numSamples);
+
+ int sx = 0, sy = 0, dx = x, dy = y;
+ computeBlitRegion(sx, sy, dx, dy, w, h, src->getWidth(), src->getHeight(), getWidth(), getHeight());
+ if(w <= 0 || h <= 0)
+ return; //zero area
+
+ if(m_numSamples == 1)
+ {
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ RIfloat amask = src->readMaskCoverage(sx + i, sy + j);
+ if(operation == VG_SET_MASK)
+ writeMaskCoverage(dx + i, dy + j, amask);
+ else
+ {
+ RIfloat aprev = readMaskCoverage(dx + i, dy + j);
+ RIfloat anew = 0.0f;
+ switch(operation)
+ {
+ case VG_UNION_MASK: anew = 1.0f - (1.0f - amask)*(1.0f - aprev); break;
+ case VG_INTERSECT_MASK: anew = amask * aprev; break;
+ default: anew = aprev * (1.0f - amask); RI_ASSERT(operation == VG_SUBTRACT_MASK); break;
+ }
+ writeMaskCoverage(dx + i, dy + j, anew);
+ }
+ }
+ }
+ }
+ else
+ {
+ for(int j=0;j<h;j++)
+ {
+ for(int i=0;i<w;i++)
+ {
+ unsigned int amask = src->readMaskMSAA(sx + i, sy + j);
+ if(operation == VG_SET_MASK)
+ writeMaskMSAA(dx + i, dy + j, amask);
+ else
+ {
+ unsigned int aprev = readMaskMSAA(dx + i, dy + j);
+ unsigned int anew = 0;
+ switch(operation)
+ {
+ case VG_UNION_MASK: anew = amask | aprev; break;
+ case VG_INTERSECT_MASK: anew = amask & aprev; break;
+ default: anew = ~amask & aprev; RI_ASSERT(operation == VG_SUBTRACT_MASK); break;
+ }
+ writeMaskMSAA(dx + i, dy + j, anew);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+RIfloat Surface::readMaskCoverage(int x, int y) const
+{
+ RI_ASSERT(x >= 0 && x < m_width && y >= 0 && y < m_height);
+ RI_ASSERT(m_numSamples == 1);
+ return m_image->readMaskPixel(x, y);
+}
+
+void Surface::writeMaskCoverage(int x, int y, RIfloat m)
+{
+ RI_ASSERT(x >= 0 && x < m_width && y >= 0 && y < m_height);
+ RI_ASSERT(m_numSamples == 1);
+ m_image->writeMaskPixel(x, y, m); //TODO support other than alpha formats but don't write to color channels?
+}
+
+unsigned int Surface::readMaskMSAA(int x, int y) const
+{
+ RI_ASSERT(x >= 0 && x < m_width && y >= 0 && y < m_height);
+ RI_ASSERT(m_numSamples > 1);
+ unsigned int m = 0;
+ for(int i=0;i<m_numSamples;i++)
+ {
+ if(m_image->readMaskPixel(x*m_numSamples+i, y) > 0.5f) //TODO is this the right formula for converting alpha to bit mask? does it matter?
+ m |= 1<<i;
+ }
+ return m;
+}
+
+void Surface::writeMaskMSAA(int x, int y, unsigned int m)
+{
+ RI_ASSERT(x >= 0 && x < m_width && y >= 0 && y < m_height);
+ RI_ASSERT(m_numSamples > 1);
+ for(int i=0;i<m_numSamples;i++)
+ {
+ RIfloat a = 0.0f;
+ if(m & (1<<i))
+ a = 1.0f;
+ m_image->writeMaskPixel(x*m_numSamples+i, y, a); //TODO support other than alpha formats but don't write to color channels?
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Color Surface::FSAAResolve(int x, int y) const
+{
+ if(m_numSamples == 1)
+ return readSample(x, y, 0);
+
+ Color::InternalFormat aaFormat = getDescriptor().isLuminance() ? Color::lLA_PRE : Color::lRGBA_PRE; //antialias in linear color space
+ Color r(0.0f, 0.0f, 0.0f, 0.0f, aaFormat);
+ for(int i=0;i<m_numSamples;i++)
+ {
+ Color d = readSample(x, y, i);
+ d.convert(aaFormat);
+ r += d;
+ }
+ r *= 1.0f/m_numSamples;
+ return r;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Drawable::Drawable(const Color::Descriptor& desc, int width, int height, int numSamples, int maskBits) :
+ m_referenceCount(0),
+ m_color(NULL),
+ m_mask(NULL)
+{
+ RI_ASSERT(width > 0 && height > 0 && numSamples > 0 && numSamples <= 32);
+ RI_ASSERT(maskBits == 0 || maskBits == 1 || maskBits == 4 || maskBits == 8);
+ m_color = RI_NEW(Surface, (desc, width, height, numSamples)); //throws bad_alloc
+ m_color->addReference();
+ if(maskBits)
+ {
+ VGImageFormat mf = VG_A_1;
+ if(maskBits == 4)
+ mf = VG_A_4;
+ else if(maskBits == 8)
+ mf = VG_A_8;
+ m_mask = RI_NEW(Surface, (Color::formatToDescriptor(mf), width, height, numSamples));
+ m_mask->addReference();
+ m_mask->clear(Color(1,1,1,1,Color::sRGBA), 0, 0, width, height);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Drawable::Drawable(Image* image, int maskBits) :
+ m_referenceCount(0),
+ m_color(NULL),
+ m_mask(NULL)
+{
+ RI_ASSERT(maskBits == 0 || maskBits == 1 || maskBits == 4 || maskBits == 8);
+ RI_ASSERT(image);
+ m_color = RI_NEW(Surface, (image));
+ m_color->addReference();
+ if(maskBits)
+ {
+ VGImageFormat mf = VG_A_1;
+ if(maskBits == 4)
+ mf = VG_A_4;
+ else if(maskBits == 8)
+ mf = VG_A_8;
+ m_mask = RI_NEW(Surface, (Color::formatToDescriptor(mf), image->getWidth(), image->getHeight(), 1));
+ m_mask->addReference();
+ m_mask->clear(Color(1,1,1,1,Color::sRGBA), 0, 0, image->getWidth(), image->getHeight());
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Drawable::Drawable(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data, int maskBits) :
+ m_referenceCount(0),
+ m_color(NULL),
+ m_mask(NULL)
+{
+ RI_ASSERT(width > 0 && height > 0);
+ RI_ASSERT(maskBits == 0 || maskBits == 1 || maskBits == 4 || maskBits == 8);
+ m_color = RI_NEW(Surface, (desc, width, height, stride, data)); //throws bad_alloc
+ m_color->addReference();
+ if(maskBits)
+ {
+ VGImageFormat mf = VG_A_1;
+ if(maskBits == 4)
+ mf = VG_A_4;
+ else if(maskBits == 8)
+ mf = VG_A_8;
+ m_mask = RI_NEW(Surface, (Color::formatToDescriptor(mf), width, height, 1));
+ m_mask->addReference();
+ m_mask->clear(Color(1,1,1,1,Color::sRGBA), 0, 0, width, height);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+Drawable::~Drawable()
+{
+ RI_ASSERT(m_referenceCount == 0);
+ if(!m_color->removeReference())
+ RI_DELETE(m_color);
+ if(m_mask)
+ if(!m_mask->removeReference())
+ RI_DELETE(m_mask);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void Drawable::resize(int newWidth, int newHeight)
+{
+ Surface* oldcolor = m_color;
+ Surface* oldmask = m_mask;
+ int oldWidth = m_color->getWidth();
+ int oldHeight = m_color->getHeight();
+
+ //TODO check that image is not a proxy
+ m_color = RI_NEW(Surface, (m_color->getDescriptor(), newWidth, newHeight, m_color->getNumSamples()));
+ m_color->addReference();
+ if(m_mask)
+ {
+ m_mask = RI_NEW(Surface, (m_mask->getDescriptor(), newWidth, newHeight, m_mask->getNumSamples()));
+ m_mask->addReference();
+ }
+
+ int wmin = RI_INT_MIN(newWidth,oldWidth);
+ int hmin = RI_INT_MIN(newHeight,oldHeight);
+ m_color->clear(Color(0.0f, 0.0f, 0.0f, 0.0f, getDescriptor().internalFormat), 0, 0, m_color->getWidth(), m_color->getHeight());
+ m_color->blit(oldcolor, 0, 0, 0, 0, wmin, hmin);
+ if(m_mask)
+ {
+ m_mask->clear(Color(1.0f, 1.0f, 1.0f, 1.0f, getDescriptor().internalFormat), 0, 0, m_mask->getWidth(), m_mask->getHeight());
+ m_mask->blit(oldmask, 0, 0, 0, 0, wmin, hmin);
+ }
+
+ if(!oldcolor->removeReference())
+ RI_DELETE(oldcolor);
+ if(oldmask)
+ if(!oldmask->removeReference())
+ RI_DELETE(oldmask);
+}
+
+//==============================================================================================
+
+} //namespace OpenVGRI
+
+//==============================================================================================