/* * Copyright (c) 2018-2022 Jean-Philippe Bruyère * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * Software, and to permit persons to whom the Software is furnished to do so, subject * to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "vkvg_surface_internal.h" #include "vkvg_context_internal.h" #include "vkvg_device_internal.h" #include "vkvg_pattern.h" VkvgPattern vkvg_pattern_create_for_surface(VkvgSurface surf) { if (!surf) { LOG(VKVG_LOG_ERR, "CREATE Pattern failed, invalid surface\n"); return (VkvgPattern)&_vkvg_status_null_pointer; } VkvgPattern pat = (vkvg_pattern_t *)calloc(1, sizeof(vkvg_pattern_t)); if (!pat) { LOG(VKVG_LOG_ERR, "CREATE Pattern failed, no memory\n"); return (VkvgPattern)&_vkvg_status_null_pointer; } pat->type = VKVG_PATTERN_TYPE_SURFACE; pat->extend = VKVG_EXTEND_NONE; pat->data = surf; pat->references = 1; vkvg_surface_reference(surf); if (vkvg_surface_status(surf)) pat->status = VKVG_STATUS_INVALID_SURFACE; return pat; } vkvg_status_t vkvg_pattern_get_linear_points(VkvgPattern pat, float *x0, float *y0, float *x1, float *y1) { if (vkvg_pattern_status(pat)) return vkvg_pattern_status(pat); if (pat->type != VKVG_PATTERN_TYPE_LINEAR) return VKVG_STATUS_PATTERN_TYPE_MISMATCH; vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; *x0 = grad->cp[0].x; *y0 = grad->cp[0].y; *x1 = grad->cp[0].z; *y1 = grad->cp[0].w; return VKVG_STATUS_SUCCESS; } vkvg_status_t vkvg_pattern_edit_linear(VkvgPattern pat, float x0, float y0, float x1, float y1) { if (vkvg_pattern_status(pat)) return vkvg_pattern_status(pat); if (pat->type != VKVG_PATTERN_TYPE_LINEAR) return VKVG_STATUS_PATTERN_TYPE_MISMATCH; vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; grad->cp[0] = (vec4){{x0}, {y0}, {x1}, {y1}}; return VKVG_STATUS_SUCCESS; } VkvgPattern vkvg_pattern_create_linear(float x0, float y0, float x1, float y1) { VkvgPattern pat = (vkvg_pattern_t *)calloc(1, sizeof(vkvg_pattern_t)); if (!pat) { LOG(VKVG_LOG_ERR, "CREATE Pattern failed, no memory\n"); return (VkvgPattern)&_vkvg_status_null_pointer; } pat->type = VKVG_PATTERN_TYPE_LINEAR; pat->extend = VKVG_EXTEND_NONE; pat->data = (void *)calloc(1, sizeof(vkvg_gradient_t)); if (pat->data) { vkvg_pattern_edit_linear(pat, x0, y0, x1, y1); pat->references = 1; } else { pat->status = VKVG_STATUS_PATTERN_INVALID_GRADIENT; } return pat; } vkvg_status_t vkvg_pattern_edit_radial(VkvgPattern pat, float cx0, float cy0, float radius0, float cx1, float cy1, float radius1) { if (vkvg_pattern_status(pat)) return vkvg_pattern_status(pat); if (pat->type != VKVG_PATTERN_TYPE_RADIAL) return VKVG_STATUS_PATTERN_TYPE_MISMATCH; vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; vec2 c0 = {cx0, cy0}; vec2 c1 = {cx1, cy1}; if (radius0 > radius1 - 1.0f) radius0 = radius1 - 1.0f; vec2 u = vec2_sub(c0, c1); float l = vec2_length(u); if (l + radius0 + 1.0f >= radius1) { vec2 v = vec2_div_s(u, l); c0 = vec2_add(c1, vec2_mult_s(v, radius1 - radius0 - 1.0f)); } grad->cp[0] = (vec4){{c0.x}, {c0.y}, {radius0}, {0}}; grad->cp[1] = (vec4){{c1.x}, {c1.y}, {radius1}, {0}}; return VKVG_STATUS_SUCCESS; } VkvgPattern vkvg_pattern_create_radial(float cx0, float cy0, float radius0, float cx1, float cy1, float radius1) { VkvgPattern pat = (vkvg_pattern_t *)calloc(1, sizeof(vkvg_pattern_t)); if (!pat) { LOG(VKVG_LOG_ERR, "CREATE Pattern failed, no memory\n"); return (VkvgPattern)&_vkvg_status_null_pointer; } pat->type = VKVG_PATTERN_TYPE_RADIAL; pat->extend = VKVG_EXTEND_NONE; pat->data = (void *)calloc(1, sizeof(vkvg_gradient_t)); if (pat->data) { vkvg_pattern_edit_radial(pat, cx0, cy0, radius0, cx1, cy1, radius1); pat->references = 1; } else pat->status = VKVG_STATUS_NO_MEMORY; return pat; } VkvgPattern vkvg_pattern_reference(VkvgPattern pat) { if (!vkvg_pattern_status(pat)) pat->references++; return pat; } uint32_t vkvg_pattern_get_reference_count(VkvgPattern pat) { if (vkvg_pattern_status(pat)) return 0; return pat->references; } vkvg_status_t vkvg_pattern_add_color_stop(VkvgPattern pat, float offset, float r, float g, float b, float a) { if (vkvg_pattern_status(pat)) return vkvg_pattern_status(pat); if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) return VKVG_STATUS_PATTERN_TYPE_MISMATCH; vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; #ifdef VKVG_PREMULT_ALPHA vkvg_color_t c = {a * r, a * g, a * b, a}; #else vkvg_color_t c = {r, g, b, a}; #endif grad->colors[grad->count] = c; #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT grad->stops[grad->count] = offset; #else grad->stops[grad->count].r = offset; #endif grad->count++; } void vkvg_pattern_set_extend(VkvgPattern pat, vkvg_extend_t extend) { if (vkvg_pattern_status(pat)) return; pat->extend = extend; } void vkvg_pattern_set_filter(VkvgPattern pat, vkvg_filter_t filter) { if (vkvg_pattern_status(pat)) return; pat->filter = filter; } vkvg_extend_t vkvg_pattern_get_extend(VkvgPattern pat) { if (vkvg_pattern_status(pat)) return (vkvg_extend_t)0; return pat->extend; } vkvg_filter_t vkvg_pattern_get_filter(VkvgPattern pat) { if (vkvg_pattern_status(pat)) return (vkvg_filter_t)0; return pat->filter; } vkvg_pattern_type_t vkvg_pattern_get_type(VkvgPattern pat) { if (vkvg_pattern_status(pat)) return (vkvg_pattern_type_t)0; return pat->type; } vkvg_status_t vkvg_pattern_get_color_stop_count(VkvgPattern pat, uint32_t *count) { if (vkvg_pattern_status(pat)) return vkvg_pattern_status(pat); if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) return VKVG_STATUS_PATTERN_TYPE_MISMATCH; vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; *count = grad->count; return VKVG_STATUS_SUCCESS; } vkvg_status_t vkvg_pattern_get_color_stop_rgba(VkvgPattern pat, uint32_t index, float *offset, float *r, float *g, float *b, float *a) { if (vkvg_pattern_status(pat)) return vkvg_pattern_status(pat); if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) return VKVG_STATUS_PATTERN_TYPE_MISMATCH; vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; if (index >= grad->count) return VKVG_STATUS_INVALID_INDEX; #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT *offset = grad->stops[index]; #else *offset = grad->stops[index].r; #endif vkvg_color_t c = grad->colors[index]; *r = c.r; *g = c.g; *b = c.b; *a = c.a; return VKVG_STATUS_SUCCESS; } void vkvg_pattern_set_matrix(VkvgPattern pat, const vkvg_matrix_t *matrix) { if (vkvg_pattern_status(pat)) return; pat->matrix = *matrix; pat->hasMatrix = true; } void vkvg_pattern_get_matrix(VkvgPattern pat, vkvg_matrix_t *matrix) { if (vkvg_pattern_status(pat)) return; if (pat->hasMatrix) *matrix = pat->matrix; else *matrix = VKVG_IDENTITY_MATRIX; } vkvg_status_t vkvg_pattern_status(VkvgPattern pat) { return !pat ? VKVG_STATUS_NULL_POINTER : pat->status; } void vkvg_pattern_destroy(VkvgPattern pat) { if (vkvg_pattern_status(pat)) return; pat->references--; if (pat->references > 0) return; if (pat->type == VKVG_PATTERN_TYPE_SURFACE) { VkvgSurface surf = (VkvgSurface)pat->data; vkvg_surface_destroy(surf); } else free(pat->data); free(pat); pat = NULL; }