Blender V5.0
gpencil_draw_data.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "DRW_render.hh"
10
11#include "DNA_light_types.h"
12#include "DNA_material_types.h"
13
14#include "BKE_image.hh"
15#include "BKE_material.hh"
16
17#include "BLI_math_matrix.h"
18#include "BLI_math_vector.h"
19#include "BLI_memblock.h"
20
21#include "GPU_uniform_buffer.hh"
22
23#include "IMB_imbuf_types.hh"
24
26
27namespace blender::draw::gpencil {
28
29/* -------------------------------------------------------------------- */
32
34{
35 MaterialPool *matpool = static_cast<MaterialPool *>(BLI_memblock_alloc(inst->gp_material_pool));
36 matpool->next = nullptr;
37 matpool->used_count = 0;
38 if (matpool->ubo == nullptr) {
39 matpool->ubo = GPU_uniformbuf_create(sizeof(matpool->mat_data));
40 }
41 inst->last_material_pool = matpool;
42 return matpool;
43}
44
45static gpu::Texture *gpencil_image_texture_get(::Image *image, bool *r_alpha_premult)
46{
47 ImageUser iuser = {nullptr};
48 gpu::Texture *gpu_tex = nullptr;
49
50 gpu_tex = BKE_image_get_gpu_texture(image, &iuser);
51 *r_alpha_premult = (gpu_tex) ? (image->alpha_mode == IMA_ALPHA_PREMUL) : false;
52
53 return gpu_tex;
54}
55
56static void gpencil_uv_transform_get(const float ofs[2],
57 const float scale[2],
58 const float rotation,
59 float r_rot_scale[2][2],
60 float r_offset[2])
61{
62 /* OPTI this could use 3x2 matrices and reduce the number of operations drastically. */
63 float mat[4][4];
64 unit_m4(mat);
65 /* Offset to center. */
66 translate_m4(mat, 0.5f, 0.5f, 0.0f);
67 /* Reversed order. */
68 rescale_m4(mat, float3{1.0f / scale[0], 1.0f / scale[1], 0.0});
69 rotate_m4(mat, 'Z', -rotation);
70 translate_m4(mat, ofs[0], ofs[1], 0.0f);
71 /* Convert to 3x2 */
72 copy_v2_v2(r_rot_scale[0], mat[0]);
73 copy_v2_v2(r_rot_scale[1], mat[1]);
74 copy_v2_v2(r_offset, mat[3]);
75}
76
77static void gpencil_shade_color(float color[3])
78{
79 /* This is scene refereed color, not gamma corrected and not per perceptual.
80 * So we lower the threshold a bit. (1.0 / 3.0) */
81 if (color[0] + color[1] + color[2] > 1.1) {
82 add_v3_fl(color, -0.25f);
83 }
84 else {
85 add_v3_fl(color, 0.15f);
86 }
87 clamp_v3(color, 0.0f, 1.0f);
88}
89
90/* Apply all overrides from the solid viewport mode to the GPencil material. */
92 Instance *inst,
93 Object *ob,
94 int color_type,
95 MaterialGPencilStyle *gp_style,
96 const eV3DShadingLightingMode lighting_mode)
97{
98 static MaterialGPencilStyle gp_style_tmp;
99
100 switch (color_type) {
103 /* Random uses a random color by layer and this is done using the tint
104 * layer. A simple color by object, like meshes, is not practical in
105 * grease pencil. */
106 copy_v4_v4(gp_style_tmp.stroke_rgba, gp_style->stroke_rgba);
107 copy_v4_v4(gp_style_tmp.fill_rgba, gp_style->fill_rgba);
108 gp_style = &gp_style_tmp;
111 break;
113 gp_style_tmp = dna::shallow_copy(*gp_style);
114 gp_style = &gp_style_tmp;
115 if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) {
116 copy_v4_fl(gp_style->stroke_rgba, 1.0f);
117 gp_style->mix_stroke_factor = 0.0f;
118 }
119
120 if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) && (gp_style->ima)) {
121 copy_v4_fl(gp_style->fill_rgba, 1.0f);
122 gp_style->mix_factor = 0.0f;
123 }
124 else if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) {
125 /* gp_style->fill_rgba is needed for correct gradient. */
126 gp_style->mix_factor = 0.0f;
127 }
128 break;
130 gp_style = &gp_style_tmp;
133 copy_v3_v3(gp_style->fill_rgba, inst->v3d_single_color);
134 gp_style->fill_rgba[3] = 1.0f;
135 copy_v4_v4(gp_style->stroke_rgba, gp_style->fill_rgba);
136 if (lighting_mode != V3D_LIGHTING_FLAT) {
138 }
139 break;
141 gp_style = &gp_style_tmp;
144 copy_v4_v4(gp_style->fill_rgba, ob->color);
145 copy_v4_v4(gp_style->stroke_rgba, ob->color);
146 if (lighting_mode != V3D_LIGHTING_FLAT) {
148 }
149 break;
151 gp_style = &gp_style_tmp;
154 copy_v4_fl(gp_style->fill_rgba, 1.0f);
155 copy_v4_fl(gp_style->stroke_rgba, 1.0f);
156 break;
157 default:
158 break;
159 }
160 return gp_style;
161}
162
164 Object *ob,
165 int *ofs,
166 const bool is_vertex_mode)
167{
168 MaterialPool *matpool = inst->last_material_pool;
169
171
172 bool reuse_matpool = matpool && ((matpool->used_count + mat_len) <= GPENCIL_MATERIAL_BUFFER_LEN);
173
174 if (reuse_matpool) {
175 /* Share the matpool with other objects. Return offset to first material. */
176 *ofs = matpool->used_count;
177 }
178 else {
179 matpool = gpencil_material_pool_add(inst);
180 *ofs = 0;
181 }
182
183 /* Force vertex color in solid mode with vertex paint mode. Same behavior as meshes. */
184 int color_type = (inst->v3d_color_type != -1 && is_vertex_mode) ? V3D_SHADING_VERTEX_COLOR :
185 inst->v3d_color_type;
187 (inst->v3d != nullptr) ? eV3DShadingLightingMode(inst->v3d->shading.light) :
189
190 MaterialPool *pool = matpool;
191 for (int i = 0; i < mat_len; i++) {
192 if ((i > 0) && (pool->used_count == GPENCIL_MATERIAL_BUFFER_LEN)) {
193 pool->next = gpencil_material_pool_add(inst);
194 pool = pool->next;
195 }
196 int mat_id = pool->used_count++;
197
198 gpMaterial *mat_data = &pool->mat_data[mat_id];
200
201 if (gp_style->mode == GP_MATERIAL_MODE_LINE) {
202 mat_data->flag = 0;
203 }
204 else {
205 switch (gp_style->alignment_mode) {
208 break;
211 break;
213 default:
215 break;
216 }
217
218 if (gp_style->mode == GP_MATERIAL_MODE_DOT) {
219 mat_data->flag |= GP_STROKE_DOTS;
220 }
221 }
222
223 if ((gp_style->mode != GP_MATERIAL_MODE_LINE) ||
224 (gp_style->flag & GP_MATERIAL_DISABLE_STENCIL))
225 {
226 mat_data->flag |= GP_STROKE_OVERLAP;
227 }
228
229 /* Material with holdout. */
230 if (gp_style->flag & GP_MATERIAL_IS_STROKE_HOLDOUT) {
231 mat_data->flag |= GP_STROKE_HOLDOUT;
232 }
233 if (gp_style->flag & GP_MATERIAL_IS_FILL_HOLDOUT) {
234 mat_data->flag |= GP_FILL_HOLDOUT;
235 }
236
237 gp_style = gpencil_viewport_material_overrides(inst, ob, color_type, gp_style, lighting_mode);
238
239 /* Dots or Squares rotation. */
240 mat_data->alignment_rot[0] = cosf(gp_style->alignment_rotation);
241 mat_data->alignment_rot[1] = sinf(gp_style->alignment_rotation);
242
243 /* Stroke Style */
244 if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) {
245 bool premul;
246 pool->tex_stroke[mat_id] = gpencil_image_texture_get(gp_style->sima, &premul);
247 mat_data->flag |= pool->tex_stroke[mat_id] ? GP_STROKE_TEXTURE_USE : GP_FLAG_NONE;
248 mat_data->flag |= premul ? GP_STROKE_TEXTURE_PREMUL : GP_FLAG_NONE;
249 copy_v4_v4(mat_data->stroke_color, gp_style->stroke_rgba);
250 mat_data->stroke_texture_mix = 1.0f - gp_style->mix_stroke_factor;
251 mat_data->stroke_u_scale = 500.0f / gp_style->texture_pixsize;
252 }
253 else /* if (gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_SOLID) */ {
254 pool->tex_stroke[mat_id] = nullptr;
255 mat_data->flag &= ~GP_STROKE_TEXTURE_USE;
256 copy_v4_v4(mat_data->stroke_color, gp_style->stroke_rgba);
257 mat_data->stroke_texture_mix = 0.0f;
258 }
259
260 /* Fill Style */
261 if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) && (gp_style->ima)) {
262 bool use_clip = (gp_style->flag & GP_MATERIAL_TEX_CLAMP) != 0;
263 bool premul;
264 pool->tex_fill[mat_id] = gpencil_image_texture_get(gp_style->ima, &premul);
265 mat_data->flag |= pool->tex_fill[mat_id] ? GP_FILL_TEXTURE_USE : GP_FLAG_NONE;
266 mat_data->flag |= premul ? GP_FILL_TEXTURE_PREMUL : GP_FLAG_NONE;
267 mat_data->flag |= use_clip ? GP_FILL_TEXTURE_CLIP : GP_FLAG_NONE;
269 gp_style->texture_scale,
270 gp_style->texture_angle,
271 reinterpret_cast<float (*)[2]>(&mat_data->fill_uv_rot_scale),
272 mat_data->fill_uv_offset);
273 copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
274 mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor;
275 }
276 else if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) {
277 bool use_radial = (gp_style->gradient_type == GP_MATERIAL_GRADIENT_RADIAL);
278 pool->tex_fill[mat_id] = nullptr;
279 mat_data->flag |= GP_FILL_GRADIENT_USE;
280 mat_data->flag |= use_radial ? GP_FILL_GRADIENT_RADIAL : GP_FLAG_NONE;
282 gp_style->texture_scale,
283 gp_style->texture_angle,
284 reinterpret_cast<float (*)[2]>(&mat_data->fill_uv_rot_scale),
285 mat_data->fill_uv_offset);
286 copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
287 copy_v4_v4(mat_data->fill_mix_color, gp_style->mix_rgba);
288 mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor;
289 if (gp_style->flag & GP_MATERIAL_FLIP_FILL) {
290 swap_v4_v4(mat_data->fill_color, mat_data->fill_mix_color);
291 }
292 }
293 else /* if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) */ {
294 pool->tex_fill[mat_id] = nullptr;
295 copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
296 mat_data->fill_texture_mix = 0.0f;
297 }
298 }
299
300 return matpool;
301}
302
304 int mat_id,
305 gpu::Texture **r_tex_stroke,
306 gpu::Texture **r_tex_fill,
307 gpu::UniformBuf **r_ubo_mat)
308{
309 MaterialPool *matpool = first_pool;
310 BLI_assert(mat_id >= 0);
311 int pool_id = mat_id / GPENCIL_MATERIAL_BUFFER_LEN;
312 for (int i = 0; i < pool_id; i++) {
313 matpool = matpool->next;
314 }
315 mat_id = mat_id % GPENCIL_MATERIAL_BUFFER_LEN;
316 *r_ubo_mat = matpool->ubo;
317 if (r_tex_fill) {
318 *r_tex_fill = matpool->tex_fill[mat_id];
319 }
320 if (r_tex_stroke) {
321 *r_tex_stroke = matpool->tex_stroke[mat_id];
322 }
323}
324
326
327/* -------------------------------------------------------------------- */
330
332{
333 LightPool *lightpool = static_cast<LightPool *>(BLI_memblock_alloc(inst->gp_light_pool));
334 lightpool->light_used = 0;
335 /* Tag light list end. */
336 lightpool->light_data[0].color[0] = -1.0;
337 if (lightpool->ubo == nullptr) {
338 lightpool->ubo = GPU_uniformbuf_create(sizeof(lightpool->light_data));
339 }
340 inst->last_light_pool = lightpool;
341 return lightpool;
342}
343
344void gpencil_light_ambient_add(LightPool *lightpool, const float color[3])
345{
346 if (lightpool->light_used >= GPENCIL_LIGHT_BUFFER_LEN) {
347 return;
348 }
349
350 gpLight *gp_light = &lightpool->light_data[lightpool->light_used];
351 gp_light->type = GP_LIGHT_TYPE_AMBIENT;
352 copy_v3_v3(gp_light->color, color);
353 lightpool->light_used++;
354
355 if (lightpool->light_used < GPENCIL_LIGHT_BUFFER_LEN) {
356 /* Tag light list end. */
357 gp_light[1].color[0] = -1.0f;
358 }
359}
360
361static float light_power_get(const Light *la)
362{
363 if (la->type == LA_AREA) {
364 return 1.0f / (4.0f * M_PI);
365 }
366 if (ELEM(la->type, LA_SPOT, LA_LOCAL)) {
367 return 1.0f / (4.0f * M_PI * M_PI);
368 }
369
370 return 1.0f / M_PI;
371}
372
374{
376
377 if (lightpool->light_used >= GPENCIL_LIGHT_BUFFER_LEN) {
378 return;
379 }
380
381 gpLight *gp_light = &lightpool->light_data[lightpool->light_used];
382 float (*mat)[4] = reinterpret_cast<float (*)[4]>(&gp_light->right);
383
384 if (light.type == LA_SPOT) {
385 copy_m4_m4(mat, ob->world_to_object().ptr());
386 gp_light->type = GP_LIGHT_TYPE_SPOT;
387 gp_light->spot_size = cosf(light.spotsize * 0.5f);
388 gp_light->spot_blend = (1.0f - gp_light->spot_size) * light.spotblend;
389 }
390 else if (light.type == LA_AREA) {
391 /* Simulate area lights using a spot light. */
392 normalize_m4_m4(mat, ob->object_to_world().ptr());
393 invert_m4(mat);
394 gp_light->type = GP_LIGHT_TYPE_SPOT;
395 gp_light->spot_size = cosf(M_PI_2);
396 gp_light->spot_blend = (1.0f - gp_light->spot_size) * 1.0f;
397 }
398 else if (light.type == LA_SUN) {
399 normalize_v3_v3(gp_light->forward, ob->object_to_world().ptr()[2]);
400 gp_light->type = GP_LIGHT_TYPE_SUN;
401 }
402 else {
403 gp_light->type = GP_LIGHT_TYPE_POINT;
404 }
405 copy_v4_v4(gp_light->position, ob->object_to_world().location());
406 copy_v3_v3(gp_light->color, &light.r);
407 mul_v3_fl(gp_light->color, light.energy * light_power_get(&light));
408
409 lightpool->light_used++;
410
411 if (lightpool->light_used < GPENCIL_LIGHT_BUFFER_LEN) {
412 /* Tag light list end. */
413 gp_light[1].color[0] = -1.0f;
414 }
415}
416
418{
419 LightPool *lightpool = inst->last_light_pool;
420
421 if (lightpool == nullptr) {
422 lightpool = gpencil_light_pool_add(inst);
423 }
424 /* TODO(fclem): Light linking. */
425 // gpencil_light_pool_populate(lightpool, ob);
426
427 return lightpool;
428}
429
431
432} // namespace blender::draw::gpencil
blender::gpu::Texture * BKE_image_get_gpu_texture(Image *image, ImageUser *iuser)
Definition image_gpu.cc:496
General operations, lookup, etc. for materials.
MaterialGPencilStyle * BKE_gpencil_material_settings(Object *ob, short act)
int BKE_object_material_used_with_fallback_eval(const Object &ob)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define M_PI
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void rescale_m4(float mat[4][4], const float scale[3])
void rotate_m4(float mat[4][4], char axis, float angle)
void unit_m4(float m[4][4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void swap_v4_v4(float a[4], float b[4])
MINLINE void add_v3_fl(float r[3], float f)
MINLINE void clamp_v3(float vec[3], float min, float max)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v4_fl(float r[4], float f)
void * BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define ELEM(...)
@ IMA_ALPHA_PREMUL
@ LA_AREA
@ LA_LOCAL
@ LA_SPOT
@ LA_SUN
@ GP_MATERIAL_STROKE_STYLE_SOLID
@ GP_MATERIAL_STROKE_STYLE_TEXTURE
@ GP_MATERIAL_FOLLOW_OBJ
@ GP_MATERIAL_FOLLOW_PATH
@ GP_MATERIAL_FOLLOW_FIXED
@ GP_MATERIAL_FLIP_FILL
@ GP_MATERIAL_DISABLE_STENCIL
@ GP_MATERIAL_IS_STROKE_HOLDOUT
@ GP_MATERIAL_IS_FILL_HOLDOUT
@ GP_MATERIAL_TEX_CLAMP
@ GP_MATERIAL_GRADIENT_RADIAL
@ GP_MATERIAL_MODE_DOT
@ GP_MATERIAL_MODE_LINE
@ GP_MATERIAL_FILL_STYLE_GRADIENT
@ GP_MATERIAL_FILL_STYLE_TEXTURE
@ GP_MATERIAL_FILL_STYLE_SOLID
@ V3D_SHADING_TEXTURE_COLOR
@ V3D_SHADING_VERTEX_COLOR
@ V3D_SHADING_MATERIAL_COLOR
@ V3D_SHADING_OBJECT_COLOR
@ V3D_SHADING_RANDOM_COLOR
@ V3D_SHADING_SINGLE_COLOR
eV3DShadingLightingMode
@ V3D_LIGHTING_FLAT
@ V3D_LIGHTING_STUDIO
T & DRW_object_get_data_for_drawing(const Object &object)
#define GPU_uniformbuf_create(size)
nullptr float
#define GPENCIL_MATERIAL_BUFFER_LEN
#define GPENCIL_LIGHT_BUFFER_LEN
@ GP_FILL_TEXTURE_USE
@ GP_STROKE_HOLDOUT
@ GP_STROKE_TEXTURE_PREMUL
@ GP_STROKE_ALIGNMENT_STROKE
@ GP_FILL_TEXTURE_PREMUL
@ GP_STROKE_TEXTURE_USE
@ GP_STROKE_ALIGNMENT_OBJECT
@ GP_FILL_GRADIENT_USE
@ GP_FILL_TEXTURE_CLIP
@ GP_FILL_GRADIENT_RADIAL
@ GP_STROKE_OVERLAP
@ GP_FILL_HOLDOUT
@ GP_STROKE_ALIGNMENT_FIXED
@ GP_LIGHT_TYPE_AMBIENT
void gpencil_light_ambient_add(LightPool *lightpool, const float color[3])
static float light_power_get(const Light *la)
static gpu::Texture * gpencil_image_texture_get(::Image *image, bool *r_alpha_premult)
static void gpencil_shade_color(float color[3])
void gpencil_light_pool_populate(LightPool *lightpool, Object *ob)
LightPool * gpencil_light_pool_add(Instance *inst)
static MaterialGPencilStyle * gpencil_viewport_material_overrides(Instance *inst, Object *ob, int color_type, MaterialGPencilStyle *gp_style, const eV3DShadingLightingMode lighting_mode)
void gpencil_material_resources_get(MaterialPool *first_pool, int mat_id, gpu::Texture **r_tex_stroke, gpu::Texture **r_tex_fill, gpu::UniformBuf **r_ubo_mat)
static MaterialPool * gpencil_material_pool_add(Instance *inst)
static void gpencil_uv_transform_get(const float ofs[2], const float scale[2], const float rotation, float r_rot_scale[2][2], float r_offset[2])
LightPool * gpencil_light_pool_create(Instance *inst, Object *)
MaterialPool * gpencil_material_pool_create(Instance *inst, Object *ob, int *ofs, const bool is_vertex_mode)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
VecBase< float, 3 > float3
#define sinf
#define cosf
char alpha_mode
float color[4]
View3DShading shading
gpLight light_data[GPENCIL_LIGHT_BUFFER_LEN]
gpu::Texture * tex_fill[GPENCIL_MATERIAL_BUFFER_LEN]
gpu::Texture * tex_stroke[GPENCIL_MATERIAL_BUFFER_LEN]
gpMaterial mat_data[GPENCIL_MATERIAL_BUFFER_LEN]
gpMaterialFlag flag
i
Definition text_draw.cc:230