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