Merge branch 'master' into blender2.8
[blender.git] / source / blender / blenkernel / intern / icons_rasterize.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * ***** END GPL LICENSE BLOCK *****
19  *
20  */
21
22 /** \file blender/blenkernel/intern/icons_rasterize.c
23  *  \ingroup bke
24  */
25 #include "MEM_guardedalloc.h"
26
27 #include "BLI_utildefines.h"
28 #include "BLI_bitmap_draw_2d.h"
29 #include "BLI_math_geom.h"
30
31 #include "IMB_imbuf.h"
32 #include "IMB_imbuf_types.h"
33
34 #include "BKE_icons.h"
35
36 #include "BLI_strict_flags.h"
37
38 struct UserRasterInfo {
39         int pt[3][2];
40         const uint *color;
41         /* only for smooth shading */
42         struct {
43                 float pt_fl[3][2];
44                 uint color_u[3][4];
45         } smooth;
46         int   rect_size[2];
47         uint *rect;
48 };
49
50 static void tri_fill_flat(int x, int x_end, int y, void *user_data)
51 {
52         struct UserRasterInfo *data = user_data;
53         uint *p = &data->rect[(y * data->rect_size[1]) + x];
54         uint col = data->color[0];
55         while (x++ != x_end) {
56                 *p++ = col;
57         }
58 }
59
60 static void tri_fill_smooth(int x, int x_end, int y, void *user_data)
61 {
62         struct UserRasterInfo *data = user_data;
63         uint *p = &data->rect[(y * data->rect_size[1]) + x];
64         float pt_step_fl[2] = {(float)x, (float)y};
65         while (x++ != x_end) {
66                 float w[3];
67                 barycentric_weights_v2_clamped(UNPACK3(data->smooth.pt_fl), pt_step_fl, w);
68
69                 uint col_u[4] = {0, 0, 0, 0};
70                 for (uint corner = 0; corner < 3; corner++) {
71                         for (uint chan = 0; chan < 4; chan++) {
72                                 col_u[chan] += data->smooth.color_u[corner][chan] * (uint)(w[corner] * 255.0f);
73                         }
74                 }
75                 union {
76                         uint  as_u32;
77                         uchar as_bytes[4];
78                 } col;
79                 col.as_bytes[0] = (uchar)(col_u[0] / 255);
80                 col.as_bytes[1] = (uchar)(col_u[1] / 255);
81                 col.as_bytes[2] = (uchar)(col_u[2] / 255);
82                 col.as_bytes[3] = (uchar)(col_u[3] / 255);
83                 *p++ = col.as_u32;
84
85                 pt_step_fl[0] += 1.0f;
86         }
87 }
88
89 ImBuf *BKE_icon_geom_rasterize(
90         const struct Icon_Geom *geom,
91         const unsigned int size_x, const unsigned int size_y)
92 {
93         const int coords_len = geom->coords_len;
94
95         const uchar (*pos)[2] = geom->coords;
96         const uint   *col = (void *)geom->colors;
97
98         /* TODO(campbell): Currently rasterizes to fixed size, then scales.
99          * Should rasterize to double size for eg instead. */
100         const int rect_size[2] = {max_ii(256, (int)size_x * 2), max_ii(256, (int)size_y * 2)};
101
102         ImBuf *ibuf = IMB_allocImBuf((uint)rect_size[0], (uint)rect_size[1], 32, IB_rect);
103
104         struct UserRasterInfo data;
105
106         data.rect_size[0] = rect_size[0];
107         data.rect_size[1] = rect_size[1];
108
109         data.rect = ibuf->rect;
110
111         float scale[2];
112         const bool use_scale = (rect_size[0] != 256) || (rect_size[1] != 256);
113
114         if (use_scale) {
115                 scale[0] = ((float)rect_size[0] / 256.0f);
116                 scale[1] = ((float)rect_size[1] / 256.0f);
117         }
118
119         for (int t = 0; t < coords_len; t += 1, pos += 3, col += 3) {
120                 if (use_scale) {
121                         ARRAY_SET_ITEMS(data.pt[0], (int)(pos[0][0] * scale[0]), (int)(pos[0][1] * scale[1]));
122                         ARRAY_SET_ITEMS(data.pt[1], (int)(pos[1][0] * scale[0]), (int)(pos[1][1] * scale[1]));
123                         ARRAY_SET_ITEMS(data.pt[2], (int)(pos[2][0] * scale[0]), (int)(pos[2][1] * scale[1]));
124                 }
125                 else {
126                         ARRAY_SET_ITEMS(data.pt[0], UNPACK2(pos[0]));
127                         ARRAY_SET_ITEMS(data.pt[1], UNPACK2(pos[1]));
128                         ARRAY_SET_ITEMS(data.pt[2], UNPACK2(pos[2]));
129                 }
130                 data.color = col;
131                 if ((col[0] == col[1]) && (col[0] == col[2])) {
132                         BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_flat, &data);
133                 }
134                 else {
135                         ARRAY_SET_ITEMS(data.smooth.pt_fl[0], UNPACK2_EX((float), data.pt[0], ));
136                         ARRAY_SET_ITEMS(data.smooth.pt_fl[1], UNPACK2_EX((float), data.pt[1], ));
137                         ARRAY_SET_ITEMS(data.smooth.pt_fl[2], UNPACK2_EX((float), data.pt[2], ));
138                         ARRAY_SET_ITEMS(data.smooth.color_u[0], UNPACK4_EX((uint), ((uchar *)(col + 0)), ));
139                         ARRAY_SET_ITEMS(data.smooth.color_u[1], UNPACK4_EX((uint), ((uchar *)(col + 1)), ));
140                         ARRAY_SET_ITEMS(data.smooth.color_u[2], UNPACK4_EX((uint), ((uchar *)(col + 2)), ));
141                         BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_smooth, &data);
142                 }
143         }
144         IMB_scaleImBuf(ibuf, size_x, size_y);
145         return ibuf;
146 }