Initial Grease Pencil 3.0 stage #106848
|
@ -115,19 +115,19 @@ static void grease_pencil_blend_write(BlendWriter *writer, ID *id, const void *i
|
||||||
GreasePencilLayerTreeNode *node = grease_pencil->layer_tree_storage.nodes[i];
|
GreasePencilLayerTreeNode *node = grease_pencil->layer_tree_storage.nodes[i];
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case GREASE_PENCIL_LAYER_TREE_LEAF: {
|
case GREASE_PENCIL_LAYER_TREE_LEAF: {
|
||||||
GreasePencilLayerTreeLeaf *node_leaf = reinterpret_cast<GreasePencilLayerTreeLeaf
|
GreasePencilLayerTreeLeaf *node_leaf = reinterpret_cast<GreasePencilLayerTreeLeaf *>(node);
|
||||||
*>(node); BLO_write_struct(writer, GreasePencilLayerTreeLeaf, node_leaf);
|
BLO_write_struct(writer, GreasePencilLayerTreeLeaf, node_leaf);
|
||||||
/* Write layer data. */
|
/* Write layer data. */
|
||||||
BLO_write_int32_array(
|
BLO_write_int32_array(
|
||||||
writer, node_leaf->layer.frames_storage.size, node_leaf->layer.frames_storage.keys);
|
writer, node_leaf->layer.frames_storage.size, node_leaf->layer.frames_storage.keys);
|
||||||
BLO_write_int32_array(
|
BLO_write_int32_array(
|
||||||
writer, node_leaf->layer.frames_storage.size,
|
writer, node_leaf->layer.frames_storage.size, node_leaf->layer.frames_storage.values);
|
||||||
node_leaf->layer.frames_storage.values);
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
}
|
}
|
||||||
case GREASE_PENCIL_LAYER_TREE_GROUP: {
|
case GREASE_PENCIL_LAYER_TREE_GROUP: {
|
||||||
GreasePencilLayerTreeGroup *group = reinterpret_cast<GreasePencilLayerTreeGroup
|
GreasePencilLayerTreeGroup *group = reinterpret_cast<GreasePencilLayerTreeGroup *>(node);
|
||||||
*>(node); BLO_write_struct(writer, GreasePencilLayerTreeGroup, group); break;
|
BLO_write_struct(writer, GreasePencilLayerTreeGroup, group);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Bastien Montagne
commented
How can you be sure here that the potential memory allocated to the if memory in Would be better to have a proper destructor for these structs anyway imho, even if not really needed right now. How can you be sure here that the potential memory allocated to the `batch_cache` is freed?
if memory in `batch_cache` is managed by drawing code, a comment in the runtime struct should specify it.
Would be better to have a proper destructor for these structs anyway imho, even if not really needed right now.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,20 +171,19 @@ static void grease_pencil_blend_read_data(BlendDataReader *reader, ID *id)
|
||||||
GreasePencilLayerTreeNode *node = grease_pencil->layer_tree_storage.nodes[i];
|
GreasePencilLayerTreeNode *node = grease_pencil->layer_tree_storage.nodes[i];
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
Hans Goudey
commented
C++ cast here C++ cast here
|
|||||||
case GREASE_PENCIL_LAYER_TREE_LEAF: {
|
case GREASE_PENCIL_LAYER_TREE_LEAF: {
|
||||||
GreasePencilLayerTreeLeaf *node_leaf = reinterpret_cast<GreasePencilLayerTreeLeaf
|
GreasePencilLayerTreeLeaf *node_leaf = reinterpret_cast<GreasePencilLayerTreeLeaf *>(node);
|
||||||
*>(node); BLO_read_data_address(reader, &node_leaf);
|
BLO_read_data_address(reader, &node_leaf);
|
||||||
filedescriptor marked this conversation as resolved
Outdated
Bastien Montagne
commented
Code is missing re-reading Code is missing re-reading `active_layer` address...
|
|||||||
/* Read layer data. */
|
/* Read layer data. */
|
||||||
BLO_read_int32_array(
|
BLO_read_int32_array(
|
||||||
reader, node_leaf->layer.frames_storage.size,
|
reader, node_leaf->layer.frames_storage.size, &node_leaf->layer.frames_storage.keys);
|
||||||
&node_leaf->layer.frames_storage.keys);
|
|
||||||
BLO_read_int32_array(
|
BLO_read_int32_array(
|
||||||
reader, node_leaf->layer.frames_storage.size,
|
reader, node_leaf->layer.frames_storage.size, &node_leaf->layer.frames_storage.values);
|
||||||
&node_leaf->layer.frames_storage.values);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GREASE_PENCIL_LAYER_TREE_GROUP: {
|
case GREASE_PENCIL_LAYER_TREE_GROUP: {
|
||||||
GreasePencilLayerTreeGroup *group = reinterpret_cast<GreasePencilLayerTreeGroup
|
GreasePencilLayerTreeGroup *group = reinterpret_cast<GreasePencilLayerTreeGroup *>(node);
|
||||||
*>(node); BLO_read_data_address(reader, &group); break;
|
BLO_read_data_address(reader, &group);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
* \ingroup draw
|
* \ingroup draw
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "BKE_gpencil_legacy.h"
|
|
||||||
#include "BKE_gpencil_modifier_legacy.h"
|
#include "BKE_gpencil_modifier_legacy.h"
|
||||||
#include "BLI_listbase_wrapper.hh"
|
#include "BLI_listbase_wrapper.hh"
|
||||||
#include "DEG_depsgraph_query.h"
|
#include "DEG_depsgraph_query.h"
|
||||||
|
@ -139,9 +138,11 @@ class Instance {
|
||||||
void object_sync(Manager &manager, ObjectRef &object_ref)
|
void object_sync(Manager &manager, ObjectRef &object_ref)
|
||||||
{
|
{
|
||||||
switch (object_ref.object->type) {
|
switch (object_ref.object->type) {
|
||||||
case OB_GPENCIL_LEGACY:
|
// case OB_GPENCIL_LEGACY:
|
||||||
|
// objects.sync_gpencil(manager, object_ref, main_fb_, main_ps_);
|
||||||
|
// break;
|
||||||
|
case OB_GREASE_PENCIL:
|
||||||
objects.sync_gpencil(manager, object_ref, main_fb_, main_ps_);
|
objects.sync_gpencil(manager, object_ref, main_fb_, main_ps_);
|
||||||
break;
|
|
||||||
case OB_LAMP:
|
case OB_LAMP:
|
||||||
lights.sync(object_ref);
|
lights.sync(object_ref);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "BKE_gpencil_legacy.h"
|
#include "BKE_grease_pencil.hh"
|
||||||
#include "BKE_image.h"
|
#include "BKE_image.h"
|
||||||
filedescriptor marked this conversation as resolved
Sergey Sharybin
commented
I am not sure all of those are needed here. I am not sure all of those are needed here.
I.e. I do not see any `BKE_image` API used in this header. Might be missing something.
|
|||||||
#include "DRW_gpu_wrapper.hh"
|
#include "DRW_gpu_wrapper.hh"
|
||||||
#include "DRW_render.h"
|
#include "DRW_render.h"
|
||||||
|
@ -30,17 +30,17 @@ class LayerModule {
|
||||||
layers_buf_.clear();
|
layers_buf_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sync(const Object *object, const bGPDlayer *gpl, bool &do_layer_blending)
|
void sync(const Object *object, const bke::gpencil::Layer &layer, bool &do_layer_blending)
|
||||||
{
|
{
|
||||||
UNUSED_VARS(object, gpl);
|
UNUSED_VARS(object, layer);
|
||||||
Sergey Sharybin
commented
In C++ use In C++ use `void sync(const Object * /*object*/, const bke::greasepencil::Layer & /*layer*/, bool &do_layer_blending)`
|
|||||||
/* TODO(fclem): All of this is placeholder. */
|
/* TODO(fclem): All of this is placeholder. */
|
||||||
gpLayer layer;
|
gpLayer gp_layer;
|
||||||
layer.vertex_color_opacity = 0.0f;
|
gp_layer.vertex_color_opacity = 0.0f;
|
||||||
layer.opacity = 1.0f;
|
gp_layer.opacity = 1.0f;
|
||||||
layer.thickness_offset = 0.0f;
|
gp_layer.thickness_offset = 0.0f;
|
||||||
layer.tint = float4(1.0f, 1.0f, 1.0f, 0.0f);
|
gp_layer.tint = float4(1.0f, 1.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
layers_buf_.append(layer);
|
layers_buf_.append(gp_layer);
|
||||||
|
|
||||||
do_layer_blending = false;
|
do_layer_blending = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "BKE_gpencil_legacy.h"
|
#include "BKE_grease_pencil.hh"
|
||||||
#include "BKE_image.h"
|
#include "BKE_image.h"
|
||||||
#include "DRW_gpu_wrapper.hh"
|
#include "DRW_gpu_wrapper.hh"
|
||||||
#include "DRW_render.h"
|
#include "DRW_render.h"
|
||||||
|
@ -117,15 +117,16 @@ class ObjectModule {
|
||||||
Framebuffer &main_fb,
|
Framebuffer &main_fb,
|
||||||
PassSortable &main_ps)
|
PassSortable &main_ps)
|
||||||
{
|
{
|
||||||
Object *object = object_ref.object;
|
using namespace blender::bke::gpencil;
|
||||||
bGPdata *gpd = static_cast<bGPdata *>(object->data);
|
|
||||||
ListBaseWrapper<const bGPDlayer> layers(&gpd->layers);
|
|
||||||
|
|
||||||
if (BLI_listbase_is_empty(&gpd->layers)) {
|
Object *object = object_ref.object;
|
||||||
|
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||||
|
|
||||||
|
if (grease_pencil.drawings().is_empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D);
|
const bool is_stroke_order_3d = true; /* TODO */
|
||||||
bool do_material_holdout = false;
|
bool do_material_holdout = false;
|
||||||
bool do_layer_blending = false;
|
bool do_layer_blending = false;
|
||||||
bool object_has_vfx = false; // TODO vfx.object_has_vfx(gpd);
|
bool object_has_vfx = false; // TODO vfx.object_has_vfx(gpd);
|
||||||
|
@ -136,9 +137,8 @@ class ObjectModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint layer_offset = layers_.object_offset_get();
|
uint layer_offset = layers_.object_offset_get();
|
||||||
for (const bGPDlayer *layer : layers) {
|
grease_pencil.runtime->root_group().foreach_layer_pre_order(
|
||||||
layers_.sync(object, layer, do_layer_blending);
|
[&](Layer &layer) { layers_.sync(object, layer, do_layer_blending); });
|
||||||
}
|
|
||||||
|
|
||||||
/* Order rendering using camera Z distance. */
|
/* Order rendering using camera Z distance. */
|
||||||
float3 position = float3(object->object_to_world[3]);
|
float3 position = float3(object->object_to_world[3]);
|
||||||
|
@ -160,45 +160,43 @@ class ObjectModule {
|
||||||
object_subpass.state_set(state);
|
object_subpass.state_set(state);
|
||||||
object_subpass.shader_set(shaders_.static_shader_get(GREASE_PENCIL));
|
object_subpass.shader_set(shaders_.static_shader_get(GREASE_PENCIL));
|
||||||
|
|
||||||
Vector<FrameData, 5> frames;
|
grease_pencil.foreach_visible_drawing(
|
||||||
displayed_frame_select(frames, layers);
|
current_frame_, [&](GreasePencilDrawing &drawing, bke::gpencil::Layer &layer) {
|
||||||
|
/* TODO(fclem): Pass per frame object matrix here. */
|
||||||
|
ResourceHandle handle = manager.resource_handle(object_ref);
|
||||||
|
gpObject &ob = objects_buf_.get_or_resize(handle.resource_index());
|
||||||
Sergey Sharybin
commented
Typically dead code is discouraged. Typically dead code is discouraged.
Not sure what is it part of, so can't really give strong suggestions.
|
|||||||
|
ob.is_shadeless = false;
|
||||||
|
ob.stroke_order3d = false;
|
||||||
|
ob.tint = float4(1.0); // frame_tint_get(gpd, frame.gpf, current_frame_);
|
||||||
|
ob.layer_offset = layer_offset;
|
||||||
|
ob.material_offset = material_offset;
|
||||||
|
|
||||||
for (const FrameData &frame : frames) {
|
GPUVertBuf *position_tx = DRW_cache_gpencil_position_buffer_get(object, current_frame_);
|
||||||
/* TODO(fclem): Pass per frame object matrix here. */
|
GPUVertBuf *color_tx = DRW_cache_gpencil_color_buffer_get(object, current_frame_);
|
||||||
ResourceHandle handle = manager.resource_handle(object_ref);
|
GPUBatch *geom = DRW_cache_gpencil_get(object, current_frame_);
|
||||||
gpObject &ob = objects_buf_.get_or_resize(handle.resource_index());
|
|
||||||
ob.is_shadeless = false;
|
|
||||||
ob.stroke_order3d = false;
|
|
||||||
ob.tint = frame_tint_get(gpd, frame.gpf, current_frame_);
|
|
||||||
ob.layer_offset = layer_offset;
|
|
||||||
ob.material_offset = material_offset;
|
|
||||||
|
|
||||||
GPUVertBuf *position_tx = DRW_cache_gpencil_position_buffer_get(object, frame.gpf->framenum);
|
if (do_layer_blending) {
|
||||||
GPUVertBuf *color_tx = DRW_cache_gpencil_color_buffer_get(object, frame.gpf->framenum);
|
// for (const LayerData &layer : frame.layers) {
|
||||||
GPUBatch *geom = DRW_cache_gpencil_get(object, frame.gpf->framenum);
|
// UNUSED_VARS(layer);
|
||||||
|
// if (has_blending(layer)) {
|
||||||
|
// object_subpass.framebuffer_set(*vfx_fb.current());
|
||||||
|
// }
|
||||||
|
|
||||||
if (do_layer_blending) {
|
/* TODO(fclem): Only draw subrange of geometry for this layer. */
|
||||||
for (const LayerData &layer : frame.layers) {
|
object_subpass.draw(geom, handle);
|
||||||
UNUSED_VARS(layer);
|
|
||||||
// if (has_blending(layer)) {
|
|
||||||
// object_subpass.framebuffer_set(*vfx_fb.current());
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* TODO(fclem): Only draw subrange of geometry for this layer. */
|
// if (has_blending(layer)) {
|
||||||
object_subpass.draw(geom, handle);
|
// layer_blend_sync(object_ref, object_subpass);
|
||||||
Sergey Sharybin
commented
Add a comment what is this about, or remove. Add a comment what is this about, or remove.
|
|||||||
|
// }
|
||||||
// if (has_blending(layer)) {
|
// }
|
||||||
// layer_blend_sync(object_ref, object_subpass);
|
}
|
||||||
// }
|
else {
|
||||||
}
|
/* Fast path. */
|
||||||
}
|
object_subpass.bind_texture("gp_pos_tx", position_tx);
|
||||||
else {
|
object_subpass.bind_texture("gp_col_tx", color_tx);
|
||||||
/* Fast path. */
|
object_subpass.draw(geom, handle);
|
||||||
object_subpass.bind_texture("gp_pos_tx", position_tx);
|
}
|
||||||
object_subpass.bind_texture("gp_col_tx", color_tx);
|
});
|
||||||
object_subpass.draw(geom, handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (object_has_vfx) {
|
if (object_has_vfx) {
|
||||||
|
@ -262,43 +260,44 @@ class ObjectModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static float4 frame_tint_get(const bGPdata *gpd, const bGPDframe *gpf, int /* current_frame */)
|
// static float4 frame_tint_get(const bGPdata *gpd, const bGPDframe *gpf, int /* current_frame
|
||||||
{
|
// */)
|
||||||
/* TODO(fclem): Onion color should rely on time and or frame id and not on runtime.onion_id.
|
// {
|
||||||
* This should be evaluated at draw time as it is just a way of displaying the data. */
|
// /* TODO(fclem): Onion color should rely on time and or frame id and not on runtime.onion_id.
|
||||||
const bool use_onion_custom_col = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0;
|
// * This should be evaluated at draw time as it is just a way of displaying the data. */
|
||||||
const bool use_onion_fade = (gpd->onion_flag & GP_ONION_FADE) != 0;
|
// const bool use_onion_custom_col = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0;
|
||||||
const bool use_next_col = gpf->runtime.onion_id > 0.0f;
|
// const bool use_onion_fade = (gpd->onion_flag & GP_ONION_FADE) != 0;
|
||||||
|
// const bool use_next_col = gpf->runtime.onion_id > 0.0f;
|
||||||
|
|
||||||
const float *onion_col_custom = (use_onion_custom_col) ?
|
// const float *onion_col_custom = (use_onion_custom_col) ?
|
||||||
(use_next_col ? gpd->gcolor_next : gpd->gcolor_prev) :
|
// (use_next_col ? gpd->gcolor_next : gpd->gcolor_prev) :
|
||||||
U.gpencil_new_layer_col;
|
// U.gpencil_new_layer_col;
|
||||||
|
|
||||||
float4 tint = {UNPACK3(onion_col_custom), 1.0f};
|
// float4 tint = {UNPACK3(onion_col_custom), 1.0f};
|
||||||
|
|
||||||
tint[3] = use_onion_fade ? (1.0f / abs(gpf->runtime.onion_id)) : 0.5f;
|
// tint[3] = use_onion_fade ? (1.0f / abs(gpf->runtime.onion_id)) : 0.5f;
|
||||||
tint[3] *= gpd->onion_factor;
|
// tint[3] *= gpd->onion_factor;
|
||||||
tint[3] = (gpd->onion_factor > 0.0f) ? clamp_f(tint[3], 0.1f, 1.0f) :
|
// tint[3] = (gpd->onion_factor > 0.0f) ? clamp_f(tint[3], 0.1f, 1.0f) :
|
||||||
clamp_f(tint[3], 0.01f, 1.0f);
|
// clamp_f(tint[3], 0.01f, 1.0f);
|
||||||
return tint;
|
// return tint;
|
||||||
}
|
// }
|
||||||
|
|
||||||
void displayed_frame_select(Vector<FrameData, 5> &frames,
|
// void displayed_frame_select(Vector<FrameData, 5> &frames,
|
||||||
ListBaseWrapper<const bGPDlayer> layers)
|
// ListBaseWrapper<const bGPDlayer> layers)
|
||||||
{
|
// {
|
||||||
/* TODO(fclem): Select onion skin frames. */
|
// /* TODO(fclem): Select onion skin frames. */
|
||||||
/** \note Change data layout to be Frame major instead of Layer major.
|
// /** \note Change data layout to be Frame major instead of Layer major.
|
||||||
* Hopefully the GPencil data layout will be closer to that in the future. */
|
// * Hopefully the GPencil data layout will be closer to that in the future. */
|
||||||
FrameData frame_data;
|
// FrameData frame_data;
|
||||||
frame_data.gpf = layers.get(0)->actframe;
|
// frame_data.gpf = layers.get(0)->actframe;
|
||||||
for (const bGPDlayer *layer : layers) {
|
// for (const bGPDlayer *layer : layers) {
|
||||||
LayerData layer_data;
|
// LayerData layer_data;
|
||||||
layer_data.gpf = layer->actframe;
|
// layer_data.gpf = layer->actframe;
|
||||||
layer_data.gpl = layer;
|
// layer_data.gpl = layer;
|
||||||
frame_data.layers.append(layer_data);
|
// frame_data.layers.append(layer_data);
|
||||||
}
|
// }
|
||||||
frames.append(frame_data);
|
// frames.append(frame_data);
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::gpencil
|
} // namespace blender::gpencil
|
||||||
|
|
These two lines could use
MEM_SAFE_FREE
macro instead.MEM_SAFE_FREE
does not replaceMEM_delete
, it replacesMEM_freeN
, which is different.I was under the impression that any memory allocated with
MEM_new
should useMEM_delete
because we also need to run the destructor.