1 // Copyright (c) 2015 Sergio Gonzalez. All rights reserved.
2 // License: https://github.com/serge-rgb/milton#license
3
4 #include "canvas.h"
5 #include "utils.h"
6
7 v2l
canvas_to_raster_with_scale(CanvasView * view,v2l canvas_point,i64 scale)8 canvas_to_raster_with_scale(CanvasView* view, v2l canvas_point, i64 scale)
9 {
10
11 f32 x = (canvas_point.x - view->pan_center.x);
12 f32 y = (canvas_point.y - view->pan_center.y);
13
14
15 f32 cos_angle = cosf(-view->angle);
16 f32 sin_angle = sinf(-view->angle);
17
18 v2l raster_point = {
19 i64(x * cos_angle - y * sin_angle) / scale + view->zoom_center.x,
20 i64(y * cos_angle + x * sin_angle) / scale + view->zoom_center.y,
21 };
22 return raster_point;
23 }
24
25 v2l
raster_to_canvas_with_scale(CanvasView * view,v2l raster_point,i64 scale)26 raster_to_canvas_with_scale(CanvasView* view, v2l raster_point, i64 scale)
27 {
28 f32 cos_angle = cosf(view->angle);
29 f32 sin_angle = sinf(view->angle);
30
31 // i64 x = raster_point.x * cos_angle - raster_point.y * sin_angle;
32 // i64 y = raster_point.y * cos_angle + raster_point.x * sin_angle;
33
34 i64 x = (raster_point.x - view->zoom_center.x);
35 i64 y = (raster_point.y - view->zoom_center.y);
36
37 v2l canvas_point = {
38 i64(x * cos_angle - y * sin_angle) * scale + view->pan_center.x,
39 i64(y * cos_angle + x * sin_angle) * scale + view->pan_center.y,
40 };
41
42 return canvas_point;
43 }
44
45 v2l
raster_to_canvas(CanvasView * view,v2l raster_point)46 raster_to_canvas(CanvasView* view, v2l raster_point)
47 {
48 return raster_to_canvas_with_scale(view, raster_point, view->scale);
49 }
50
51 v2l
canvas_to_raster(CanvasView * view,v2l canvas_point)52 canvas_to_raster(CanvasView* view, v2l canvas_point)
53 {
54 return canvas_to_raster_with_scale(view, canvas_point, view->scale);
55 }
56
57 Rect
raster_to_canvas_bounding_rect(CanvasView * view,i32 x,i32 y,i32 w,i32 h,i64 scale)58 raster_to_canvas_bounding_rect(CanvasView* view, i32 x, i32 y, i32 w, i32 h, i64 scale)
59 {
60 Rect result = rect_without_size();
61
62 v2l corners[4] = {
63 v2l{ x, y },
64 v2l{ x+w, y },
65 v2l{ x+w, y+h },
66 v2l{ x, y+h },
67 };
68
69 for (int i = 0; i < 4; ++i) {
70 v2l p = raster_to_canvas_with_scale(view, corners[i], scale);
71 if (p.x < result.left) {
72 result.left = p.x;
73 }
74 if (p.x > result.right) {
75 result.right = p.x;
76 }
77 if (p.y < result.top) {
78 result.top = p.y;
79 }
80 if (p.y > result.bottom) {
81 result.bottom = p.y;
82 }
83 }
84
85 return result;
86 }
87
88 Rect
canvas_to_raster_bounding_rect(CanvasView * view,Rect rect)89 canvas_to_raster_bounding_rect(CanvasView* view, Rect rect)
90 {
91 Rect result = rect_without_size();
92
93 v2l corners[4] = {
94 v2l{ rect.left, rect.top },
95 v2l{ rect.right, rect.top },
96 v2l{ rect.right, rect.bottom },
97 v2l{ rect.left, rect.bottom },
98 };
99
100 for (int i = 0; i < 4; ++i) {
101 v2l p = canvas_to_raster(view, corners[i]);
102 if (p.x < result.left) {
103 result.left = p.x;
104 }
105 if (p.x > result.right) {
106 result.right = p.x;
107 }
108 if (p.y < result.top) {
109 result.top = p.y;
110 }
111 if (p.y > result.bottom) {
112 result.bottom = p.y;
113 }
114 }
115
116 return result;
117 }
118
119 void
reset_transform_at_origin(v2l * pan_center,i64 * scale,f32 * angle)120 reset_transform_at_origin(v2l* pan_center, i64* scale, f32* angle)
121 {
122 *pan_center = {};
123 *scale = 1024;
124 *angle = 0.0f;
125 }
126
127
128 // Does point p0 with radius r0 contain point p1 with radius r1?
129 b32
stroke_point_contains_point(v2l p0,i64 r0,v2l p1,i64 r1)130 stroke_point_contains_point(v2l p0, i64 r0, v2l p1, i64 r1)
131 {
132 v2l d = p1 - p0;
133 // using manhattan distance, less chance of overflow. Still works well enough for this case.
134 u64 m = (u64)MLT_ABS(d.x) + MLT_ABS(d.y) + r1;
135 //i32 m = magnitude_i(d) + r1;
136 b32 contained = false;
137 if ( r0 >= 0 ) {
138 contained = (m < (u64)r0);
139 } else {
140 contained = true;
141 }
142 return contained;
143 }
144
145 Rect
bounding_box_for_stroke(Stroke * stroke)146 bounding_box_for_stroke(Stroke* stroke)
147 {
148 Rect bb = bounding_rect_for_points(stroke->points, stroke->num_points);
149 Rect bb_enlarged = rect_enlarge(bb, stroke->brush.radius);
150 return bb_enlarged;
151 }
152
153 Rect
bounding_box_for_last_n_points(Stroke * stroke,i32 last_n)154 bounding_box_for_last_n_points(Stroke* stroke, i32 last_n)
155 {
156 i32 forward = max(stroke->num_points - last_n, 0);
157 i32 num_points = min(last_n, stroke->num_points);
158 Rect bb = bounding_rect_for_points(stroke->points + forward, num_points);
159 Rect bb_enlarged = rect_enlarge(bb, stroke->brush.radius);
160 return bb_enlarged;
161 }
162
163 Rect
canvas_rect_to_raster_rect(CanvasView * view,Rect canvas_rect)164 canvas_rect_to_raster_rect(CanvasView* view, Rect canvas_rect)
165 {
166 Rect raster_rect;
167 raster_rect.bot_right = canvas_to_raster(view, canvas_rect.bot_right);
168 raster_rect.top_left = canvas_to_raster(view, canvas_rect.top_left);
169 return raster_rect;
170 }
171
172
173 namespace layer
174 {
175 i64
count_strokes(Layer * root)176 count_strokes(Layer* root)
177 {
178 i64 count = 0;
179 for ( Layer *layer = root;
180 layer != NULL;
181 layer = layer->next ) {
182 count += layer->strokes.count;
183 }
184 return count;
185 }
186
187 Layer*
get_topmost(Layer * root)188 get_topmost(Layer* root)
189 {
190 Layer* layer = root;
191 while ( layer->next ) {
192 layer = layer->next;
193 }
194 return layer;
195 }
196 Layer*
get_by_id(Layer * root_layer,i32 id)197 get_by_id(Layer* root_layer, i32 id)
198 {
199 Layer* l = NULL;
200 for ( Layer* layer = root_layer; layer; layer = layer->next ) {
201 if ( layer->id == id ) {
202 l = layer;
203 }
204 }
205 return l;
206 }
207
208 // Push stroke at the top of the current layer
209 Stroke*
layer_push_stroke(Layer * layer,Stroke stroke)210 layer_push_stroke(Layer* layer, Stroke stroke)
211 {
212 push(&layer->strokes, stroke);
213 return peek(&layer->strokes);
214 }
215
216 b32
layer_has_blur_effect(Layer * layer)217 layer_has_blur_effect(Layer* layer)
218 {
219 b32 result = false;
220 for ( LayerEffect* e = layer->effects; e != NULL; e = e->next ) {
221 if ( e->enabled && e->type == LayerEffectType_BLUR ) {
222 result = true;
223 break;
224 }
225 }
226 return result;
227 }
228
229
230 void
layer_toggle_visibility(Layer * layer)231 layer_toggle_visibility(Layer* layer)
232 {
233 b32 visible = layer->flags & LayerFlags_VISIBLE;
234 if ( visible ) {
235 layer->flags &= ~LayerFlags_VISIBLE;
236 } else {
237 layer->flags |= LayerFlags_VISIBLE;
238 }
239 }
240
241 i32
number_of_layers(Layer * layer)242 number_of_layers(Layer* layer)
243 {
244 int n = 0;
245 while ( layer ) {
246 ++n;
247 layer = layer->next;
248 }
249 return n;
250 }
251
252 } // namespace layer
253