[6d5e378] | 1 | /*
|
---|
| 2 | * Copyright (c) 2012 Petr Koupy
|
---|
| 3 | * All rights reserved.
|
---|
| 4 | *
|
---|
| 5 | * Redistribution and use in source and binary forms, with or without
|
---|
| 6 | * modification, are permitted provided that the following conditions
|
---|
| 7 | * are met:
|
---|
| 8 | *
|
---|
| 9 | * - Redistributions of source code must retain the above copyright
|
---|
| 10 | * notice, this list of conditions and the following disclaimer.
|
---|
| 11 | * - Redistributions in binary form must reproduce the above copyright
|
---|
| 12 | * notice, this list of conditions and the following disclaimer in the
|
---|
| 13 | * documentation and/or other materials provided with the distribution.
|
---|
| 14 | * - The name of the author may not be used to endorse or promote products
|
---|
| 15 | * derived from this software without specific prior written permission.
|
---|
| 16 | *
|
---|
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
---|
| 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
---|
| 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
---|
| 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
---|
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
---|
| 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
---|
| 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
---|
| 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
| 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
---|
| 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 27 | */
|
---|
| 28 |
|
---|
| 29 | /** @addtogroup draw
|
---|
| 30 | * @{
|
---|
| 31 | */
|
---|
| 32 | /**
|
---|
| 33 | * @file
|
---|
| 34 | */
|
---|
| 35 |
|
---|
| 36 | #include <assert.h>
|
---|
| 37 | #include <adt/list.h>
|
---|
[38d150e] | 38 | #include <stdlib.h>
|
---|
[6d5e378] | 39 |
|
---|
| 40 | #include "drawctx.h"
|
---|
| 41 |
|
---|
| 42 | void drawctx_init(drawctx_t *context, surface_t *surface)
|
---|
| 43 | {
|
---|
| 44 | assert(surface);
|
---|
| 45 | list_initialize(&context->list);
|
---|
| 46 | context->surface = surface;
|
---|
| 47 | context->compose = compose_src;
|
---|
| 48 | context->mask = NULL;
|
---|
| 49 | context->source = NULL;
|
---|
| 50 | context->shall_clip = false;
|
---|
| 51 | context->clip_x = 0;
|
---|
| 52 | context->clip_y = 0;
|
---|
| 53 | surface_get_resolution(surface, &context->clip_width, &context->clip_height);
|
---|
| 54 | }
|
---|
| 55 |
|
---|
| 56 | void drawctx_save(drawctx_t *context)
|
---|
| 57 | {
|
---|
| 58 | drawctx_t *to_save = (drawctx_t *) malloc(sizeof(drawctx_t));
|
---|
| 59 | if (to_save) {
|
---|
| 60 | link_initialize(&to_save->link);
|
---|
| 61 | to_save->compose = context->compose;
|
---|
| 62 | to_save->mask = context->mask;
|
---|
| 63 | to_save->source = context->source;
|
---|
| 64 | to_save->shall_clip = context->shall_clip;
|
---|
| 65 | to_save->clip_x = context->clip_x;
|
---|
| 66 | to_save->clip_y = context->clip_y;
|
---|
| 67 | to_save->clip_width = context->clip_width;
|
---|
| 68 | to_save->clip_height = context->clip_height;
|
---|
| 69 | list_append(&to_save->link, &context->list);
|
---|
| 70 | }
|
---|
| 71 | }
|
---|
| 72 |
|
---|
| 73 | void drawctx_restore(drawctx_t *context)
|
---|
| 74 | {
|
---|
| 75 | drawctx_t *to_load = (drawctx_t *) list_last(&context->list);
|
---|
| 76 | if (to_load) {
|
---|
| 77 | list_remove(&to_load->link);
|
---|
| 78 | context->compose = to_load->compose;
|
---|
| 79 | context->mask = to_load->mask;
|
---|
| 80 | context->source = to_load->source;
|
---|
| 81 | context->shall_clip = to_load->shall_clip;
|
---|
| 82 | context->clip_x = to_load->clip_x;
|
---|
| 83 | context->clip_y = to_load->clip_y;
|
---|
| 84 | context->clip_width = to_load->clip_width;
|
---|
| 85 | context->clip_height = to_load->clip_height;
|
---|
| 86 | free(to_load);
|
---|
| 87 | }
|
---|
| 88 | }
|
---|
| 89 |
|
---|
| 90 | void drawctx_set_compose(drawctx_t *context, compose_t compose)
|
---|
| 91 | {
|
---|
| 92 | context->compose = compose;
|
---|
| 93 | }
|
---|
| 94 |
|
---|
| 95 | void drawctx_set_clip(drawctx_t *context,
|
---|
| 96 | sysarg_t x, sysarg_t y, sysarg_t width, sysarg_t height)
|
---|
| 97 | {
|
---|
| 98 | surface_get_resolution(context->surface,
|
---|
| 99 | &context->clip_width, &context->clip_height);
|
---|
| 100 | context->shall_clip = (x > 0) || (y > 0) ||
|
---|
| 101 | (width < context->clip_width) || (height < context->clip_height);
|
---|
| 102 |
|
---|
| 103 | context->clip_x = x;
|
---|
| 104 | context->clip_y = y;
|
---|
| 105 | context->clip_width = width;
|
---|
| 106 | context->clip_height = height;
|
---|
| 107 | }
|
---|
| 108 |
|
---|
| 109 | void drawctx_set_mask(drawctx_t *context, surface_t *mask)
|
---|
| 110 | {
|
---|
| 111 | context->mask = mask;
|
---|
| 112 | }
|
---|
| 113 |
|
---|
| 114 | void drawctx_set_source(drawctx_t *context, source_t *source)
|
---|
| 115 | {
|
---|
| 116 | context->source = source;
|
---|
| 117 | }
|
---|
| 118 |
|
---|
| 119 | void drawctx_set_font(drawctx_t *context, font_t *font)
|
---|
| 120 | {
|
---|
| 121 | context->font = font;
|
---|
| 122 | }
|
---|
| 123 |
|
---|
| 124 | void drawctx_transfer(drawctx_t *context,
|
---|
| 125 | sysarg_t x, sysarg_t y, sysarg_t width, sysarg_t height)
|
---|
| 126 | {
|
---|
| 127 | if (!context->source) {
|
---|
| 128 | return;
|
---|
| 129 | }
|
---|
| 130 |
|
---|
[75baf6e] | 131 | bool transfer_fast = source_is_fast(context->source) &&
|
---|
| 132 | (context->shall_clip == false) &&
|
---|
| 133 | (context->mask == NULL) &&
|
---|
| 134 | (context->compose == compose_src || context->compose == compose_over);
|
---|
[7dba813] | 135 |
|
---|
| 136 | if (transfer_fast) {
|
---|
| 137 |
|
---|
| 138 | for (sysarg_t _y = y; _y < y + height; ++_y) {
|
---|
| 139 | pixel_t *src = source_direct_access(context->source, x, _y);
|
---|
| 140 | pixel_t *dst = pixelmap_pixel_at(surface_pixmap_access(context->surface), x, _y);
|
---|
| 141 | if (src && dst) {
|
---|
| 142 | sysarg_t count = width;
|
---|
| 143 | while (count-- != 0) {
|
---|
| 144 | *dst++ = *src++;
|
---|
| 145 | }
|
---|
[6d5e378] | 146 | }
|
---|
[7dba813] | 147 | }
|
---|
| 148 | surface_add_damaged_region(context->surface, x, y, width, height);
|
---|
| 149 |
|
---|
| 150 | } else {
|
---|
| 151 |
|
---|
| 152 | bool clipped = false;
|
---|
| 153 | bool masked = false;
|
---|
| 154 | for (sysarg_t _y = y; _y < y + height; ++_y) {
|
---|
| 155 | for (sysarg_t _x = x; _x < x + width; ++_x) {
|
---|
| 156 | if (context->shall_clip) {
|
---|
[3bacee1] | 157 | clipped = _x < context->clip_x && _x >= context->clip_width &&
|
---|
| 158 | _y < context->clip_y && _y >= context->clip_height;
|
---|
[7dba813] | 159 | }
|
---|
| 160 |
|
---|
| 161 | if (context->mask) {
|
---|
| 162 | pixel_t p = surface_get_pixel(context->mask, _x, _y);
|
---|
| 163 | masked = p > 0 ? false : true;
|
---|
| 164 | }
|
---|
| 165 |
|
---|
| 166 | if (!clipped && !masked) {
|
---|
| 167 | pixel_t p_src = source_determine_pixel(context->source, _x, _y);
|
---|
| 168 | pixel_t p_dst = surface_get_pixel(context->surface, _x, _y);
|
---|
| 169 | pixel_t p_res = context->compose(p_src, p_dst);
|
---|
| 170 | surface_put_pixel(context->surface, _x, _y, p_res);
|
---|
| 171 | }
|
---|
[6d5e378] | 172 | }
|
---|
| 173 | }
|
---|
[7dba813] | 174 |
|
---|
[6d5e378] | 175 | }
|
---|
| 176 | }
|
---|
| 177 |
|
---|
| 178 | void drawctx_stroke(drawctx_t *context, path_t *path)
|
---|
| 179 | {
|
---|
| 180 | if (!context->source || !path) {
|
---|
| 181 | return;
|
---|
| 182 | }
|
---|
| 183 |
|
---|
[7c3fb9b] | 184 | /*
|
---|
| 185 | * Note:
|
---|
[6d5e378] | 186 | * Antialiasing could be achieved by up-scaling path coordinates and
|
---|
| 187 | * rendering into temporary higher-resolution surface. Then, the temporary
|
---|
| 188 | * surface would be set as a source and its damaged region would be
|
---|
[7c3fb9b] | 189 | * transferred to the original surface.
|
---|
| 190 | */
|
---|
[6d5e378] | 191 |
|
---|
[feeac0d] | 192 | list_foreach(*((list_t *) path), link, path_step_t, step) {
|
---|
[6d5e378] | 193 | switch (step->type) {
|
---|
| 194 | case PATH_STEP_MOVETO:
|
---|
| 195 | // TODO
|
---|
| 196 | break;
|
---|
| 197 | case PATH_STEP_LINETO:
|
---|
| 198 | // TODO
|
---|
| 199 | break;
|
---|
| 200 | default:
|
---|
| 201 | break;
|
---|
| 202 | }
|
---|
| 203 | }
|
---|
| 204 | }
|
---|
| 205 |
|
---|
| 206 | void drawctx_fill(drawctx_t *context, path_t *path)
|
---|
| 207 | {
|
---|
| 208 | if (!context->source || !path) {
|
---|
| 209 | return;
|
---|
| 210 | }
|
---|
| 211 |
|
---|
| 212 | // TODO
|
---|
| 213 | }
|
---|
| 214 |
|
---|
| 215 | void drawctx_print(drawctx_t *context, const char *text, sysarg_t x, sysarg_t y)
|
---|
| 216 | {
|
---|
| 217 | if (context->font && context->source) {
|
---|
| 218 | font_draw_text(context->font, context, context->source, text, x, y);
|
---|
| 219 | }
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 | /** @}
|
---|
| 223 | */
|
---|