Merge branch 'blender-v4.3-release'
This commit is contained in:
@@ -26,7 +26,6 @@ _modules = [
|
||||
"properties_data_curve",
|
||||
"properties_data_curves",
|
||||
"properties_data_empty",
|
||||
"properties_data_gpencil",
|
||||
"properties_data_grease_pencil",
|
||||
"properties_data_light",
|
||||
"properties_data_lattice",
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2018-2023 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import bpy
|
||||
from bpy.types import Menu, Panel, UIList
|
||||
from rna_prop_ui import PropertyPanel
|
||||
from .space_properties import PropertiesAnimationMixin
|
||||
|
||||
###############################
|
||||
# Base-Classes (for shared stuff - e.g. poll, attributes, etc.)
|
||||
|
||||
|
||||
class DataButtonsPanel:
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "data"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.gpencil
|
||||
|
||||
|
||||
class ObjectButtonsPanel:
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "data"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
ob = context.object
|
||||
return ob and ob.type == 'GPENCIL'
|
||||
|
||||
|
||||
class LayerDataButtonsPanel:
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "data"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
gpencil = context.gpencil
|
||||
return gpencil and gpencil.layers.active
|
||||
|
||||
|
||||
###############################
|
||||
# GP Object Properties Panels and Helper Classes
|
||||
|
||||
class DATA_PT_context_gpencil(DataButtonsPanel, Panel):
|
||||
bl_label = ""
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
ob = context.object
|
||||
space = context.space_data
|
||||
|
||||
if ob:
|
||||
layout.template_ID(ob, "data")
|
||||
else:
|
||||
layout.template_ID(space, "pin_id")
|
||||
|
||||
|
||||
class DATA_PT_gpencil_onion_skinning(DataButtonsPanel, Panel):
|
||||
bl_label = "Onion Skinning"
|
||||
|
||||
def draw(self, context):
|
||||
gpd = context.gpencil
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
col = layout.column()
|
||||
col.prop(gpd, "onion_mode")
|
||||
col.prop(gpd, "onion_factor", text="Opacity", slider=True)
|
||||
col.prop(gpd, "onion_keyframe_type")
|
||||
|
||||
if gpd.onion_mode == 'ABSOLUTE':
|
||||
col = layout.column(align=True)
|
||||
col.prop(gpd, "ghost_before_range", text="Frames Before")
|
||||
col.prop(gpd, "ghost_after_range", text="Frames After")
|
||||
elif gpd.onion_mode == 'RELATIVE':
|
||||
col = layout.column(align=True)
|
||||
col.prop(gpd, "ghost_before_range", text="Keyframes Before")
|
||||
col.prop(gpd, "ghost_after_range", text="Keyframes After")
|
||||
|
||||
|
||||
class DATA_PT_gpencil_onion_skinning_custom_colors(DataButtonsPanel, Panel):
|
||||
bl_parent_id = "DATA_PT_gpencil_onion_skinning"
|
||||
bl_label = "Custom Colors"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw_header(self, context):
|
||||
gpd = context.gpencil
|
||||
|
||||
self.layout.prop(gpd, "use_ghost_custom_colors", text="")
|
||||
|
||||
def draw(self, context):
|
||||
gpd = context.gpencil
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.enabled = gpd.users <= 1 and gpd.use_ghost_custom_colors
|
||||
|
||||
layout.prop(gpd, "before_color", text="Before")
|
||||
layout.prop(gpd, "after_color", text="After")
|
||||
|
||||
|
||||
class DATA_PT_gpencil_onion_skinning_display(DataButtonsPanel, Panel):
|
||||
bl_parent_id = "DATA_PT_gpencil_onion_skinning"
|
||||
bl_label = "Display"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
gpd = context.gpencil
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.enabled = gpd.users <= 1
|
||||
|
||||
layout.prop(gpd, "use_ghosts_always", text="View in Render")
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(gpd, "use_onion_fade", text="Fade")
|
||||
sub = layout.column()
|
||||
sub.active = gpd.onion_mode in {'RELATIVE', 'SELECTED'}
|
||||
sub.prop(gpd, "use_onion_loop", text="Show Start Frame")
|
||||
|
||||
|
||||
class GPENCIL_UL_vgroups(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
vgroup = item
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
layout.prop(vgroup, "name", text="", emboss=False, icon_value=icon)
|
||||
icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED'
|
||||
layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False)
|
||||
elif self.layout_type == 'GRID':
|
||||
layout.alignment = 'CENTER'
|
||||
layout.label(text="", icon_value=icon)
|
||||
|
||||
|
||||
class DATA_PT_gpencil_strokes(DataButtonsPanel, Panel):
|
||||
bl_label = "Strokes"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
ob = context.object
|
||||
gpd = context.gpencil
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(gpd, "stroke_depth_order")
|
||||
|
||||
if ob:
|
||||
col.enabled = not ob.show_in_front
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(gpd, "stroke_thickness_space")
|
||||
sub = col.column()
|
||||
sub.active = gpd.stroke_thickness_space == 'WORLDSPACE'
|
||||
sub.prop(gpd, "pixel_factor", text="Thickness Scale")
|
||||
|
||||
col.prop(gpd, "edit_curve_resolution")
|
||||
|
||||
|
||||
class DATA_PT_gpencil_display(DataButtonsPanel, Panel):
|
||||
bl_label = "Viewport Display"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
gpd = context.gpencil
|
||||
|
||||
layout.prop(gpd, "edit_line_color", text="Edit Line Color")
|
||||
|
||||
|
||||
class DATA_PT_gpencil_canvas(DataButtonsPanel, Panel):
|
||||
bl_label = "Canvas"
|
||||
bl_parent_id = "DATA_PT_gpencil_display"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
gpd = context.gpencil
|
||||
grid = gpd.grid
|
||||
|
||||
row = layout.row(align=True)
|
||||
col = row.column()
|
||||
col.prop(grid, "color", text="Color")
|
||||
col.prop(grid, "scale", text="Scale")
|
||||
col.prop(grid, "offset")
|
||||
row = layout.row(align=True)
|
||||
col = row.column()
|
||||
col.prop(grid, "lines", text="Subdivisions")
|
||||
|
||||
|
||||
class DATA_PT_gpencil_animation(DataButtonsPanel, PropertiesAnimationMixin, PropertyPanel, Panel):
|
||||
_animated_id_context_property = "gpencil"
|
||||
|
||||
|
||||
class DATA_PT_custom_props_gpencil(DataButtonsPanel, PropertyPanel, Panel):
|
||||
_context_path = "object.data"
|
||||
_property_type = bpy.types.GreasePencil
|
||||
|
||||
|
||||
###############################
|
||||
|
||||
|
||||
classes = (
|
||||
DATA_PT_context_gpencil,
|
||||
DATA_PT_gpencil_onion_skinning,
|
||||
DATA_PT_gpencil_onion_skinning_custom_colors,
|
||||
DATA_PT_gpencil_onion_skinning_display,
|
||||
DATA_PT_gpencil_strokes,
|
||||
DATA_PT_gpencil_display,
|
||||
DATA_PT_gpencil_canvas,
|
||||
DATA_PT_gpencil_animation,
|
||||
DATA_PT_custom_props_gpencil,
|
||||
|
||||
GPENCIL_UL_vgroups,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
from bpy.utils import register_class
|
||||
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
@@ -20,25 +20,6 @@ struct bGPDlayer;
|
||||
struct bGPDstroke;
|
||||
struct bGPdata;
|
||||
|
||||
/**
|
||||
* Convert a curve object to grease pencil stroke.
|
||||
*
|
||||
* \param bmain: Main thread pointer
|
||||
* \param scene: Original scene.
|
||||
* \param ob_gp: Grease pencil object to add strokes.
|
||||
* \param ob_cu: Curve to convert.
|
||||
* \param use_collections: Create layers using collection names.
|
||||
* \param scale_thickness: Scale thickness factor.
|
||||
* \param sample: Sample distance, zero to disable.
|
||||
*/
|
||||
void BKE_gpencil_convert_curve(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
struct Object *ob_gp,
|
||||
struct Object *ob_cu,
|
||||
bool use_collections,
|
||||
float scale_thickness,
|
||||
float sample);
|
||||
|
||||
/**
|
||||
* Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil stroke points.
|
||||
*/
|
||||
@@ -46,32 +27,12 @@ struct bGPDcurve *BKE_gpencil_stroke_editcurve_generate(struct bGPDstroke *gps,
|
||||
float error_threshold,
|
||||
float corner_angle,
|
||||
float stroke_radius);
|
||||
/**
|
||||
* Updates the edit-curve for a stroke. Frees the old curve if one exists and generates a new one.
|
||||
*/
|
||||
void BKE_gpencil_stroke_editcurve_update(struct bGPdata *gpd,
|
||||
struct bGPDlayer *gpl,
|
||||
struct bGPDstroke *gps);
|
||||
/**
|
||||
* Sync the selection from stroke to edit-curve.
|
||||
*/
|
||||
void BKE_gpencil_editcurve_stroke_sync_selection(struct bGPdata *gpd,
|
||||
struct bGPDstroke *gps,
|
||||
struct bGPDcurve *gpc);
|
||||
/**
|
||||
* Sync the selection from edit-curve to stroke.
|
||||
*/
|
||||
void BKE_gpencil_stroke_editcurve_sync_selection(struct bGPdata *gpd,
|
||||
struct bGPDstroke *gps,
|
||||
struct bGPDcurve *gpc);
|
||||
void BKE_gpencil_strokes_selected_update_editcurve(struct bGPdata *gpd);
|
||||
void BKE_gpencil_strokes_selected_sync_selection_editcurve(struct bGPdata *gpd);
|
||||
/**
|
||||
* Recalculate stroke points with the edit-curve of the stroke.
|
||||
*/
|
||||
void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps,
|
||||
uint resolution,
|
||||
bool is_adaptive);
|
||||
/**
|
||||
* Recalculate the handles of the edit curve of a grease pencil stroke.
|
||||
*/
|
||||
|
||||
@@ -67,57 +67,12 @@ void BKE_gpencil_stroke_boundingbox_calc(struct bGPDstroke *gps);
|
||||
* \param r_normal: Return Normal vector normalized
|
||||
*/
|
||||
void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]);
|
||||
/**
|
||||
* Reduce a series of points to a simplified version,
|
||||
* but maintains the general shape of the series.
|
||||
*
|
||||
* Ramer - Douglas - Peucker algorithm
|
||||
* by http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gps: Grease pencil stroke
|
||||
* \param epsilon: Epsilon value to define precision of the algorithm
|
||||
*/
|
||||
void BKE_gpencil_stroke_simplify_adaptive(struct bGPdata *gpd,
|
||||
struct bGPDstroke *gps,
|
||||
float epsilon);
|
||||
/**
|
||||
* Simplify alternate vertex of stroke except extremes.
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gps: Grease pencil stroke
|
||||
*/
|
||||
void BKE_gpencil_stroke_simplify_fixed(struct bGPdata *gpd, struct bGPDstroke *gps);
|
||||
/**
|
||||
* Subdivide a stroke
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gps: Stroke
|
||||
* \param level: Level of subdivision
|
||||
* \param type: Type of subdivision
|
||||
*/
|
||||
void BKE_gpencil_stroke_subdivide(struct bGPdata *gpd,
|
||||
struct bGPDstroke *gps,
|
||||
int level,
|
||||
int type);
|
||||
|
||||
/**
|
||||
* Trim stroke to the first intersection or loop.
|
||||
* \param gps: Stroke data
|
||||
*/
|
||||
bool BKE_gpencil_stroke_trim(struct bGPdata *gpd, struct bGPDstroke *gps);
|
||||
/**
|
||||
* Reduce a series of points when the distance is below a threshold.
|
||||
* Special case for first and last points (both are kept) for other points,
|
||||
* the merge point always is at first point.
|
||||
*
|
||||
* \param gpd: Grease pencil data-block.
|
||||
* \param gpf: Grease Pencil frame.
|
||||
* \param gps: Grease Pencil stroke.
|
||||
* \param threshold: Distance between points.
|
||||
* \param use_unselected: Set to true to analyze all stroke and not only selected points.
|
||||
*/
|
||||
void BKE_gpencil_stroke_merge_distance(struct bGPdata *gpd,
|
||||
struct bGPDframe *gpf,
|
||||
struct bGPDstroke *gps,
|
||||
float threshold,
|
||||
bool use_unselected);
|
||||
|
||||
/**
|
||||
* Get points of stroke always flat to view not affected
|
||||
@@ -199,18 +154,6 @@ void BKE_gpencil_point_coords_apply_with_mat4(struct bGPdata *gpd,
|
||||
const GPencilPointCoordinates *elem_data,
|
||||
const float mat[4][4]);
|
||||
|
||||
/**
|
||||
* Resample a stroke
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gps: Stroke to sample
|
||||
* \param dist: Distance of one segment
|
||||
* \param sharp_threshold: Threshold for preserving sharp corners
|
||||
*/
|
||||
bool BKE_gpencil_stroke_sample(struct bGPdata *gpd,
|
||||
struct bGPDstroke *gps,
|
||||
const float dist,
|
||||
const bool select,
|
||||
const float sharp_threshold);
|
||||
/**
|
||||
* Apply smooth position to stroke point.
|
||||
* \param gps: Stroke to smooth
|
||||
@@ -293,47 +236,7 @@ void BKE_gpencil_stroke_smooth(struct bGPDstroke *gps,
|
||||
* \param gps: Stroke to close
|
||||
*/
|
||||
bool BKE_gpencil_stroke_close(struct bGPDstroke *gps);
|
||||
/**
|
||||
* Dissolve points in stroke.
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gpf: Grease pencil frame
|
||||
* \param gps: Grease pencil stroke
|
||||
* \param tag: Type of tag for point
|
||||
*/
|
||||
void BKE_gpencil_dissolve_points(struct bGPdata *gpd,
|
||||
struct bGPDframe *gpf,
|
||||
struct bGPDstroke *gps,
|
||||
short tag);
|
||||
|
||||
/**
|
||||
* Backbone stretch similar to Freestyle.
|
||||
* \param gps: Stroke to sample.
|
||||
* \param dist: Length of the added section.
|
||||
* \param overshoot_fac: Relative length of the curve which is used to determine the extension.
|
||||
* \param mode: Affect to Start, End or Both extremes (0->Both, 1->Start, 2->End).
|
||||
* \param follow_curvature: True for approximating curvature of given overshoot.
|
||||
* \param extra_point_count: When follow_curvature is true, use this amount of extra points.
|
||||
*/
|
||||
bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps,
|
||||
float dist,
|
||||
float overshoot_fac,
|
||||
short mode,
|
||||
bool follow_curvature,
|
||||
int extra_point_count,
|
||||
float segment_influence,
|
||||
float max_angle,
|
||||
bool invert_curvature);
|
||||
/**
|
||||
* Trim stroke to needed segments.
|
||||
* \param gps: Target stroke.
|
||||
* \param index_from: the index of the first point to be used in the trimmed result.
|
||||
* \param index_to: the index of the last point to be used in the trimmed result.
|
||||
* \param keep_point: Keep strokes with one point. False remove the single points strokes
|
||||
*/
|
||||
bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps,
|
||||
int index_from,
|
||||
int index_to,
|
||||
const bool keep_point);
|
||||
/**
|
||||
* Split the given stroke into several new strokes, partitioning
|
||||
* it based on whether the stroke points have a particular flag
|
||||
@@ -347,38 +250,11 @@ struct bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd,
|
||||
bool select,
|
||||
bool flat_cap,
|
||||
int limit);
|
||||
void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd,
|
||||
struct bGPDframe *gpf,
|
||||
struct bGPDstroke *gps,
|
||||
struct bGPDstroke *next_stroke,
|
||||
struct bGPDcurve *gpc,
|
||||
int tag_flags);
|
||||
|
||||
/**
|
||||
* Flip stroke.
|
||||
*/
|
||||
void BKE_gpencil_stroke_flip(struct bGPDstroke *gps);
|
||||
/**
|
||||
* Split stroke.
|
||||
* \param gpd: Grease pencil data-block.
|
||||
* \param gpf: Grease pencil frame.
|
||||
* \param gps: Grease pencil original stroke.
|
||||
* \param before_index: Position of the point to split.
|
||||
* \param remaining_gps: Secondary stroke after split.
|
||||
* \return True if the split was done
|
||||
*/
|
||||
bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
|
||||
struct bGPDframe *gpf,
|
||||
struct bGPDstroke *gps,
|
||||
int before_index,
|
||||
struct bGPDstroke **remaining_gps);
|
||||
/**
|
||||
* Shrink the stroke by length.
|
||||
* \param gps: Stroke to shrink
|
||||
* \param dist: delta length
|
||||
* \param mode: 1->Start, 2->End
|
||||
*/
|
||||
bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, float dist, short mode);
|
||||
|
||||
/**
|
||||
* Calculate grease pencil stroke length.
|
||||
@@ -409,63 +285,6 @@ void BKE_gpencil_stroke_join(struct bGPDstroke *gps_a,
|
||||
bool fit_thickness,
|
||||
bool smooth,
|
||||
bool auto_flip);
|
||||
/**
|
||||
* Set stroke start point in the selected index. Only works for Cyclic strokes.
|
||||
* \param start_idx: Index of the point to be the start point.
|
||||
*/
|
||||
void BKE_gpencil_stroke_start_set(struct bGPDstroke *gps, int start_idx);
|
||||
/**
|
||||
* Copy the stroke of the frame to all frames selected (except current).
|
||||
*/
|
||||
void BKE_gpencil_stroke_copy_to_keyframes(struct bGPdata *gpd,
|
||||
struct bGPDlayer *gpl,
|
||||
struct bGPDframe *gpf,
|
||||
struct bGPDstroke *gps,
|
||||
bool tail);
|
||||
|
||||
/**
|
||||
* Convert a mesh object to grease pencil stroke.
|
||||
*
|
||||
* \param bmain: Main thread pointer.
|
||||
* \param depsgraph: Original depsgraph.
|
||||
* \param scene: Original scene.
|
||||
* \param ob_gp: Grease pencil object to add strokes.
|
||||
* \param ob_mesh: Mesh to convert.
|
||||
* \param angle: Limit angle to consider a edge-loop ends.
|
||||
* \param thickness: Thickness of the strokes.
|
||||
* \param offset: Offset along the normals.
|
||||
* \param matrix: Transformation matrix.
|
||||
* \param frame_offset: Destination frame number offset.
|
||||
* \param use_seams: Only export seam edges.
|
||||
* \param use_faces: Export faces as filled strokes.
|
||||
*/
|
||||
bool BKE_gpencil_convert_mesh(struct Main *bmain,
|
||||
struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct Object *ob_gp,
|
||||
struct Object *ob_mesh,
|
||||
float angle,
|
||||
int thickness,
|
||||
float offset,
|
||||
const float matrix[4][4],
|
||||
int frame_offset,
|
||||
bool use_seams,
|
||||
bool use_faces,
|
||||
bool use_vgroups);
|
||||
|
||||
/**
|
||||
* Subdivide the grease pencil stroke so the number of points is target_number.
|
||||
* Does not change the shape of the stroke. The new points will be distributed as
|
||||
* uniformly as possible by repeatedly subdividing the current longest edge.
|
||||
*
|
||||
* \param gps: The stroke to be up-sampled.
|
||||
* \param target_number: The number of points the up-sampled stroke should have.
|
||||
* \param select: Select/Deselect the stroke.
|
||||
*/
|
||||
void BKE_gpencil_stroke_uniform_subdivide(struct bGPdata *gpd,
|
||||
struct bGPDstroke *gps,
|
||||
uint32_t target_number,
|
||||
bool select);
|
||||
|
||||
/**
|
||||
* Stroke to view space
|
||||
@@ -485,18 +304,6 @@ void BKE_gpencil_stroke_to_view_space(struct bGPDstroke *gps,
|
||||
void BKE_gpencil_stroke_from_view_space(struct bGPDstroke *gps,
|
||||
float viewinv[4][4],
|
||||
const float diff_mat[4][4]);
|
||||
/**
|
||||
* Calculates the perimeter of a stroke projected from the view and returns it as a new stroke.
|
||||
* \param subdivisions: Number of subdivisions for the start and end caps.
|
||||
* \return bGPDstroke pointer to stroke perimeter.
|
||||
*/
|
||||
struct bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(float viewmat[4][4],
|
||||
struct bGPdata *gpd,
|
||||
const struct bGPDlayer *gpl,
|
||||
struct bGPDstroke *gps,
|
||||
int subdivisions,
|
||||
const float diff_mat[4][4],
|
||||
const float thickness_chg);
|
||||
/**
|
||||
* Get average pressure.
|
||||
*/
|
||||
|
||||
@@ -42,8 +42,6 @@ struct bGPdata;
|
||||
#define GPENCIL_SIMPLIFY_FILL(scene, playing) \
|
||||
((GPENCIL_SIMPLIFY_ONPLAY(playing) && GPENCIL_SIMPLIFY(scene) && \
|
||||
(scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL)))
|
||||
#define GPENCIL_SIMPLIFY_MODIF(scene) \
|
||||
((GPENCIL_SIMPLIFY(scene) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER)))
|
||||
#define GPENCIL_SIMPLIFY_FX(scene, playing) \
|
||||
((GPENCIL_SIMPLIFY_ONPLAY(playing) && GPENCIL_SIMPLIFY(scene) && \
|
||||
(scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FX)))
|
||||
@@ -55,20 +53,6 @@ struct bGPdata;
|
||||
/* Vertex Color macros. */
|
||||
#define GPENCIL_USE_VERTEX_COLOR(toolsettings) \
|
||||
(((toolsettings)->gp_paint->mode == GPPAINT_FLAG_USE_VERTEXCOLOR))
|
||||
#define GPENCIL_USE_VERTEX_COLOR_STROKE(toolsettings, brush) \
|
||||
((GPENCIL_USE_VERTEX_COLOR(toolsettings) && \
|
||||
(((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
|
||||
((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
|
||||
#define GPENCIL_USE_VERTEX_COLOR_FILL(toolsettings, brush) \
|
||||
((GPENCIL_USE_VERTEX_COLOR(toolsettings) && \
|
||||
(((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
|
||||
((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
|
||||
#define GPENCIL_TINT_VERTEX_COLOR_STROKE(brush) \
|
||||
(((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
|
||||
((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
|
||||
#define GPENCIL_TINT_VERTEX_COLOR_FILL(brush) \
|
||||
(((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
|
||||
((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
|
||||
|
||||
/* ------------ Grease-Pencil API ------------------ */
|
||||
|
||||
@@ -88,11 +72,6 @@ void BKE_gpencil_free_layers(struct ListBase *list);
|
||||
void BKE_gpencil_free_legacy_palette_data(struct ListBase *list);
|
||||
/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
|
||||
void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all);
|
||||
/**
|
||||
* Delete grease pencil evaluated data
|
||||
* \param gpd_eval: Grease pencil data-block
|
||||
*/
|
||||
void BKE_gpencil_eval_delete(struct bGPdata *gpd_eval);
|
||||
void BKE_gpencil_free_layer_masks(struct bGPDlayer *gpl);
|
||||
/**
|
||||
* Tag data-block for depsgraph update.
|
||||
@@ -104,17 +83,6 @@ void BKE_gpencil_tag(struct bGPdata *gpd);
|
||||
void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd);
|
||||
void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
|
||||
|
||||
/**
|
||||
* Ensure selection status of stroke is in sync with its points.
|
||||
* \param gps: Grease pencil stroke
|
||||
*/
|
||||
void BKE_gpencil_stroke_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
|
||||
void BKE_gpencil_curve_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
|
||||
/** Assign unique stroke ID for selection. */
|
||||
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps);
|
||||
/** Reset unique stroke ID for selection. */
|
||||
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps);
|
||||
|
||||
/**
|
||||
* Add a new gp-frame to the given layer.
|
||||
* \param gpl: Grease pencil layer
|
||||
@@ -164,38 +132,6 @@ struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src,
|
||||
bool dup_frames,
|
||||
bool dup_strokes);
|
||||
|
||||
/**
|
||||
* Make a copy of a given gpencil data settings.
|
||||
*/
|
||||
void BKE_gpencil_data_copy_settings(const struct bGPdata *gpd_src, struct bGPdata *gpd_dst);
|
||||
|
||||
/**
|
||||
* Make a copy of a given gpencil layer settings.
|
||||
*/
|
||||
void BKE_gpencil_layer_copy_settings(const struct bGPDlayer *gpl_src, struct bGPDlayer *gpl_dst);
|
||||
|
||||
/**
|
||||
* Make a copy of a given gpencil frame settings.
|
||||
*/
|
||||
void BKE_gpencil_frame_copy_settings(const struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
|
||||
|
||||
/**
|
||||
* Make a copy of a given gpencil stroke settings.
|
||||
*/
|
||||
void BKE_gpencil_stroke_copy_settings(const struct bGPDstroke *gps_src,
|
||||
struct bGPDstroke *gps_dst);
|
||||
|
||||
/**
|
||||
* Make a copy of strokes between gpencil frames.
|
||||
* \param gpf_src: Source grease pencil frame
|
||||
* \param gpf_dst: Destination grease pencil frame
|
||||
*/
|
||||
void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
|
||||
/* Create a hash with the list of selected frame number. */
|
||||
void BKE_gpencil_frame_selected_hash(struct bGPdata *gpd, struct GHash *r_list);
|
||||
|
||||
/* Make a copy of a given gpencil stroke editcurve */
|
||||
struct bGPDcurve *BKE_gpencil_stroke_curve_duplicate(struct bGPDcurve *gpc_src);
|
||||
/**
|
||||
* Make a copy of a given grease-pencil stroke.
|
||||
* \param gps_src: Source grease pencil strokes.
|
||||
@@ -216,73 +152,6 @@ struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain,
|
||||
const struct bGPdata *gpd,
|
||||
bool internal_copy);
|
||||
|
||||
/**
|
||||
* Delete the last stroke of the given frame.
|
||||
* \param gpl: Grease pencil layer
|
||||
* \param gpf: Grease pencil frame
|
||||
*/
|
||||
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
|
||||
|
||||
/* materials */
|
||||
/**
|
||||
* Reassign strokes using a material.
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param totcol: Total materials
|
||||
* \param index: Index of the material
|
||||
*/
|
||||
void BKE_gpencil_material_index_reassign(struct bGPdata *gpd, int totcol, int index);
|
||||
/**
|
||||
* Remove strokes using a material.
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param index: Index of the material
|
||||
* \return True if removed
|
||||
*/
|
||||
bool BKE_gpencil_material_index_used(struct bGPdata *gpd, int index);
|
||||
/**
|
||||
* Remap material
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param remap: Remap index
|
||||
* \param remap_len: Remap length
|
||||
*/
|
||||
void BKE_gpencil_material_remap(struct bGPdata *gpd,
|
||||
const unsigned int *remap,
|
||||
unsigned int remap_len);
|
||||
/**
|
||||
* Load a table with material conversion index for merged materials.
|
||||
* \param ob: Grease pencil object.
|
||||
* \param hue_threshold: Threshold for Hue.
|
||||
* \param sat_threshold: Threshold for Saturation.
|
||||
* \param val_threshold: Threshold for Value.
|
||||
* \param r_mat_table: return material table.
|
||||
* \return True if done.
|
||||
*/
|
||||
bool BKE_gpencil_merge_materials_table_get(struct Object *ob,
|
||||
float hue_threshold,
|
||||
float sat_threshold,
|
||||
float val_threshold,
|
||||
struct GHash *r_mat_table);
|
||||
/**
|
||||
* Merge similar materials
|
||||
* \param ob: Grease pencil object
|
||||
* \param hue_threshold: Threshold for Hue
|
||||
* \param sat_threshold: Threshold for Saturation
|
||||
* \param val_threshold: Threshold for Value
|
||||
* \param r_removed: Number of materials removed
|
||||
* \return True if done
|
||||
*/
|
||||
bool BKE_gpencil_merge_materials(struct Object *ob,
|
||||
float hue_threshold,
|
||||
float sat_threshold,
|
||||
float val_threshold,
|
||||
int *r_removed);
|
||||
|
||||
/* statistics functions */
|
||||
/**
|
||||
* Calc grease pencil statistics functions.
|
||||
* \param gpd: Grease pencil data-block
|
||||
*/
|
||||
void BKE_gpencil_stats_update(struct bGPdata *gpd);
|
||||
|
||||
/**
|
||||
* Create a new stroke, with pre-allocated data buffers.
|
||||
* \param mat_idx: Index of the material
|
||||
@@ -303,22 +172,6 @@ struct bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thic
|
||||
struct bGPDstroke *BKE_gpencil_stroke_add(
|
||||
struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, bool insert_at_head);
|
||||
|
||||
/**
|
||||
* Add a stroke and copy the temporary drawing color value
|
||||
* from one of the existing stroke.
|
||||
* \param gpf: Grease pencil frame
|
||||
* \param existing: Stroke with the style to copy
|
||||
* \param mat_idx: Material index
|
||||
* \param totpoints: Total points
|
||||
* \param thickness: Stroke thickness
|
||||
* \return Pointer to new stroke
|
||||
*/
|
||||
struct bGPDstroke *BKE_gpencil_stroke_add_existing_style(struct bGPDframe *gpf,
|
||||
struct bGPDstroke *existing,
|
||||
int mat_idx,
|
||||
int totpoints,
|
||||
short thickness);
|
||||
|
||||
struct bGPDcurve *BKE_gpencil_stroke_editcurve_new(int tot_curve_points);
|
||||
|
||||
/* Stroke and Fill - Alpha Visibility Threshold */
|
||||
@@ -405,13 +258,6 @@ void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
|
||||
*/
|
||||
void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, bool unlock);
|
||||
|
||||
/**
|
||||
* Add grease pencil mask layer.
|
||||
* \param gpl: Grease pencil layer
|
||||
* \param name: Name of the mask
|
||||
* \return Pointer to new mask layer
|
||||
*/
|
||||
struct bGPDlayer_Mask *BKE_gpencil_layer_mask_add(struct bGPDlayer *gpl, const char *name);
|
||||
/**
|
||||
* Remove grease pencil mask layer.
|
||||
* \param gpl: Grease pencil layer
|
||||
@@ -424,13 +270,6 @@ void BKE_gpencil_layer_mask_remove(struct bGPDlayer *gpl, struct bGPDlayer_Mask
|
||||
* \param name: Name of the mask layer
|
||||
*/
|
||||
void BKE_gpencil_layer_mask_remove_ref(struct bGPdata *gpd, const char *name);
|
||||
/**
|
||||
* Get mask layer by name.
|
||||
* \param gpl: Grease pencil layer
|
||||
* \param name: Mask name
|
||||
* \return Pointer to mask layer
|
||||
*/
|
||||
struct bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(struct bGPDlayer *gpl, const char *name);
|
||||
/**
|
||||
* Sort grease pencil mask layers.
|
||||
* \param gpd: Grease pencil data-block
|
||||
@@ -450,10 +289,6 @@ void BKE_gpencil_layer_mask_copy(const struct bGPDlayer *gpl_src, struct bGPDlay
|
||||
* Clean any invalid mask layer.
|
||||
*/
|
||||
void BKE_gpencil_layer_mask_cleanup(struct bGPdata *gpd, struct bGPDlayer *gpl);
|
||||
/**
|
||||
* Clean any invalid mask layer for all layers.
|
||||
*/
|
||||
void BKE_gpencil_layer_mask_cleanup_all_layers(struct bGPdata *gpd);
|
||||
|
||||
/**
|
||||
* Sort grease pencil frames.
|
||||
@@ -462,17 +297,7 @@ void BKE_gpencil_layer_mask_cleanup_all_layers(struct bGPdata *gpd);
|
||||
*/
|
||||
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames);
|
||||
|
||||
struct bGPDlayer *BKE_gpencil_layer_get_by_name(struct bGPdata *gpd,
|
||||
const char *name,
|
||||
int first_if_not_found);
|
||||
|
||||
/* Brush */
|
||||
/**
|
||||
* Get grease pencil material from brush.
|
||||
* \param brush: Brush
|
||||
* \return Pointer to material
|
||||
*/
|
||||
struct Material *BKE_gpencil_brush_material_get(struct Brush *brush);
|
||||
/**
|
||||
* Set grease pencil brush material.
|
||||
* \param brush: Brush
|
||||
@@ -480,121 +305,7 @@ struct Material *BKE_gpencil_brush_material_get(struct Brush *brush);
|
||||
*/
|
||||
void BKE_gpencil_brush_material_set(struct Brush *brush, struct Material *material);
|
||||
|
||||
/* Object */
|
||||
/**
|
||||
* Get active color, and add all default settings if we don't find anything.
|
||||
* \param ob: Grease pencil object
|
||||
* \return Material pointer
|
||||
*/
|
||||
struct Material *BKE_gpencil_object_material_ensure_active(struct Object *ob);
|
||||
/**
|
||||
* Adds the pinned material to the object if necessary.
|
||||
* \param bmain: Main pointer
|
||||
* \param ob: Grease pencil object
|
||||
* \param brush: Brush
|
||||
* \return Pointer to material
|
||||
*/
|
||||
struct Material *BKE_gpencil_object_material_ensure_from_brush(struct Main *bmain,
|
||||
struct Object *ob,
|
||||
struct Brush *brush);
|
||||
/**
|
||||
* Assigns the material to object (if not already present) and returns its index (mat_nr).
|
||||
* \param bmain: Main pointer
|
||||
* \param ob: Grease pencil object
|
||||
* \param material: Material
|
||||
* \return Index of the material
|
||||
*/
|
||||
int BKE_gpencil_object_material_ensure(struct Main *bmain,
|
||||
struct Object *ob,
|
||||
struct Material *material);
|
||||
struct Material *BKE_gpencil_object_material_ensure_by_name(struct Main *bmain,
|
||||
struct Object *ob,
|
||||
const char *name,
|
||||
int *r_index);
|
||||
|
||||
/**
|
||||
* Creates a new grease-pencil material and assigns it to object.
|
||||
* \param bmain: Main pointer
|
||||
* \param ob: Grease pencil object
|
||||
* \param name: Material name
|
||||
* \param r_index: value is set to zero based index of the new material if \a r_index is not NULL.
|
||||
* \return Material pointer.
|
||||
*/
|
||||
struct Material *BKE_gpencil_object_material_new(struct Main *bmain,
|
||||
struct Object *ob,
|
||||
const char *name,
|
||||
int *r_index);
|
||||
|
||||
/**
|
||||
* Get material index (0-based like mat_nr not #Object::actcol).
|
||||
* \param ob: Grease pencil object
|
||||
* \param ma: Material
|
||||
* \return Index of the material
|
||||
*/
|
||||
int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma);
|
||||
int BKE_gpencil_object_material_index_get_by_name(struct Object *ob, const char *name);
|
||||
|
||||
/**
|
||||
* Returns the material for a brush with respect to its pinned state.
|
||||
* \param ob: Grease pencil object
|
||||
* \param brush: Brush
|
||||
* \return Material pointer
|
||||
*/
|
||||
struct Material *BKE_gpencil_object_material_from_brush_get(struct Object *ob,
|
||||
struct Brush *brush);
|
||||
/**
|
||||
* Returns the material index for a brush with respect to its pinned state.
|
||||
* \param ob: Grease pencil object
|
||||
* \param brush: Brush
|
||||
* \return Material index.
|
||||
*/
|
||||
int BKE_gpencil_object_material_get_index_from_brush(struct Object *ob, struct Brush *brush);
|
||||
|
||||
/**
|
||||
* Guaranteed to return a material assigned to object. Returns never NULL.
|
||||
* \param bmain: Main pointer
|
||||
* \param ob: Grease pencil object
|
||||
* \return Material pointer.
|
||||
*/
|
||||
struct Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(
|
||||
struct Main *bmain, struct Object *ob, struct ToolSettings *ts);
|
||||
/**
|
||||
* Guaranteed to return a material assigned to object. Returns never NULL.
|
||||
* \param bmain: Main pointer
|
||||
* \param ob: Grease pencil object.
|
||||
* \param brush: Brush
|
||||
* \return Material pointer
|
||||
*/
|
||||
struct Material *BKE_gpencil_object_material_ensure_from_active_input_brush(struct Main *bmain,
|
||||
struct Object *ob,
|
||||
struct Brush *brush);
|
||||
/**
|
||||
* Guaranteed to return a material assigned to object. Returns never NULL.
|
||||
* Only use this for materials unrelated to user input.
|
||||
* \param ob: Grease pencil object
|
||||
* \return Material pointer
|
||||
*/
|
||||
struct Material *BKE_gpencil_object_material_ensure_from_active_input_material(struct Object *ob);
|
||||
|
||||
/**
|
||||
* Check if stroke has any point selected
|
||||
* \param gps: Grease pencil stroke
|
||||
* \return True if selected
|
||||
*/
|
||||
bool BKE_gpencil_stroke_select_check(const struct bGPDstroke *gps);
|
||||
|
||||
/* vertex groups */
|
||||
/**
|
||||
* Ensure stroke has vertex group.
|
||||
* \param gps: Grease pencil stroke
|
||||
*/
|
||||
void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps);
|
||||
/**
|
||||
* Remove a vertex group.
|
||||
* \param ob: Grease pencil object
|
||||
* \param defgroup: deform group
|
||||
*/
|
||||
void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
|
||||
/**
|
||||
* Make a copy of a given gpencil weights.
|
||||
* \param gps_src: Source grease pencil stroke
|
||||
@@ -602,14 +313,6 @@ void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup)
|
||||
*/
|
||||
void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst);
|
||||
|
||||
/* Set active frame by layer. */
|
||||
/**
|
||||
* Set current grease pencil active frame.
|
||||
* \param depsgraph: Current depsgraph
|
||||
* \param gpd: Grease pencil data-block.
|
||||
*/
|
||||
void BKE_gpencil_frame_active_set(struct Depsgraph *depsgraph, struct bGPdata *gpd);
|
||||
|
||||
/**
|
||||
* Get range of selected frames in layer.
|
||||
* Always the active frame is considered as selected, so if no more selected the range
|
||||
@@ -636,19 +339,6 @@ float BKE_gpencil_multiframe_falloff_calc(
|
||||
* \param scene: Scene
|
||||
*/
|
||||
void BKE_gpencil_palette_ensure(struct Main *bmain, struct Scene *scene);
|
||||
|
||||
/**
|
||||
* Create grease pencil strokes from image
|
||||
* \param sima: Image
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gpf: Grease pencil frame
|
||||
* \param size: Size
|
||||
* \param mask: Mask
|
||||
* \return True if done
|
||||
*/
|
||||
bool BKE_gpencil_from_image(
|
||||
struct SpaceImage *sima, struct bGPdata *gpd, struct bGPDframe *gpf, float size, bool mask);
|
||||
|
||||
/* Iterators */
|
||||
/**
|
||||
* Frame & stroke are NULL if it is a layer callback.
|
||||
@@ -658,11 +348,6 @@ typedef void (*gpIterCb)(struct bGPDlayer *layer,
|
||||
struct bGPDstroke *stroke,
|
||||
void *thunk);
|
||||
|
||||
void BKE_gpencil_visible_stroke_iter(struct bGPdata *gpd,
|
||||
gpIterCb layer_cb,
|
||||
gpIterCb stroke_cb,
|
||||
void *thunk);
|
||||
|
||||
void BKE_gpencil_visible_stroke_advanced_iter(struct ViewLayer *view_layer,
|
||||
struct Object *ob,
|
||||
gpIterCb layer_cb,
|
||||
@@ -733,17 +418,6 @@ int BKE_gpencil_material_find_index_by_name_prefix(struct Object *ob, const char
|
||||
|
||||
void BKE_gpencil_blend_read_data(struct BlendDataReader *reader, struct bGPdata *gpd);
|
||||
|
||||
bool BKE_gpencil_can_avoid_full_copy_on_write(const struct Depsgraph *depsgraph,
|
||||
struct bGPdata *gpd);
|
||||
|
||||
/**
|
||||
* Update the geometry of the evaluated bGPdata.
|
||||
* This function will:
|
||||
* 1) Copy the original data over to the evaluated object.
|
||||
* 2) Update the original pointers in the runtime structs.
|
||||
*/
|
||||
void BKE_gpencil_update_on_write(struct bGPdata *gpd_orig, struct bGPdata *gpd_eval);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -26,10 +26,6 @@ typedef void (*GreasePencilIDWalkFunc)(void *user_data,
|
||||
struct Object *ob,
|
||||
struct ID **idpoin,
|
||||
int cb_flag);
|
||||
typedef void (*GreasePencilTexWalkFunc)(void *user_data,
|
||||
struct Object *ob,
|
||||
struct GpencilModifierData *md,
|
||||
const char *propname);
|
||||
|
||||
/**
|
||||
* Free grease pencil modifier data
|
||||
|
||||
@@ -102,31 +102,6 @@ void BKE_gpencil_traverse_update_cache(GPencilUpdateCache *cache,
|
||||
GPencilUpdateCacheTraverseSettings *ts,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Tags an element (bGPdata, bGPDlayer, bGPDframe, or bGPDstroke) and all of its containing data to
|
||||
* be updated in the next update-on-write operation.
|
||||
*
|
||||
* The function assumes that when a parameter is NULL all of the following parameters are NULL too.
|
||||
* E.g. in order to tag a layer (gpl), the parameters would *have* to be (gpd, gpl, NULL, NULL).
|
||||
*/
|
||||
void BKE_gpencil_tag_full_update(struct bGPdata *gpd,
|
||||
struct bGPDlayer *gpl,
|
||||
struct bGPDframe *gpf,
|
||||
struct bGPDstroke *gps);
|
||||
|
||||
/**
|
||||
* Tags an element (bGPdata, bGPDlayer, bGPDframe, or bGPDstroke) to be updated in the next
|
||||
* update-on-write operation. This function will not update any of the containing data, only the
|
||||
* struct itself.
|
||||
*
|
||||
* The function assumes that when a parameter is NULL all of the following parameters are NULL too.
|
||||
* E.g. in order to tag a layer (gpl), the parameters would *have* to be (gpd, gpl, NULL, NULL).
|
||||
*/
|
||||
void BKE_gpencil_tag_light_update(struct bGPdata *gpd,
|
||||
struct bGPDlayer *gpl,
|
||||
struct bGPDframe *gpf,
|
||||
struct bGPDstroke *gps);
|
||||
|
||||
/**
|
||||
* Frees the GPencilUpdateCache on the gpd->runtime. This will not free the data that the cache
|
||||
* node might point to. It assumes that the cache does not own the data.
|
||||
|
||||
@@ -100,18 +100,6 @@ struct ObjectRuntime {
|
||||
*/
|
||||
Mesh *editmesh_eval_cage = nullptr;
|
||||
|
||||
/**
|
||||
* Original grease pencil bGPdata pointer, before object->data was changed to point
|
||||
* to gpd_eval.
|
||||
* Is assigned by dependency graph's copy-on-evaluation.
|
||||
*/
|
||||
bGPdata *gpd_orig = nullptr;
|
||||
/**
|
||||
* bGPdata structure created during object evaluation.
|
||||
* It has all modifiers applied.
|
||||
*/
|
||||
bGPdata *gpd_eval = nullptr;
|
||||
|
||||
/**
|
||||
* This is a mesh representation of corresponding object.
|
||||
* It created when Python calls `object.to_mesh()`.
|
||||
|
||||
@@ -44,415 +44,6 @@ extern "C" {
|
||||
/** \name Convert to curve object
|
||||
* \{ */
|
||||
|
||||
/* Helper: Check materials with same color. */
|
||||
static int gpencil_check_same_material_color(Object *ob_gp,
|
||||
const float color_stroke[4],
|
||||
const float color_fill[4],
|
||||
const bool do_stroke,
|
||||
const bool do_fill,
|
||||
Material **r_mat)
|
||||
{
|
||||
int index = -1;
|
||||
Material *ma = nullptr;
|
||||
*r_mat = nullptr;
|
||||
float color_cu[4];
|
||||
float hsv_stroke[4], hsv_fill[4];
|
||||
|
||||
copy_v4_v4(color_cu, color_stroke);
|
||||
zero_v3(hsv_stroke);
|
||||
rgb_to_hsv_v(color_cu, hsv_stroke);
|
||||
hsv_stroke[3] = color_stroke[3];
|
||||
|
||||
copy_v4_v4(color_cu, color_fill);
|
||||
zero_v3(hsv_fill);
|
||||
rgb_to_hsv_v(color_cu, hsv_fill);
|
||||
hsv_fill[3] = color_fill[3];
|
||||
|
||||
bool match_stroke = false;
|
||||
bool match_fill = false;
|
||||
|
||||
for (int i = 1; i <= ob_gp->totcol; i++) {
|
||||
ma = BKE_object_material_get(ob_gp, i);
|
||||
MaterialGPencilStyle *gp_style = ma->gp_style;
|
||||
const bool fill = (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID);
|
||||
const bool stroke = (gp_style->fill_style == GP_MATERIAL_STROKE_STYLE_SOLID);
|
||||
|
||||
if (do_fill && !fill) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (do_stroke && !stroke) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check color with small tolerance (better result in HSV). */
|
||||
float hsv2[4];
|
||||
if (do_fill) {
|
||||
zero_v3(hsv2);
|
||||
rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
|
||||
hsv2[3] = gp_style->fill_rgba[3];
|
||||
if (compare_v4v4(hsv_fill, hsv2, 0.01f)) {
|
||||
*r_mat = ma;
|
||||
index = i - 1;
|
||||
match_fill = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
match_fill = true;
|
||||
}
|
||||
|
||||
if (do_stroke) {
|
||||
zero_v3(hsv2);
|
||||
rgb_to_hsv_v(gp_style->stroke_rgba, hsv2);
|
||||
hsv2[3] = gp_style->stroke_rgba[3];
|
||||
if (compare_v4v4(hsv_stroke, hsv2, 0.01f)) {
|
||||
*r_mat = ma;
|
||||
index = i - 1;
|
||||
match_stroke = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
match_stroke = true;
|
||||
}
|
||||
|
||||
/* If match, don't look for more. */
|
||||
if (match_stroke || match_fill) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match_stroke || !match_fill) {
|
||||
*r_mat = nullptr;
|
||||
index = -1;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* Helper: Add gpencil material using curve material as base. */
|
||||
static Material *gpencil_add_from_curve_material(Main *bmain,
|
||||
Object *ob_gp,
|
||||
const float stroke_color[4],
|
||||
const float fill_color[4],
|
||||
const bool stroke,
|
||||
const bool fill,
|
||||
int *r_index)
|
||||
{
|
||||
Material *mat_gp = BKE_gpencil_object_material_new(bmain, ob_gp, "Material", r_index);
|
||||
MaterialGPencilStyle *gp_style = mat_gp->gp_style;
|
||||
|
||||
/* Stroke color. */
|
||||
if (stroke) {
|
||||
copy_v4_v4(mat_gp->gp_style->stroke_rgba, stroke_color);
|
||||
gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
|
||||
}
|
||||
|
||||
/* Fill color. */
|
||||
if (fill) {
|
||||
copy_v4_v4(mat_gp->gp_style->fill_rgba, fill_color);
|
||||
gp_style->flag |= GP_MATERIAL_FILL_SHOW;
|
||||
}
|
||||
|
||||
/* Check at least one is enabled. */
|
||||
if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) &&
|
||||
((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0))
|
||||
{
|
||||
gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
|
||||
}
|
||||
|
||||
return mat_gp;
|
||||
}
|
||||
|
||||
/* Helper: Create new stroke section. */
|
||||
static void gpencil_add_new_points(bGPDstroke *gps,
|
||||
const float *coord_array,
|
||||
const float pressure_start,
|
||||
const float pressure_end,
|
||||
const int init,
|
||||
const int totpoints,
|
||||
const float init_co[3],
|
||||
const bool last)
|
||||
{
|
||||
BLI_assert(totpoints > 0);
|
||||
|
||||
const float step = 1.0f / (float(totpoints) - 1.0f);
|
||||
float factor = 0.0f;
|
||||
for (int i = 0; i < totpoints; i++) {
|
||||
bGPDspoint *pt = &gps->points[i + init];
|
||||
copy_v3_v3(&pt->x, &coord_array[3 * i]);
|
||||
/* Be sure the last point is not on top of the first point of the curve or
|
||||
* the close of the stroke will produce glitches. */
|
||||
if ((last) && (i > 0) && (i == totpoints - 1)) {
|
||||
float dist = len_v3v3(init_co, &pt->x);
|
||||
if (dist < 0.1f) {
|
||||
/* Interpolate between previous point and current to back slightly. */
|
||||
bGPDspoint *pt_prev = &gps->points[i + init - 1];
|
||||
interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
|
||||
}
|
||||
}
|
||||
|
||||
pt->strength = 1.0f;
|
||||
pt->pressure = interpf(pressure_end, pressure_start, factor);
|
||||
factor += step;
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper: Get the first collection that includes the object. */
|
||||
static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
|
||||
{
|
||||
Collection *mycol = nullptr;
|
||||
FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
|
||||
LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
|
||||
if ((mycol == nullptr) && (cob->ob == ob)) {
|
||||
mycol = collection;
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_SCENE_COLLECTION_END;
|
||||
|
||||
return mycol;
|
||||
}
|
||||
static int gpencil_get_stroke_material_fromcurve(
|
||||
Main *bmain, Object *ob_gp, Object *ob_cu, bool *r_do_stroke, bool *r_do_fill)
|
||||
{
|
||||
Curve *cu = (Curve *)ob_cu->data;
|
||||
|
||||
Material *mat_gp = nullptr;
|
||||
Material *mat_curve_stroke = nullptr;
|
||||
Material *mat_curve_fill = nullptr;
|
||||
|
||||
float color_stroke[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
float color_fill[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
|
||||
/* If the curve has 2 materials, the first is considered as Fill and the second as Stroke.
|
||||
* If the has only one material, if the name contains "_stroke",
|
||||
* it's used as a stroke, otherwise as fill. */
|
||||
if (ob_cu->totcol >= 2) {
|
||||
*r_do_stroke = true;
|
||||
*r_do_fill = true;
|
||||
mat_curve_fill = BKE_object_material_get(ob_cu, 1);
|
||||
mat_curve_stroke = BKE_object_material_get(ob_cu, 2);
|
||||
}
|
||||
else if (ob_cu->totcol == 1) {
|
||||
mat_curve_stroke = BKE_object_material_get(ob_cu, 1);
|
||||
if ((mat_curve_stroke) && (strstr(mat_curve_stroke->id.name, "_stroke") != nullptr)) {
|
||||
*r_do_stroke = true;
|
||||
*r_do_fill = false;
|
||||
mat_curve_fill = nullptr;
|
||||
}
|
||||
else {
|
||||
*r_do_stroke = false;
|
||||
*r_do_fill = true;
|
||||
/* Invert materials. */
|
||||
mat_curve_fill = mat_curve_stroke;
|
||||
mat_curve_stroke = nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* No materials in the curve. */
|
||||
*r_do_fill = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mat_curve_stroke) {
|
||||
copy_v4_v4(color_stroke, &mat_curve_stroke->r);
|
||||
}
|
||||
if (mat_curve_fill) {
|
||||
copy_v4_v4(color_fill, &mat_curve_fill->r);
|
||||
}
|
||||
|
||||
int index = gpencil_check_same_material_color(
|
||||
ob_gp, color_stroke, color_fill, *r_do_stroke, *r_do_fill, &mat_gp);
|
||||
|
||||
if ((ob_gp->totcol < index) || (index < 0)) {
|
||||
mat_gp = gpencil_add_from_curve_material(
|
||||
bmain, ob_gp, color_stroke, color_fill, *r_do_stroke, *r_do_fill, &index);
|
||||
}
|
||||
|
||||
/* Set fill and stroke depending of curve type (3D or 2D). */
|
||||
if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
|
||||
mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
|
||||
mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
|
||||
}
|
||||
else {
|
||||
mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
|
||||
mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* Helper: Convert one spline to grease pencil stroke. */
|
||||
static void gpencil_convert_spline(Main *bmain,
|
||||
Object *ob_gp,
|
||||
Object *ob_cu,
|
||||
const float scale_thickness,
|
||||
const float sample,
|
||||
bGPDframe *gpf,
|
||||
Nurb *nu)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob_gp->data;
|
||||
bool cyclic = true;
|
||||
|
||||
/* Create Stroke. */
|
||||
bGPDstroke *gps = static_cast<bGPDstroke *>(MEM_callocN(sizeof(bGPDstroke), "bGPDstroke"));
|
||||
gps->thickness = 1.0f;
|
||||
gps->fill_opacity_fac = 1.0f;
|
||||
gps->hardness = 1.0f;
|
||||
gps->uv_scale = 1.0f;
|
||||
|
||||
ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f);
|
||||
ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
|
||||
gps->inittime = 0.0f;
|
||||
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
gps->flag |= GP_STROKE_3DSPACE;
|
||||
|
||||
gps->mat_nr = 0;
|
||||
/* Count total points
|
||||
* The total of points must consider that last point of each segment is equal to the first
|
||||
* point of next segment.
|
||||
*/
|
||||
int totpoints = 0;
|
||||
int segments = 0;
|
||||
int resolu = nu->resolu + 1;
|
||||
segments = nu->pntsu;
|
||||
if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
|
||||
segments--;
|
||||
cyclic = false;
|
||||
}
|
||||
totpoints = (resolu * segments) - (segments - 1);
|
||||
|
||||
/* Materials
|
||||
* Notice: The color of the material is the color of viewport and not the final shader color.
|
||||
*/
|
||||
bool do_stroke, do_fill;
|
||||
int index = gpencil_get_stroke_material_fromcurve(bmain, ob_gp, ob_cu, &do_stroke, &do_fill);
|
||||
CLAMP_MIN(index, 0);
|
||||
|
||||
/* Assign material index to stroke. */
|
||||
gps->mat_nr = index;
|
||||
|
||||
/* Add stroke to frame. */
|
||||
BLI_addtail(&gpf->strokes, gps);
|
||||
|
||||
float init_co[3];
|
||||
|
||||
switch (nu->type) {
|
||||
case CU_POLY: {
|
||||
/* Allocate memory for storage points. */
|
||||
gps->totpoints = nu->pntsu;
|
||||
gps->points = static_cast<bGPDspoint *>(
|
||||
MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"));
|
||||
/* Increase thickness for this type. */
|
||||
gps->thickness = 10.0f;
|
||||
|
||||
/* Get all curve points */
|
||||
for (int s = 0; s < gps->totpoints; s++) {
|
||||
BPoint *bp = &nu->bp[s];
|
||||
bGPDspoint *pt = &gps->points[s];
|
||||
copy_v3_v3(&pt->x, bp->vec);
|
||||
pt->pressure = bp->radius;
|
||||
pt->strength = 1.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CU_BEZIER: {
|
||||
/* Allocate memory for storage points. */
|
||||
gps->totpoints = totpoints;
|
||||
gps->points = static_cast<bGPDspoint *>(
|
||||
MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"));
|
||||
|
||||
int init = 0;
|
||||
resolu = nu->resolu + 1;
|
||||
segments = nu->pntsu;
|
||||
if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
|
||||
segments--;
|
||||
}
|
||||
/* Get all interpolated curve points of Bezier. */
|
||||
for (int s = 0; s < segments; s++) {
|
||||
int inext = (s + 1) % nu->pntsu;
|
||||
BezTriple *prevbezt = &nu->bezt[s];
|
||||
BezTriple *bezt = &nu->bezt[inext];
|
||||
bool last = bool(s == segments - 1);
|
||||
|
||||
float *coord_array = static_cast<float *>(
|
||||
MEM_callocN(sizeof(float[3]) * resolu, __func__));
|
||||
for (int j = 0; j < 3; j++) {
|
||||
BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
|
||||
prevbezt->vec[2][j],
|
||||
bezt->vec[0][j],
|
||||
bezt->vec[1][j],
|
||||
coord_array + j,
|
||||
resolu - 1,
|
||||
sizeof(float[3]));
|
||||
}
|
||||
/* Save first point coordinates. */
|
||||
if (s == 0) {
|
||||
copy_v3_v3(init_co, &coord_array[0]);
|
||||
}
|
||||
/* Add points to the stroke */
|
||||
float radius_start = prevbezt->radius * scale_thickness;
|
||||
float radius_end = bezt->radius * scale_thickness;
|
||||
|
||||
gpencil_add_new_points(
|
||||
gps, coord_array, radius_start, radius_end, init, resolu, init_co, last);
|
||||
|
||||
/* Free memory. */
|
||||
MEM_freeN(coord_array);
|
||||
|
||||
/* As the last point of segment is the first point of next segment, back one array
|
||||
* element to avoid duplicated points on the same location.
|
||||
*/
|
||||
init += resolu - 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CU_NURBS: {
|
||||
if (nu->pntsv == 1) {
|
||||
|
||||
int nurb_points;
|
||||
if (nu->flagu & CU_NURB_CYCLIC) {
|
||||
resolu++;
|
||||
nurb_points = nu->pntsu * resolu;
|
||||
}
|
||||
else {
|
||||
nurb_points = (nu->pntsu - 1) * resolu;
|
||||
}
|
||||
/* Get all curve points. */
|
||||
float *coord_array = static_cast<float *>(
|
||||
MEM_callocN(sizeof(float[3]) * nurb_points, __func__));
|
||||
BKE_nurb_makeCurve(nu, coord_array, nullptr, nullptr, nullptr, resolu, sizeof(float[3]));
|
||||
|
||||
/* Allocate memory for storage points. */
|
||||
gps->totpoints = nurb_points;
|
||||
gps->points = static_cast<bGPDspoint *>(
|
||||
MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"));
|
||||
|
||||
/* Add points. */
|
||||
gpencil_add_new_points(gps, coord_array, 1.0f, 1.0f, 0, gps->totpoints, init_co, false);
|
||||
|
||||
MEM_freeN(coord_array);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Cyclic curve, close stroke. */
|
||||
if (cyclic) {
|
||||
BKE_gpencil_stroke_close(gps);
|
||||
}
|
||||
|
||||
if (sample > 0.0f) {
|
||||
BKE_gpencil_stroke_sample(gpd, gps, sample, false, 0);
|
||||
}
|
||||
|
||||
/* Recalc fill geometry. */
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
static void gpencil_editstroke_deselect_all(bGPDcurve *gpc)
|
||||
{
|
||||
for (int i = 0; i < gpc->tot_curve_points; i++) {
|
||||
@@ -464,80 +55,6 @@ static void gpencil_editstroke_deselect_all(bGPDcurve *gpc)
|
||||
gpc->flag &= ~GP_CURVE_SELECT;
|
||||
}
|
||||
|
||||
void BKE_gpencil_convert_curve(Main *bmain,
|
||||
Scene *scene,
|
||||
Object *ob_gp,
|
||||
Object *ob_cu,
|
||||
const bool use_collections,
|
||||
const float scale_thickness,
|
||||
const float sample)
|
||||
{
|
||||
if (ELEM(nullptr, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL_LEGACY) ||
|
||||
(ob_gp->data == nullptr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Curve *cu = (Curve *)ob_cu->data;
|
||||
bGPdata *gpd = (bGPdata *)ob_gp->data;
|
||||
bGPDlayer *gpl = nullptr;
|
||||
|
||||
/* If the curve is empty, cancel. */
|
||||
if (cu->nurb.first == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if there is an active layer. */
|
||||
if (use_collections) {
|
||||
Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
|
||||
if (collection != nullptr) {
|
||||
gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2);
|
||||
if (gpl == nullptr) {
|
||||
gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gpl == nullptr) {
|
||||
gpl = BKE_gpencil_layer_active_get(gpd);
|
||||
if (gpl == nullptr) {
|
||||
gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if there is an active frame and add if needed. */
|
||||
bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_COPY);
|
||||
|
||||
/* Read all splines of the curve and create a stroke for each. */
|
||||
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
|
||||
gpencil_convert_spline(bmain, ob_gp, ob_cu, scale_thickness, sample, gpf, nu);
|
||||
}
|
||||
|
||||
/* Merge any similar material. */
|
||||
int removed = 0;
|
||||
BKE_gpencil_merge_materials(ob_gp, 0.001f, 0.001f, 0.001f, &removed);
|
||||
|
||||
/* Remove any unused slot. */
|
||||
int actcol = ob_gp->actcol;
|
||||
|
||||
for (int slot = 1; slot <= ob_gp->totcol; slot++) {
|
||||
while (slot <= ob_gp->totcol && !BKE_object_material_slot_used(ob_gp, slot)) {
|
||||
ob_gp->actcol = slot;
|
||||
BKE_object_material_slot_remove(bmain, ob_gp);
|
||||
|
||||
if (actcol >= slot) {
|
||||
actcol--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ob_gp->actcol = actcol;
|
||||
|
||||
/* Tag for recalculation */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_SYNC_TO_EVAL);
|
||||
DEG_id_tag_update(&ob_gp->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -729,28 +246,6 @@ bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
|
||||
return editcurve;
|
||||
}
|
||||
|
||||
void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
|
||||
{
|
||||
if (gps == nullptr || gps->totpoints < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gps->editcurve != nullptr) {
|
||||
BKE_gpencil_free_stroke_editcurve(gps);
|
||||
}
|
||||
|
||||
float defaultpixsize = 1000.0f / gpd->pixfactor;
|
||||
float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f;
|
||||
|
||||
bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_generate(
|
||||
gps, gpd->curve_edit_threshold, gpd->curve_edit_corner_angle, stroke_radius);
|
||||
if (editcurve == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
gps->editcurve = editcurve;
|
||||
}
|
||||
|
||||
void BKE_gpencil_editcurve_stroke_sync_selection(bGPdata * /*gpd*/,
|
||||
bGPDstroke *gps,
|
||||
bGPDcurve *gpc)
|
||||
@@ -777,346 +272,6 @@ void BKE_gpencil_editcurve_stroke_sync_selection(bGPdata * /*gpd*/,
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_gpencil_stroke_editcurve_sync_selection(bGPdata *gpd, bGPDstroke *gps, bGPDcurve *gpc)
|
||||
{
|
||||
if (gpc->flag & GP_CURVE_SELECT) {
|
||||
gps->flag |= GP_STROKE_SELECT;
|
||||
BKE_gpencil_stroke_select_index_set(gpd, gps);
|
||||
|
||||
for (int i = 0; i < gpc->tot_curve_points - 1; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
bGPDspoint *pt = &gps->points[gpc_pt->point_index];
|
||||
bGPDcurve_point *gpc_pt_next = &gpc->curve_points[i + 1];
|
||||
|
||||
if (gpc_pt->flag & GP_CURVE_POINT_SELECT) {
|
||||
pt->flag |= GP_SPOINT_SELECT;
|
||||
if (gpc_pt_next->flag & GP_CURVE_POINT_SELECT) {
|
||||
/* select all the points after */
|
||||
for (int j = gpc_pt->point_index + 1; j < gpc_pt_next->point_index; j++) {
|
||||
bGPDspoint *pt_next = &gps->points[j];
|
||||
pt_next->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
/* deselect all points after */
|
||||
for (int j = gpc_pt->point_index + 1; j < gpc_pt_next->point_index; j++) {
|
||||
bGPDspoint *pt_next = &gps->points[j];
|
||||
pt_next->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bGPDcurve_point *gpc_first = &gpc->curve_points[0];
|
||||
bGPDcurve_point *gpc_last = &gpc->curve_points[gpc->tot_curve_points - 1];
|
||||
bGPDspoint *last_pt = &gps->points[gpc_last->point_index];
|
||||
if (gpc_last->flag & GP_CURVE_POINT_SELECT) {
|
||||
last_pt->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
else {
|
||||
last_pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
|
||||
if (gps->flag & GP_STROKE_CYCLIC) {
|
||||
if (gpc_first->flag & GP_CURVE_POINT_SELECT && gpc_last->flag & GP_CURVE_POINT_SELECT) {
|
||||
for (int i = gpc_last->point_index + 1; i < gps->totpoints; i++) {
|
||||
bGPDspoint *pt_next = &gps->points[i];
|
||||
pt_next->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = gpc_last->point_index + 1; i < gps->totpoints; i++) {
|
||||
bGPDspoint *pt_next = &gps->points[i];
|
||||
pt_next->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
BKE_gpencil_stroke_select_index_reset(gps);
|
||||
for (int i = 0; i < gps->totpoints; i++) {
|
||||
bGPDspoint *pt = &gps->points[i];
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gpencil_interpolate_fl_from_to(
|
||||
float from, float to, float *point_offset, int it, int stride)
|
||||
{
|
||||
/* smooth interpolation */
|
||||
float *r = point_offset;
|
||||
for (int i = 0; i <= it; i++) {
|
||||
float fac = float(i) / float(it);
|
||||
fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; /* Smooth. */
|
||||
*r = interpf(to, from, fac);
|
||||
r = static_cast<float *>(POINTER_OFFSET(r, stride));
|
||||
}
|
||||
}
|
||||
|
||||
static void gpencil_interpolate_v4_from_to(
|
||||
float from[4], float to[4], float *point_offset, int it, int stride)
|
||||
{
|
||||
/* smooth interpolation */
|
||||
float *r = point_offset;
|
||||
for (int i = 0; i <= it; i++) {
|
||||
float fac = float(i) / float(it);
|
||||
fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; /* Smooth. */
|
||||
interp_v4_v4v4(r, from, to, fac);
|
||||
r = static_cast<float *>(POINTER_OFFSET(r, stride));
|
||||
}
|
||||
}
|
||||
|
||||
static float gpencil_approximate_curve_segment_arclength(bGPDcurve_point *cpt_start,
|
||||
bGPDcurve_point *cpt_end)
|
||||
{
|
||||
BezTriple *bezt_start = &cpt_start->bezt;
|
||||
BezTriple *bezt_end = &cpt_end->bezt;
|
||||
|
||||
float chord_len = len_v3v3(bezt_start->vec[1], bezt_end->vec[1]);
|
||||
float net_len = len_v3v3(bezt_start->vec[1], bezt_start->vec[2]);
|
||||
net_len += len_v3v3(bezt_start->vec[2], bezt_end->vec[0]);
|
||||
net_len += len_v3v3(bezt_end->vec[0], bezt_end->vec[1]);
|
||||
|
||||
return (chord_len + net_len) / 2.0f;
|
||||
}
|
||||
|
||||
static void gpencil_calculate_stroke_points_curve_segment(
|
||||
bGPDcurve_point *cpt, bGPDcurve_point *cpt_next, float *points_offset, int resolu, int stride)
|
||||
{
|
||||
/* sample points on all 3 axis between two curve points */
|
||||
for (uint axis = 0; axis < 3; axis++) {
|
||||
BKE_curve_forward_diff_bezier(
|
||||
cpt->bezt.vec[1][axis],
|
||||
cpt->bezt.vec[2][axis],
|
||||
cpt_next->bezt.vec[0][axis],
|
||||
cpt_next->bezt.vec[1][axis],
|
||||
static_cast<float *>(POINTER_OFFSET(points_offset, sizeof(float) * axis)),
|
||||
int(resolu),
|
||||
stride);
|
||||
}
|
||||
|
||||
/* interpolate other attributes */
|
||||
gpencil_interpolate_fl_from_to(
|
||||
cpt->pressure,
|
||||
cpt_next->pressure,
|
||||
static_cast<float *>(POINTER_OFFSET(points_offset, sizeof(float) * 3)),
|
||||
resolu,
|
||||
stride);
|
||||
gpencil_interpolate_fl_from_to(
|
||||
cpt->strength,
|
||||
cpt_next->strength,
|
||||
static_cast<float *>(POINTER_OFFSET(points_offset, sizeof(float) * 4)),
|
||||
resolu,
|
||||
stride);
|
||||
gpencil_interpolate_v4_from_to(
|
||||
cpt->vert_color,
|
||||
cpt_next->vert_color,
|
||||
static_cast<float *>(POINTER_OFFSET(points_offset, sizeof(float) * 5)),
|
||||
resolu,
|
||||
stride);
|
||||
}
|
||||
|
||||
static float *gpencil_stroke_points_from_editcurve_adaptive_resolu(
|
||||
bGPDcurve_point *curve_point_array,
|
||||
int curve_point_array_len,
|
||||
int resolution,
|
||||
bool is_cyclic,
|
||||
int *r_points_len)
|
||||
{
|
||||
/* One stride contains: `x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor`. */
|
||||
const uint stride = sizeof(float[9]);
|
||||
const uint cpt_last = curve_point_array_len - 1;
|
||||
const uint num_segments = (is_cyclic) ? curve_point_array_len : curve_point_array_len - 1;
|
||||
int *segment_point_lengths = static_cast<int *>(
|
||||
MEM_callocN(sizeof(int) * num_segments, __func__));
|
||||
|
||||
uint points_len = 1;
|
||||
for (int i = 0; i < cpt_last; i++) {
|
||||
bGPDcurve_point *cpt = &curve_point_array[i];
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
|
||||
float arclen = gpencil_approximate_curve_segment_arclength(cpt, cpt_next);
|
||||
int segment_resolu = int(floorf(arclen * resolution));
|
||||
CLAMP_MIN(segment_resolu, 1);
|
||||
|
||||
segment_point_lengths[i] = segment_resolu;
|
||||
points_len += segment_resolu;
|
||||
}
|
||||
|
||||
if (is_cyclic) {
|
||||
bGPDcurve_point *cpt = &curve_point_array[cpt_last];
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[0];
|
||||
float arclen = gpencil_approximate_curve_segment_arclength(cpt, cpt_next);
|
||||
int segment_resolu = int(floorf(arclen * resolution));
|
||||
CLAMP_MIN(segment_resolu, 1);
|
||||
|
||||
segment_point_lengths[cpt_last] = segment_resolu;
|
||||
points_len += segment_resolu;
|
||||
}
|
||||
|
||||
float(*r_points)[9] = static_cast<float(*)[9]>(
|
||||
MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__));
|
||||
float *points_offset = &r_points[0][0];
|
||||
int point_index = 0;
|
||||
for (int i = 0; i < cpt_last; i++) {
|
||||
bGPDcurve_point *cpt_curr = &curve_point_array[i];
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
|
||||
int segment_resolu = segment_point_lengths[i];
|
||||
gpencil_calculate_stroke_points_curve_segment(
|
||||
cpt_curr, cpt_next, points_offset, segment_resolu, stride);
|
||||
/* update the index */
|
||||
cpt_curr->point_index = point_index;
|
||||
point_index += segment_resolu;
|
||||
points_offset = static_cast<float *>(POINTER_OFFSET(points_offset, segment_resolu * stride));
|
||||
}
|
||||
|
||||
bGPDcurve_point *cpt_curr = &curve_point_array[cpt_last];
|
||||
cpt_curr->point_index = point_index;
|
||||
if (is_cyclic) {
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[0];
|
||||
int segment_resolu = segment_point_lengths[cpt_last];
|
||||
gpencil_calculate_stroke_points_curve_segment(
|
||||
cpt_curr, cpt_next, points_offset, segment_resolu, stride);
|
||||
}
|
||||
|
||||
MEM_freeN(segment_point_lengths);
|
||||
|
||||
*r_points_len = points_len;
|
||||
return (float *)r_points;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: calculate the points on a curve with a fixed resolution.
|
||||
*/
|
||||
static float *gpencil_stroke_points_from_editcurve_fixed_resolu(bGPDcurve_point *curve_point_array,
|
||||
int curve_point_array_len,
|
||||
int resolution,
|
||||
bool is_cyclic,
|
||||
int *r_points_len)
|
||||
{
|
||||
/* One stride contains: `x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor`. */
|
||||
const uint stride = sizeof(float[9]);
|
||||
const uint array_last = curve_point_array_len - 1;
|
||||
const uint resolu_stride = resolution * stride;
|
||||
const uint points_len = BKE_curve_calc_coords_axis_len(
|
||||
curve_point_array_len, resolution, is_cyclic, false);
|
||||
|
||||
float(*r_points)[9] = static_cast<float(*)[9]>(
|
||||
MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__));
|
||||
float *points_offset = &r_points[0][0];
|
||||
for (uint i = 0; i < array_last; i++) {
|
||||
bGPDcurve_point *cpt_curr = &curve_point_array[i];
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
|
||||
|
||||
gpencil_calculate_stroke_points_curve_segment(
|
||||
cpt_curr, cpt_next, points_offset, resolution, stride);
|
||||
/* update the index */
|
||||
cpt_curr->point_index = i * resolution;
|
||||
points_offset = static_cast<float *>(POINTER_OFFSET(points_offset, resolu_stride));
|
||||
}
|
||||
|
||||
bGPDcurve_point *cpt_curr = &curve_point_array[array_last];
|
||||
cpt_curr->point_index = array_last * resolution;
|
||||
if (is_cyclic) {
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[0];
|
||||
gpencil_calculate_stroke_points_curve_segment(
|
||||
cpt_curr, cpt_next, points_offset, resolution, stride);
|
||||
}
|
||||
|
||||
*r_points_len = points_len;
|
||||
return (float *)r_points;
|
||||
}
|
||||
|
||||
void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
|
||||
const uint resolution,
|
||||
const bool adaptive)
|
||||
{
|
||||
if (gps == nullptr || gps->editcurve == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
bGPDcurve *editcurve = gps->editcurve;
|
||||
bGPDcurve_point *curve_point_array = editcurve->curve_points;
|
||||
int curve_point_array_len = editcurve->tot_curve_points;
|
||||
if (curve_point_array_len == 0) {
|
||||
return;
|
||||
}
|
||||
/* Handle case for single curve point. */
|
||||
if (curve_point_array_len == 1) {
|
||||
bGPDcurve_point *cpt = &curve_point_array[0];
|
||||
/* resize stroke point array */
|
||||
gps->totpoints = 1;
|
||||
gps->points = static_cast<bGPDspoint *>(
|
||||
MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints));
|
||||
if (gps->dvert != nullptr) {
|
||||
gps->dvert = static_cast<MDeformVert *>(
|
||||
MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints));
|
||||
}
|
||||
|
||||
bGPDspoint *pt = &gps->points[0];
|
||||
copy_v3_v3(&pt->x, cpt->bezt.vec[1]);
|
||||
|
||||
pt->pressure = cpt->pressure;
|
||||
pt->strength = cpt->strength;
|
||||
|
||||
copy_v4_v4(pt->vert_color, cpt->vert_color);
|
||||
|
||||
/* deselect */
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
BKE_gpencil_stroke_select_index_reset(gps);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
|
||||
|
||||
int points_len = 0;
|
||||
float(*points)[9] = nullptr;
|
||||
if (adaptive) {
|
||||
points = (float(*)[9])gpencil_stroke_points_from_editcurve_adaptive_resolu(
|
||||
curve_point_array, curve_point_array_len, resolution, is_cyclic, &points_len);
|
||||
}
|
||||
else {
|
||||
points = (float(*)[9])gpencil_stroke_points_from_editcurve_fixed_resolu(
|
||||
curve_point_array, curve_point_array_len, resolution, is_cyclic, &points_len);
|
||||
}
|
||||
|
||||
if (points == nullptr || points_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* resize stroke point array */
|
||||
gps->totpoints = points_len;
|
||||
gps->points = static_cast<bGPDspoint *>(
|
||||
MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints));
|
||||
if (gps->dvert != nullptr) {
|
||||
gps->dvert = static_cast<MDeformVert *>(
|
||||
MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints));
|
||||
}
|
||||
|
||||
/* write new data to stroke point array */
|
||||
for (int i = 0; i < points_len; i++) {
|
||||
bGPDspoint *pt = &gps->points[i];
|
||||
copy_v3_v3(&pt->x, &points[i][0]);
|
||||
|
||||
pt->pressure = points[i][3];
|
||||
pt->strength = points[i][4];
|
||||
|
||||
copy_v4_v4(pt->vert_color, &points[i][5]);
|
||||
|
||||
/* deselect points */
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
BKE_gpencil_stroke_select_index_reset(gps);
|
||||
|
||||
/* free temp data */
|
||||
MEM_freeN(points);
|
||||
}
|
||||
|
||||
void BKE_gpencil_editcurve_recalculate_handles(bGPDstroke *gps)
|
||||
{
|
||||
if (gps == nullptr || gps->editcurve == nullptr) {
|
||||
@@ -1325,68 +480,4 @@ void BKE_gpencil_editcurve_subdivide(bGPDstroke *gps, const int cuts)
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_gpencil_strokes_selected_update_editcurve(bGPdata *gpd)
|
||||
{
|
||||
const bool is_multiedit = bool(GPENCIL_MULTIEDIT_SESSIONS_ON(gpd));
|
||||
/* For all selected strokes, update edit curve. */
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
if (!BKE_gpencil_layer_is_editable(gpl)) {
|
||||
continue;
|
||||
}
|
||||
bGPDframe *init_gpf = static_cast<bGPDframe *>((is_multiedit) ? gpl->frames.first :
|
||||
gpl->actframe);
|
||||
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
|
||||
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && is_multiedit)) {
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
/* skip deselected stroke */
|
||||
if (!(gps->flag & GP_STROKE_SELECT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Generate the curve if there is none or the stroke was changed */
|
||||
if (gps->editcurve == nullptr) {
|
||||
BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
|
||||
/* Continue if curve could not be generated. */
|
||||
if (gps->editcurve == nullptr) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (gps->editcurve->flag & GP_CURVE_NEEDS_STROKE_UPDATE) {
|
||||
BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
|
||||
}
|
||||
/* Update the selection from the stroke to the curve. */
|
||||
BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve);
|
||||
|
||||
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_gpencil_strokes_selected_sync_selection_editcurve(bGPdata *gpd)
|
||||
{
|
||||
const bool is_multiedit = bool(GPENCIL_MULTIEDIT_SESSIONS_ON(gpd));
|
||||
/* Sync selection for all strokes with editcurve. */
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
if (!BKE_gpencil_layer_is_editable(gpl)) {
|
||||
continue;
|
||||
}
|
||||
bGPDframe *init_gpf = static_cast<bGPDframe *>((is_multiedit) ? gpl->frames.first :
|
||||
gpl->actframe);
|
||||
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
|
||||
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && is_multiedit)) {
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
bGPDcurve *gpc = gps->editcurve;
|
||||
if (gpc != nullptr) {
|
||||
/* Update the selection of every stroke that has an editcurve */
|
||||
BKE_gpencil_stroke_editcurve_sync_selection(gpd, gps, gpc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -419,29 +419,6 @@ static void gpencil_modifier_foreach_ID_link(GpencilModifierData *md,
|
||||
/* *************************************************** */
|
||||
/* Modifier Methods - Evaluation Loops, etc. */
|
||||
|
||||
void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd)
|
||||
{
|
||||
DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
|
||||
int ctime = int(DEG_get_ctime(depsgraph));
|
||||
|
||||
/* update active frame */
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
gpl->actframe = BKE_gpencil_layer_frame_get(gpl, ctime, GP_GETFRAME_USE_PREV);
|
||||
}
|
||||
|
||||
if (DEG_is_active(depsgraph)) {
|
||||
bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
|
||||
|
||||
/* sync "actframe" changes back to main-db too,
|
||||
* so that editing tools work with copy-on-evaluation
|
||||
* when the current frame changes
|
||||
*/
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_orig->layers) {
|
||||
gpl->actframe = BKE_gpencil_layer_frame_get(gpl, ctime, GP_GETFRAME_USE_PREV);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void modifier_free_data_id_us_cb(void * /*user_data*/,
|
||||
Object * /*ob*/,
|
||||
ID **idpoin,
|
||||
|
||||
@@ -29,24 +29,6 @@ static GPencilUpdateCache *update_cache_alloc(int index, int flag, void *data)
|
||||
return new_cache;
|
||||
}
|
||||
|
||||
static short cache_node_compare(void *node, void *data)
|
||||
{
|
||||
int index_a = ((GPencilUpdateCacheNode *)node)->cache->index;
|
||||
int index_b = ((GPencilUpdateCache *)data)->index;
|
||||
if (index_a == index_b) {
|
||||
return 0;
|
||||
}
|
||||
return index_a < index_b ? 1 : -1;
|
||||
}
|
||||
|
||||
static DLRBT_Node *cache_node_alloc(void *data)
|
||||
{
|
||||
GPencilUpdateCacheNode *new_node = static_cast<GPencilUpdateCacheNode *>(
|
||||
MEM_callocN(sizeof(GPencilUpdateCacheNode), __func__));
|
||||
new_node->cache = ((GPencilUpdateCache *)data);
|
||||
return (DLRBT_Node *)new_node;
|
||||
}
|
||||
|
||||
static void cache_node_free(void *node);
|
||||
|
||||
static void update_cache_free(GPencilUpdateCache *cache)
|
||||
@@ -65,136 +47,6 @@ static void cache_node_free(void *node)
|
||||
MEM_freeN(node);
|
||||
}
|
||||
|
||||
static void cache_node_update(void *node, void *data)
|
||||
{
|
||||
GPencilUpdateCache *update_cache = ((GPencilUpdateCacheNode *)node)->cache;
|
||||
GPencilUpdateCache *new_update_cache = (GPencilUpdateCache *)data;
|
||||
|
||||
/* If the new cache is already "covered" by the current cache, just free it and return. */
|
||||
if (new_update_cache->flag <= update_cache->flag) {
|
||||
update_cache_free(new_update_cache);
|
||||
return;
|
||||
}
|
||||
|
||||
update_cache->data = new_update_cache->data;
|
||||
update_cache->flag = new_update_cache->flag;
|
||||
|
||||
/* In case the new cache does a full update, remove its children since they will be all
|
||||
* updated by this cache. */
|
||||
if (new_update_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
|
||||
BLI_dlrbTree_free(update_cache->children, cache_node_free);
|
||||
}
|
||||
|
||||
update_cache_free(new_update_cache);
|
||||
}
|
||||
|
||||
static void update_cache_node_create_ex(GPencilUpdateCache *root_cache,
|
||||
void *data,
|
||||
int gpl_index,
|
||||
int gpf_index,
|
||||
int gps_index,
|
||||
bool full_copy)
|
||||
{
|
||||
if (root_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
|
||||
/* Entire data-block has to be recalculated, e.g. nothing else needs to be added to the cache.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
const int node_flag = full_copy ? GP_UPDATE_NODE_FULL_COPY : GP_UPDATE_NODE_LIGHT_COPY;
|
||||
|
||||
if (gpl_index == -1) {
|
||||
root_cache->data = (bGPdata *)data;
|
||||
root_cache->flag = node_flag;
|
||||
if (full_copy) {
|
||||
/* Entire data-block has to be recalculated, remove all caches of "lower" elements. */
|
||||
BLI_dlrbTree_free(root_cache->children, cache_node_free);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_layer_update_node = (gpf_index == -1);
|
||||
/* If the data pointer in #GPencilUpdateCache is nullptr, this element is not actually cached
|
||||
* and does not need to be updated, but we do need the index to find elements that are in
|
||||
* levels below. E.g. if a stroke needs to be updated, the frame it is in would not hold a
|
||||
* pointer to it's data. */
|
||||
GPencilUpdateCache *gpl_cache = update_cache_alloc(
|
||||
gpl_index,
|
||||
is_layer_update_node ? node_flag : GP_UPDATE_NODE_NO_COPY,
|
||||
is_layer_update_node ? (bGPDlayer *)data : nullptr);
|
||||
GPencilUpdateCacheNode *gpl_node = (GPencilUpdateCacheNode *)BLI_dlrbTree_add(
|
||||
root_cache->children, cache_node_compare, cache_node_alloc, cache_node_update, gpl_cache);
|
||||
|
||||
BLI_dlrbTree_linkedlist_sync(root_cache->children);
|
||||
if (gpl_node->cache->flag == GP_UPDATE_NODE_FULL_COPY || is_layer_update_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_frame_update_node = (gps_index == -1);
|
||||
GPencilUpdateCache *gpf_cache = update_cache_alloc(
|
||||
gpf_index,
|
||||
is_frame_update_node ? node_flag : GP_UPDATE_NODE_NO_COPY,
|
||||
is_frame_update_node ? (bGPDframe *)data : nullptr);
|
||||
GPencilUpdateCacheNode *gpf_node = (GPencilUpdateCacheNode *)BLI_dlrbTree_add(
|
||||
gpl_node->cache->children,
|
||||
cache_node_compare,
|
||||
cache_node_alloc,
|
||||
cache_node_update,
|
||||
gpf_cache);
|
||||
|
||||
BLI_dlrbTree_linkedlist_sync(gpl_node->cache->children);
|
||||
if (gpf_node->cache->flag == GP_UPDATE_NODE_FULL_COPY || is_frame_update_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPencilUpdateCache *gps_cache = update_cache_alloc(gps_index, node_flag, (bGPDstroke *)data);
|
||||
BLI_dlrbTree_add(gpf_node->cache->children,
|
||||
cache_node_compare,
|
||||
cache_node_alloc,
|
||||
cache_node_update,
|
||||
gps_cache);
|
||||
|
||||
BLI_dlrbTree_linkedlist_sync(gpf_node->cache->children);
|
||||
}
|
||||
|
||||
static void update_cache_node_create(
|
||||
bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, bool full_copy)
|
||||
{
|
||||
if (gpd == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPencilUpdateCache *root_cache = gpd->runtime.update_cache;
|
||||
if (root_cache == nullptr) {
|
||||
gpd->runtime.update_cache = update_cache_alloc(0, GP_UPDATE_NODE_NO_COPY, nullptr);
|
||||
root_cache = gpd->runtime.update_cache;
|
||||
}
|
||||
|
||||
if (root_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
|
||||
/* Entire data-block has to be recalculated, e.g. nothing else needs to be added to the cache.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
const int gpl_index = (gpl != nullptr) ? BLI_findindex(&gpd->layers, gpl) : -1;
|
||||
const int gpf_index = (gpl != nullptr && gpf != nullptr) ? BLI_findindex(&gpl->frames, gpf) : -1;
|
||||
const int gps_index = (gpf != nullptr && gps != nullptr) ? BLI_findindex(&gpf->strokes, gps) :
|
||||
-1;
|
||||
|
||||
void *data = gps;
|
||||
if (!data) {
|
||||
data = gpf;
|
||||
}
|
||||
if (!data) {
|
||||
data = gpl;
|
||||
}
|
||||
if (!data) {
|
||||
data = gpd;
|
||||
}
|
||||
|
||||
update_cache_node_create_ex(root_cache, data, gpl_index, gpf_index, gps_index, full_copy);
|
||||
}
|
||||
|
||||
static void gpencil_traverse_update_cache_ex(GPencilUpdateCache *parent_cache,
|
||||
GPencilUpdateCacheTraverseSettings *ts,
|
||||
int depth,
|
||||
@@ -237,16 +89,6 @@ void BKE_gpencil_traverse_update_cache(GPencilUpdateCache *cache,
|
||||
gpencil_traverse_update_cache_ex(cache, ts, 0, user_data);
|
||||
}
|
||||
|
||||
void BKE_gpencil_tag_full_update(bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
|
||||
{
|
||||
update_cache_node_create(gpd, gpl, gpf, gps, true);
|
||||
}
|
||||
|
||||
void BKE_gpencil_tag_light_update(bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
|
||||
{
|
||||
update_cache_node_create(gpd, gpl, gpf, gps, false);
|
||||
}
|
||||
|
||||
void BKE_gpencil_free_update_cache(bGPdata *gpd)
|
||||
{
|
||||
GPencilUpdateCache *gpd_cache = gpd->runtime.update_cache;
|
||||
|
||||
@@ -511,8 +511,6 @@ bool BKE_object_material_slot_used(Object *object, short actcol)
|
||||
case ID_MB:
|
||||
/* Meta-elements don't support materials at the moment. */
|
||||
return false;
|
||||
case ID_GD_LEGACY:
|
||||
return BKE_gpencil_material_index_used((bGPdata *)ob_data, actcol - 1);
|
||||
case ID_GP:
|
||||
return BKE_grease_pencil_material_index_used(reinterpret_cast<GreasePencil *>(ob_data),
|
||||
actcol - 1);
|
||||
@@ -1172,9 +1170,6 @@ void BKE_object_material_remap(Object *ob, const uint *remap)
|
||||
else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
|
||||
BKE_curve_material_remap(static_cast<Curve *>(ob->data), remap, ob->totcol);
|
||||
}
|
||||
else if (ob->type == OB_GPENCIL_LEGACY) {
|
||||
BKE_gpencil_material_remap(static_cast<bGPdata *>(ob->data), remap, ob->totcol);
|
||||
}
|
||||
else if (ob->type == OB_GREASE_PENCIL) {
|
||||
BKE_grease_pencil_material_remap(static_cast<GreasePencil *>(ob->data), remap, ob->totcol);
|
||||
}
|
||||
@@ -1427,10 +1422,6 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
|
||||
BKE_displist_free(&ob->runtime->curve_cache->disp);
|
||||
}
|
||||
}
|
||||
/* check indices from gpencil legacy. */
|
||||
else if (ob->type == OB_GPENCIL_LEGACY) {
|
||||
BKE_gpencil_material_index_reassign((bGPdata *)ob->data, ob->totcol, actcol - 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1667,12 +1667,6 @@ void BKE_object_free_derived_caches(Object *ob)
|
||||
|
||||
BKE_crazyspace_api_eval_clear(ob);
|
||||
|
||||
/* Clear grease pencil data. */
|
||||
if (ob->runtime->gpd_eval != nullptr) {
|
||||
BKE_gpencil_eval_delete(ob->runtime->gpd_eval);
|
||||
ob->runtime->gpd_eval = nullptr;
|
||||
}
|
||||
|
||||
if (ob->runtime->geometry_set_eval != nullptr) {
|
||||
delete ob->runtime->geometry_set_eval;
|
||||
ob->runtime->geometry_set_eval = nullptr;
|
||||
@@ -3865,30 +3859,6 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
|
||||
return ok;
|
||||
}
|
||||
|
||||
struct GPencilStrokePointIterData {
|
||||
const float (*obmat)[4];
|
||||
|
||||
void (*point_func_cb)(const float co[3], void *user_data);
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static void foreach_display_point_gpencil_stroke_fn(bGPDlayer * /*layer*/,
|
||||
bGPDframe * /*frame*/,
|
||||
bGPDstroke *stroke,
|
||||
void *thunk)
|
||||
{
|
||||
GPencilStrokePointIterData *iter_data = (GPencilStrokePointIterData *)thunk;
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
for (i = 0, pt = stroke->points; i < stroke->totpoints; i++, pt++) {
|
||||
float3 co;
|
||||
mul_v3_m4v3(co, iter_data->obmat, &pt->x);
|
||||
iter_data->point_func_cb(co, iter_data->user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_object_foreach_display_point(Object *ob,
|
||||
const float obmat[4][4],
|
||||
void (*func_cb)(const float[3], void *),
|
||||
@@ -3905,15 +3875,6 @@ void BKE_object_foreach_display_point(Object *ob,
|
||||
func_cb(co, user_data);
|
||||
}
|
||||
}
|
||||
else if (ob->type == OB_GPENCIL_LEGACY) {
|
||||
GPencilStrokePointIterData iter_data{};
|
||||
iter_data.obmat = obmat;
|
||||
iter_data.point_func_cb = func_cb;
|
||||
iter_data.user_data = user_data;
|
||||
|
||||
BKE_gpencil_visible_stroke_iter(
|
||||
(bGPdata *)ob->data, nullptr, foreach_display_point_gpencil_stroke_fn, &iter_data);
|
||||
}
|
||||
else if (ob->runtime->curve_cache && ob->runtime->curve_cache->disp.first) {
|
||||
LISTBASE_FOREACH (DispList *, dl, &ob->runtime->curve_cache->disp) {
|
||||
const float *v3 = dl->verts;
|
||||
@@ -4880,7 +4841,6 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int /*flag*/)
|
||||
{
|
||||
blender::bke::ObjectRuntime *runtime = object->runtime;
|
||||
runtime->data_eval = nullptr;
|
||||
runtime->gpd_eval = nullptr;
|
||||
runtime->mesh_deform_eval = nullptr;
|
||||
runtime->curve_cache = nullptr;
|
||||
runtime->object_as_temp_mesh = nullptr;
|
||||
|
||||
@@ -390,24 +390,19 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
|
||||
|
||||
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
|
||||
{
|
||||
if (ob->type == OB_GPENCIL_LEGACY) {
|
||||
BKE_gpencil_vgroup_remove(ob, defgroup);
|
||||
if (BKE_object_is_in_editmode_vgroup(ob)) {
|
||||
object_defgroup_remove_edit_mode(ob, defgroup);
|
||||
}
|
||||
else {
|
||||
if (BKE_object_is_in_editmode_vgroup(ob)) {
|
||||
object_defgroup_remove_edit_mode(ob, defgroup);
|
||||
}
|
||||
else {
|
||||
object_defgroup_remove_object_mode(ob, defgroup);
|
||||
}
|
||||
|
||||
if (ob->type == OB_GREASE_PENCIL) {
|
||||
blender::bke::greasepencil::validate_drawing_vertex_groups(
|
||||
*static_cast<GreasePencil *>(ob->data));
|
||||
}
|
||||
|
||||
BKE_object_batch_cache_dirty_tag(ob);
|
||||
object_defgroup_remove_object_mode(ob, defgroup);
|
||||
}
|
||||
|
||||
if (ob->type == OB_GREASE_PENCIL) {
|
||||
blender::bke::greasepencil::validate_drawing_vertex_groups(
|
||||
*static_cast<GreasePencil *>(ob->data));
|
||||
}
|
||||
|
||||
BKE_object_batch_cache_dirty_tag(ob);
|
||||
}
|
||||
|
||||
void BKE_object_defgroup_remove_all_ex(Object *ob, bool only_unlocked)
|
||||
|
||||
@@ -282,9 +282,6 @@ void BKE_object_batch_cache_dirty_tag(Object *ob)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OB_GPENCIL_LEGACY:
|
||||
BKE_gpencil_batch_cache_dirty_tag((bGPdata *)ob->data);
|
||||
break;
|
||||
case OB_CURVES:
|
||||
BKE_curves_batch_cache_dirty_tag((Curves *)ob->data, BKE_CURVES_BATCH_DIRTY_ALL);
|
||||
break;
|
||||
|
||||
@@ -56,7 +56,6 @@ set(SRC
|
||||
intern/eval/deg_eval_flush.cc
|
||||
intern/eval/deg_eval_runtime_backup.cc
|
||||
intern/eval/deg_eval_runtime_backup_animation.cc
|
||||
intern/eval/deg_eval_runtime_backup_gpencil.cc
|
||||
intern/eval/deg_eval_runtime_backup_modifier.cc
|
||||
intern/eval/deg_eval_runtime_backup_movieclip.cc
|
||||
intern/eval/deg_eval_runtime_backup_object.cc
|
||||
@@ -126,7 +125,6 @@ set(SRC
|
||||
intern/eval/deg_eval_flush.h
|
||||
intern/eval/deg_eval_runtime_backup.h
|
||||
intern/eval/deg_eval_runtime_backup_animation.h
|
||||
intern/eval/deg_eval_runtime_backup_gpencil.h
|
||||
intern/eval/deg_eval_runtime_backup_modifier.h
|
||||
intern/eval/deg_eval_runtime_backup_movieclip.h
|
||||
intern/eval/deg_eval_runtime_backup_object.h
|
||||
|
||||
@@ -1783,18 +1783,6 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata)
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_GD_LEGACY: {
|
||||
/* GPencil evaluation operations. */
|
||||
op_node = add_operation_node(obdata,
|
||||
NodeType::GEOMETRY,
|
||||
OperationCode::GEOMETRY_EVAL,
|
||||
[obdata_cow](::Depsgraph *depsgraph) {
|
||||
BKE_gpencil_frame_active_set(depsgraph,
|
||||
(bGPdata *)obdata_cow);
|
||||
});
|
||||
op_node->set_as_entry();
|
||||
break;
|
||||
}
|
||||
case ID_CV: {
|
||||
Curves *curves_id = reinterpret_cast<Curves *>(obdata);
|
||||
|
||||
|
||||
@@ -888,14 +888,6 @@ ID *deg_update_eval_copy_datablock(const Depsgraph *depsgraph, const IDNode *id_
|
||||
update_edit_mode_pointers(depsgraph, id_orig, id_cow);
|
||||
return id_cow;
|
||||
}
|
||||
/* In case we don't need to do a copy-on-evaluation, we can use the update cache of the grease
|
||||
* pencil data to do an update-on-write. */
|
||||
if (id_type == ID_GD_LEGACY && BKE_gpencil_can_avoid_full_copy_on_write(
|
||||
(const ::Depsgraph *)depsgraph, (bGPdata *)id_orig))
|
||||
{
|
||||
BKE_gpencil_update_on_write((bGPdata *)id_orig, (bGPdata *)id_cow);
|
||||
return id_cow;
|
||||
}
|
||||
}
|
||||
|
||||
RuntimeBackup backup(depsgraph);
|
||||
|
||||
@@ -25,8 +25,7 @@ RuntimeBackup::RuntimeBackup(const Depsgraph *depsgraph)
|
||||
object_backup(depsgraph),
|
||||
drawdata_ptr(nullptr),
|
||||
movieclip_backup(depsgraph),
|
||||
volume_backup(depsgraph),
|
||||
gpencil_backup(depsgraph)
|
||||
volume_backup(depsgraph)
|
||||
{
|
||||
drawdata_backup.first = drawdata_backup.last = nullptr;
|
||||
}
|
||||
@@ -61,9 +60,6 @@ void RuntimeBackup::init_from_id(ID *id)
|
||||
case ID_VO:
|
||||
volume_backup.init_from_volume(reinterpret_cast<Volume *>(id));
|
||||
break;
|
||||
case ID_GD_LEGACY:
|
||||
gpencil_backup.init_from_gpencil(reinterpret_cast<bGPdata *>(id));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -104,9 +100,6 @@ void RuntimeBackup::restore_to_id(ID *id)
|
||||
case ID_VO:
|
||||
volume_backup.restore_to_volume(reinterpret_cast<Volume *>(id));
|
||||
break;
|
||||
case ID_GD_LEGACY:
|
||||
gpencil_backup.restore_to_gpencil(reinterpret_cast<bGPdata *>(id));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "DNA_ID.h"
|
||||
|
||||
#include "intern/eval/deg_eval_runtime_backup_animation.h"
|
||||
#include "intern/eval/deg_eval_runtime_backup_gpencil.h"
|
||||
#include "intern/eval/deg_eval_runtime_backup_movieclip.h"
|
||||
#include "intern/eval/deg_eval_runtime_backup_object.h"
|
||||
#include "intern/eval/deg_eval_runtime_backup_scene.h"
|
||||
@@ -56,7 +55,6 @@ class RuntimeBackup {
|
||||
DrawDataList *drawdata_ptr;
|
||||
MovieClipBackup movieclip_backup;
|
||||
VolumeBackup volume_backup;
|
||||
GPencilBackup gpencil_backup;
|
||||
};
|
||||
|
||||
} // namespace blender::deg
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup depsgraph
|
||||
*/
|
||||
|
||||
#include "intern/eval/deg_eval_runtime_backup_gpencil.h"
|
||||
#include "intern/depsgraph.hh"
|
||||
|
||||
#include "BKE_gpencil_legacy.h"
|
||||
#include "BKE_gpencil_update_cache_legacy.h"
|
||||
|
||||
#include "DNA_gpencil_legacy_types.h"
|
||||
|
||||
namespace blender::deg {
|
||||
|
||||
GPencilBackup::GPencilBackup(const Depsgraph *depsgraph) : depsgraph(depsgraph) {}
|
||||
|
||||
void GPencilBackup::init_from_gpencil(bGPdata * /*gpd*/) {}
|
||||
|
||||
void GPencilBackup::restore_to_gpencil(bGPdata *gpd)
|
||||
{
|
||||
bGPdata *gpd_orig = reinterpret_cast<bGPdata *>(gpd->id.orig_id);
|
||||
|
||||
/* We check for the active depsgraph here to avoid freeing the cache on the original object
|
||||
* multiple times. This free is only needed for the case where we tagged a full update in the
|
||||
* update cache and did not do an update-on-write. */
|
||||
if (depsgraph->is_active) {
|
||||
BKE_gpencil_free_update_cache(gpd_orig);
|
||||
}
|
||||
/* Doing a copy-on-evaluation copies the update cache pointer. Make sure to reset it
|
||||
* to null as we should never use the update cache from eval data. */
|
||||
gpd->runtime.update_cache = nullptr;
|
||||
/* Make sure to update the original runtime pointers in the eval data. */
|
||||
BKE_gpencil_data_update_orig_pointers(gpd_orig, gpd);
|
||||
}
|
||||
|
||||
} // namespace blender::deg
|
||||
@@ -1,28 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup depsgraph
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct bGPdata;
|
||||
|
||||
namespace blender::deg {
|
||||
|
||||
struct Depsgraph;
|
||||
|
||||
/* Backup of volume datablocks runtime data. */
|
||||
class GPencilBackup {
|
||||
public:
|
||||
GPencilBackup(const Depsgraph *depsgraph);
|
||||
|
||||
void init_from_gpencil(bGPdata *gpd);
|
||||
void restore_to_gpencil(bGPdata *gpd);
|
||||
|
||||
const Depsgraph *depsgraph;
|
||||
};
|
||||
|
||||
} // namespace blender::deg
|
||||
@@ -294,9 +294,6 @@ void Instance::object_sync(Object *ob)
|
||||
case OB_CURVES:
|
||||
sync.sync_curves(ob, ob_handle, res_handle, ob_ref);
|
||||
break;
|
||||
case OB_GREASE_PENCIL:
|
||||
sync.sync_gpencil(ob, ob_handle, res_handle);
|
||||
break;
|
||||
case OB_LIGHTPROBE:
|
||||
light_probes.sync_probe(ob, ob_handle);
|
||||
break;
|
||||
|
||||
@@ -393,149 +393,6 @@ void SyncModule::sync_volume(Object *ob,
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name GPencil
|
||||
* \{ */
|
||||
|
||||
#define DO_BATCHING true
|
||||
|
||||
struct gpIterData {
|
||||
Instance &inst;
|
||||
Object *ob;
|
||||
MaterialArray &material_array;
|
||||
int cfra;
|
||||
|
||||
/* Drawcall batching. */
|
||||
gpu::Batch *geom = nullptr;
|
||||
Material *material = nullptr;
|
||||
int vfirst = 0;
|
||||
int vcount = 0;
|
||||
bool instancing = false;
|
||||
|
||||
gpIterData(Instance &inst_, Object *ob_, ObjectHandle &ob_handle, ResourceHandle resource_handle)
|
||||
: inst(inst_),
|
||||
ob(ob_),
|
||||
material_array(inst_.materials.material_array_get(
|
||||
ob_,
|
||||
inst_.velocity.step_object_sync(
|
||||
ob, ob_handle.object_key, resource_handle, ob_handle.recalc)))
|
||||
{
|
||||
cfra = DEG_get_ctime(inst.depsgraph);
|
||||
};
|
||||
};
|
||||
|
||||
static void gpencil_drawcall_flush(gpIterData &iter)
|
||||
{
|
||||
#if 0 /* Incompatible with new draw manager. */
|
||||
if (iter.geom != nullptr) {
|
||||
geometry_call(iter.material->shading.sub_pass,
|
||||
iter.ob,
|
||||
iter.geom,
|
||||
iter.vfirst,
|
||||
iter.vcount,
|
||||
iter.instancing);
|
||||
geometry_call(iter.material->prepass.sub_pass,
|
||||
iter.ob,
|
||||
iter.geom,
|
||||
iter.vfirst,
|
||||
iter.vcount,
|
||||
iter.instancing);
|
||||
geometry_call(iter.material->shadow.sub_pass,
|
||||
iter.ob,
|
||||
iter.geom,
|
||||
iter.vfirst,
|
||||
iter.vcount,
|
||||
iter.instancing);
|
||||
}
|
||||
#endif
|
||||
iter.geom = nullptr;
|
||||
iter.vfirst = -1;
|
||||
iter.vcount = 0;
|
||||
}
|
||||
|
||||
/* Group draw-calls that are consecutive and with the same type. Reduces GPU driver overhead. */
|
||||
static void gpencil_drawcall_add(gpIterData &iter,
|
||||
gpu::Batch *geom,
|
||||
Material *material,
|
||||
int v_first,
|
||||
int v_count,
|
||||
bool instancing)
|
||||
{
|
||||
int last = iter.vfirst + iter.vcount;
|
||||
/* Interrupt draw-call grouping if the sequence is not consecutive. */
|
||||
if (!DO_BATCHING || (geom != iter.geom) || (material != iter.material) || (v_first - last > 3)) {
|
||||
gpencil_drawcall_flush(iter);
|
||||
}
|
||||
iter.geom = geom;
|
||||
iter.material = material;
|
||||
iter.instancing = instancing;
|
||||
if (iter.vfirst == -1) {
|
||||
iter.vfirst = v_first;
|
||||
}
|
||||
iter.vcount = v_first + v_count - iter.vfirst;
|
||||
}
|
||||
|
||||
static void gpencil_stroke_sync(bGPDlayer * /*gpl*/,
|
||||
bGPDframe * /*gpf*/,
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
gpIterData &iter = *(gpIterData *)thunk;
|
||||
|
||||
Material *material = &iter.material_array.materials[gps->mat_nr];
|
||||
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter.ob, gps->mat_nr + 1);
|
||||
|
||||
bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
|
||||
bool show_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0) ||
|
||||
(!DRW_state_is_image_render() && ((gps->flag & GP_STROKE_NOFILL) != 0));
|
||||
bool show_fill = (gps->tot_triangles > 0) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0);
|
||||
|
||||
if (hide_material) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpu::Batch *geom = DRW_cache_gpencil_get(iter.ob, iter.cfra);
|
||||
|
||||
if (show_fill) {
|
||||
int vfirst = gps->runtime.fill_start * 3;
|
||||
int vcount = gps->tot_triangles * 3;
|
||||
gpencil_drawcall_add(iter, geom, material, vfirst, vcount, false);
|
||||
}
|
||||
|
||||
if (show_stroke) {
|
||||
/* Start one vert before to have gl_InstanceID > 0 (see shader). */
|
||||
int vfirst = gps->runtime.stroke_start * 3;
|
||||
/* Include "potential" cyclic vertex and start adj vertex (see shader). */
|
||||
int vcount = gps->totpoints + 1 + 1;
|
||||
gpencil_drawcall_add(iter, geom, material, vfirst, vcount, true);
|
||||
}
|
||||
}
|
||||
|
||||
void SyncModule::sync_gpencil(Object *ob, ObjectHandle &ob_handle, ResourceHandle res_handle)
|
||||
{
|
||||
/* TODO(fclem): Waiting for a user option to use the render engine instead of gpencil engine. */
|
||||
return;
|
||||
|
||||
/* Is this a surface or curves? */
|
||||
if (!inst_.use_surfaces) {
|
||||
return;
|
||||
}
|
||||
|
||||
UNUSED_VARS(res_handle);
|
||||
|
||||
gpIterData iter(inst_, ob, ob_handle, res_handle);
|
||||
|
||||
BKE_gpencil_visible_stroke_iter((bGPdata *)ob->data, nullptr, gpencil_stroke_sync, &iter);
|
||||
|
||||
gpencil_drawcall_flush(iter);
|
||||
|
||||
bool is_alpha_blend = true; /* TODO material.is_alpha_blend. */
|
||||
bool has_transparent_shadows = true; /* TODO material.has_transparent_shadows. */
|
||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Hair
|
||||
* \{ */
|
||||
|
||||
@@ -178,7 +178,6 @@ class SyncModule {
|
||||
ObjectHandle &ob_handle,
|
||||
ResourceHandle res_handle,
|
||||
const ObjectRef &ob_ref);
|
||||
void sync_gpencil(Object *ob, ObjectHandle &ob_handle, ResourceHandle res_handle);
|
||||
void sync_curves(Object *ob,
|
||||
ObjectHandle &ob_handle,
|
||||
ResourceHandle res_handle,
|
||||
|
||||
@@ -244,16 +244,6 @@ void GPENCIL_cache_init(void *ved)
|
||||
pd->do_fast_drawing = false;
|
||||
|
||||
pd->obact = draw_ctx->obact;
|
||||
if (pd->obact && pd->obact->type == OB_GPENCIL_LEGACY && !(pd->draw_depth_only)) {
|
||||
/* Check if active object has a temp stroke data. */
|
||||
bGPdata *gpd = (bGPdata *)pd->obact->data;
|
||||
if (gpd->runtime.sbuffer_used > 0) {
|
||||
pd->sbuffer_gpd = gpd;
|
||||
pd->sbuffer_stroke = DRW_cache_gpencil_sbuffer_stroke_data_get(pd->obact);
|
||||
pd->sbuffer_layer = BKE_gpencil_layer_active_get(pd->sbuffer_gpd);
|
||||
pd->do_fast_drawing = false; /* TODO: option. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pd->do_fast_drawing) {
|
||||
@@ -332,273 +322,8 @@ void GPENCIL_cache_init(void *ved)
|
||||
}
|
||||
}
|
||||
|
||||
#define DRAW_NOW 2
|
||||
|
||||
struct gpIterPopulateData {
|
||||
Object *ob;
|
||||
GPENCIL_tObject *tgp_ob;
|
||||
GPENCIL_PrivateData *pd;
|
||||
GPENCIL_MaterialPool *matpool;
|
||||
DRWShadingGroup *grp;
|
||||
/* Last material UBO bound. Used to avoid unneeded buffer binding. */
|
||||
GPUUniformBuf *ubo_mat;
|
||||
GPUUniformBuf *ubo_lights;
|
||||
/* Last texture bound. */
|
||||
GPUTexture *tex_fill;
|
||||
GPUTexture *tex_stroke;
|
||||
/* Offset in the material pool to the first material of this object. */
|
||||
int mat_ofs;
|
||||
/* Is the sbuffer call need to be issued. */
|
||||
int do_sbuffer_call;
|
||||
/* Indices to do correct insertion of the sbuffer stroke. */
|
||||
int stroke_index_last;
|
||||
int stroke_index_offset;
|
||||
/* Infos for call batching. */
|
||||
blender::gpu::Batch *geom;
|
||||
int vfirst, vcount;
|
||||
};
|
||||
|
||||
#define DISABLE_BATCHING 0
|
||||
|
||||
static void gpencil_drawcall_flush(gpIterPopulateData *iter)
|
||||
{
|
||||
#if !DISABLE_BATCHING
|
||||
if (iter->geom != nullptr) {
|
||||
DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount);
|
||||
}
|
||||
#endif
|
||||
|
||||
iter->geom = nullptr;
|
||||
iter->vfirst = -1;
|
||||
iter->vcount = 0;
|
||||
}
|
||||
|
||||
/* Group draw-calls that are consecutive and with the same type. Reduces GPU driver overhead. */
|
||||
static void gpencil_drawcall_add(gpIterPopulateData *iter,
|
||||
blender::gpu::Batch *geom,
|
||||
int v_first,
|
||||
int v_count)
|
||||
{
|
||||
#if DISABLE_BATCHING
|
||||
DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count);
|
||||
return;
|
||||
#endif
|
||||
|
||||
int last = iter->vfirst + iter->vcount;
|
||||
/* Interrupt draw-call grouping if the sequence is not consecutive. */
|
||||
if ((geom != iter->geom) || (v_first - last > 0)) {
|
||||
gpencil_drawcall_flush(iter);
|
||||
}
|
||||
iter->geom = geom;
|
||||
if (iter->vfirst == -1) {
|
||||
iter->vfirst = v_first;
|
||||
}
|
||||
iter->vcount = v_first + v_count - iter->vfirst;
|
||||
}
|
||||
|
||||
static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
|
||||
bGPDframe *gpf,
|
||||
bGPDstroke *gps,
|
||||
void *thunk);
|
||||
|
||||
static void gpencil_sbuffer_cache_populate(gpIterPopulateData *iter)
|
||||
{
|
||||
iter->do_sbuffer_call = DRAW_NOW;
|
||||
/* In order to draw the sbuffer stroke correctly mixed with other strokes,
|
||||
* we need to offset the stroke index of the sbuffer stroke and the subsequent strokes.
|
||||
* Remember, sbuffer stroke indices start from 0. So we add last index to avoid
|
||||
* masking issues. */
|
||||
iter->grp = DRW_shgroup_create_sub(iter->grp);
|
||||
DRW_shgroup_uniform_block(iter->grp, "gp_materials", iter->ubo_mat);
|
||||
DRW_shgroup_uniform_float_copy(iter->grp, "gpStrokeIndexOffset", iter->stroke_index_last);
|
||||
|
||||
const DRWContextState *ctx = DRW_context_state_get();
|
||||
ToolSettings *ts = ctx->scene->toolsettings;
|
||||
if (ts->gpencil_v3d_align & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) {
|
||||
/* In this case we can't do correct projection during stroke. We just disable depth test. */
|
||||
DRW_shgroup_uniform_texture(iter->grp, "gpSceneDepthTexture", iter->pd->dummy_tx);
|
||||
}
|
||||
|
||||
gpencil_stroke_cache_populate(nullptr, nullptr, iter->pd->sbuffer_stroke, iter);
|
||||
gpencil_drawcall_flush(iter);
|
||||
|
||||
iter->stroke_index_offset = iter->pd->sbuffer_stroke->totpoints + 1;
|
||||
iter->do_sbuffer_call = 0;
|
||||
}
|
||||
|
||||
static void gpencil_layer_cache_populate(bGPDlayer *gpl,
|
||||
bGPDframe *gpf,
|
||||
bGPDstroke * /*gps*/,
|
||||
void *thunk)
|
||||
{
|
||||
gpIterPopulateData *iter = (gpIterPopulateData *)thunk;
|
||||
GPENCIL_PrivateData *pd = iter->pd;
|
||||
bGPdata *gpd = (bGPdata *)iter->ob->data;
|
||||
|
||||
gpencil_drawcall_flush(iter);
|
||||
|
||||
if (iter->do_sbuffer_call) {
|
||||
gpencil_sbuffer_cache_populate(iter);
|
||||
}
|
||||
else {
|
||||
iter->do_sbuffer_call = !pd->do_fast_drawing && (gpd == pd->sbuffer_gpd) &&
|
||||
(gpl == pd->sbuffer_layer) &&
|
||||
(gpf == nullptr || gpf->runtime.onion_id == 0.0f);
|
||||
}
|
||||
|
||||
GPENCIL_tLayer *tgp_layer = gpencil_layer_cache_add(pd, iter->ob, gpl, gpf, iter->tgp_ob);
|
||||
|
||||
const bool use_lights = pd->use_lighting && ((gpl->flag & GP_LAYER_USE_LIGHTS) != 0) &&
|
||||
(iter->ob->dtx & OB_USE_GPENCIL_LIGHTS);
|
||||
|
||||
iter->ubo_lights = (use_lights) ? pd->global_light_pool->ubo : pd->shadeless_light_pool->ubo;
|
||||
|
||||
gpencil_material_resources_get(iter->matpool, 0, nullptr, nullptr, &iter->ubo_mat);
|
||||
|
||||
/* Iterator dependent uniforms. */
|
||||
DRWShadingGroup *grp = iter->grp = tgp_layer->base_shgrp;
|
||||
DRW_shgroup_uniform_block(grp, "gp_lights", iter->ubo_lights);
|
||||
DRW_shgroup_uniform_block(grp, "gp_materials", iter->ubo_mat);
|
||||
DRW_shgroup_uniform_texture(grp, "gpFillTexture", iter->tex_fill);
|
||||
DRW_shgroup_uniform_texture(grp, "gpStrokeTexture", iter->tex_stroke);
|
||||
DRW_shgroup_uniform_int_copy(grp, "gpMaterialOffset", iter->mat_ofs);
|
||||
DRW_shgroup_uniform_float_copy(grp, "gpStrokeIndexOffset", iter->stroke_index_offset);
|
||||
DRW_shgroup_uniform_vec2_copy(grp, "viewportSize", DRW_viewport_size_get());
|
||||
}
|
||||
|
||||
static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
|
||||
bGPDframe *gpf,
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
gpIterPopulateData *iter = (gpIterPopulateData *)thunk;
|
||||
|
||||
bGPdata *gpd = static_cast<bGPdata *>(iter->ob->data);
|
||||
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1);
|
||||
|
||||
const bool is_render = iter->pd->is_render;
|
||||
bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
|
||||
bool show_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0) ||
|
||||
(!is_render && ((gps->flag & GP_STROKE_NOFILL) != 0));
|
||||
bool show_fill = (gps->tot_triangles > 0) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0) &&
|
||||
(!iter->pd->simplify_fill) && ((gps->flag & GP_STROKE_NOFILL) == 0);
|
||||
bool only_lines = !GPENCIL_PAINT_MODE(gpd) && gpl && gpf && gpl->actframe != gpf &&
|
||||
iter->pd->use_multiedit_lines_only;
|
||||
bool is_onion = gpl && gpf && gpf->runtime.onion_id != 0;
|
||||
bool hide_onion = is_onion && ((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0);
|
||||
if ((hide_material) || (!show_stroke && !show_fill) || (only_lines && !is_onion) || (hide_onion))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GPUUniformBuf *ubo_mat;
|
||||
GPUTexture *tex_stroke, *tex_fill;
|
||||
gpencil_material_resources_get(
|
||||
iter->matpool, iter->mat_ofs + gps->mat_nr, &tex_stroke, &tex_fill, &ubo_mat);
|
||||
|
||||
bool resource_changed = (iter->ubo_mat != ubo_mat) ||
|
||||
(tex_fill && (iter->tex_fill != tex_fill)) ||
|
||||
(tex_stroke && (iter->tex_stroke != tex_stroke));
|
||||
|
||||
if (resource_changed) {
|
||||
gpencil_drawcall_flush(iter);
|
||||
|
||||
iter->grp = DRW_shgroup_create_sub(iter->grp);
|
||||
if (iter->ubo_mat != ubo_mat) {
|
||||
DRW_shgroup_uniform_block(iter->grp, "gp_materials", ubo_mat);
|
||||
iter->ubo_mat = ubo_mat;
|
||||
}
|
||||
if (tex_fill) {
|
||||
DRW_shgroup_uniform_texture(iter->grp, "gpFillTexture", tex_fill);
|
||||
iter->tex_fill = tex_fill;
|
||||
}
|
||||
if (tex_stroke) {
|
||||
DRW_shgroup_uniform_texture(iter->grp, "gpStrokeTexture", tex_stroke);
|
||||
iter->tex_stroke = tex_stroke;
|
||||
}
|
||||
}
|
||||
|
||||
bool do_sbuffer = (iter->do_sbuffer_call == DRAW_NOW);
|
||||
|
||||
blender::gpu::Batch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_get(iter->ob, show_fill) :
|
||||
DRW_cache_gpencil_get(iter->ob, iter->pd->cfra);
|
||||
if (geom != iter->geom) {
|
||||
gpencil_drawcall_flush(iter);
|
||||
|
||||
blender::gpu::VertBuf *position_tx =
|
||||
do_sbuffer ? DRW_cache_gpencil_sbuffer_position_buffer_get(iter->ob, show_fill) :
|
||||
DRW_cache_gpencil_position_buffer_get(iter->ob, iter->pd->cfra);
|
||||
blender::gpu::VertBuf *color_tx = do_sbuffer ?
|
||||
DRW_cache_gpencil_sbuffer_color_buffer_get(iter->ob,
|
||||
show_fill) :
|
||||
DRW_cache_gpencil_color_buffer_get(iter->ob,
|
||||
iter->pd->cfra);
|
||||
DRW_shgroup_buffer_texture(iter->grp, "gp_pos_tx", position_tx);
|
||||
DRW_shgroup_buffer_texture(iter->grp, "gp_col_tx", color_tx);
|
||||
}
|
||||
|
||||
if (show_fill) {
|
||||
int vfirst = gps->runtime.fill_start * 3;
|
||||
int vcount = gps->tot_triangles * 3;
|
||||
gpencil_drawcall_add(iter, geom, vfirst, vcount);
|
||||
}
|
||||
|
||||
if (show_stroke) {
|
||||
int vfirst = gps->runtime.stroke_start * 3;
|
||||
bool is_cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2);
|
||||
int vcount = (gps->totpoints + int(is_cyclic)) * 2 * 3;
|
||||
gpencil_drawcall_add(iter, geom, vfirst, vcount);
|
||||
}
|
||||
|
||||
iter->stroke_index_last = gps->runtime.vertex_start + gps->totpoints + 1;
|
||||
}
|
||||
|
||||
static void gpencil_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopulateData *iter)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)iter->ob->data;
|
||||
if (gpd != iter->pd->sbuffer_gpd) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPENCIL_TextureList *txl = vedata->txl;
|
||||
GPUTexture *depth_texture = iter->pd->scene_depth_tx;
|
||||
GPENCIL_tObject *last_tgp_ob = iter->pd->tobjects.last;
|
||||
/* Create another temp object that only contain the stroke. */
|
||||
const blender::Bounds<float3> bounds = BKE_gpencil_data_minmax(gpd).value_or(
|
||||
blender::Bounds(float3(0)));
|
||||
iter->tgp_ob = gpencil_object_cache_add(
|
||||
iter->pd, iter->ob, (gpd->draw_mode == GP_DRAWMODE_3D), bounds);
|
||||
/* Remove from the main list. */
|
||||
iter->pd->tobjects.last = last_tgp_ob;
|
||||
last_tgp_ob->next = nullptr;
|
||||
/* Add to sbuffer tgpobject list. */
|
||||
BLI_LINKS_APPEND(&iter->pd->sbuffer_tobjects, iter->tgp_ob);
|
||||
/* Remove depth test with scene (avoid self occlusion). */
|
||||
iter->pd->scene_depth_tx = txl->dummy_texture;
|
||||
|
||||
gpencil_layer_cache_populate(
|
||||
iter->pd->sbuffer_layer, iter->pd->sbuffer_layer->actframe, nullptr, iter);
|
||||
|
||||
const DRWContextState *ctx = DRW_context_state_get();
|
||||
ToolSettings *ts = ctx->scene->toolsettings;
|
||||
if (ts->gpencil_v3d_align & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) {
|
||||
/* In this case we can't do correct projection during stroke. We just disable depth test. */
|
||||
DRW_shgroup_uniform_texture(iter->grp, "gpSceneDepthTexture", iter->pd->dummy_tx);
|
||||
}
|
||||
|
||||
iter->do_sbuffer_call = DRAW_NOW;
|
||||
gpencil_stroke_cache_populate(nullptr, nullptr, iter->pd->sbuffer_stroke, iter);
|
||||
gpencil_drawcall_flush(iter);
|
||||
|
||||
gpencil_vfx_cache_populate(
|
||||
vedata, iter->ob, iter->tgp_ob, (gpd != nullptr && GPENCIL_ANY_EDIT_MODE(gpd)));
|
||||
|
||||
/* Restore state. */
|
||||
iter->do_sbuffer_call = 0;
|
||||
iter->pd->scene_depth_tx = depth_texture;
|
||||
}
|
||||
|
||||
/* Check if the passed in layer is used by any other layer as a mask (in the viewlayer). */
|
||||
static bool is_used_as_layer_mask_in_viewlayer(const GreasePencil &grease_pencil,
|
||||
const blender::bke::greasepencil::Layer &mask_layer,
|
||||
@@ -877,59 +602,13 @@ void GPENCIL_cache_populate(void *ved, Object *ob)
|
||||
GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
|
||||
GPENCIL_PrivateData *pd = vedata->stl->pd;
|
||||
GPENCIL_TextureList *txl = vedata->txl;
|
||||
const bool is_final_render = DRW_state_is_image_render();
|
||||
|
||||
/* object must be visible */
|
||||
if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ob->data && (ob->type == OB_GPENCIL_LEGACY) && (ob->dt >= OB_SOLID)) {
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
const blender::Bounds<float3> bounds = BKE_gpencil_data_minmax(gpd).value_or(
|
||||
blender::Bounds(float3(0)));
|
||||
gpIterPopulateData iter = {nullptr};
|
||||
iter.ob = ob;
|
||||
iter.pd = pd;
|
||||
iter.tgp_ob = gpencil_object_cache_add(pd, ob, (gpd->draw_mode == GP_DRAWMODE_3D), bounds);
|
||||
iter.matpool = gpencil_material_pool_create(pd, ob, &iter.mat_ofs, GPENCIL_VERTEX_MODE(gpd));
|
||||
iter.tex_fill = txl->dummy_texture;
|
||||
iter.tex_stroke = txl->dummy_texture;
|
||||
|
||||
/* Special case for rendering onion skin. */
|
||||
bool do_onion = (!pd->is_render) ? pd->do_onion : (gpd->onion_flag & GP_ONION_GHOST_ALWAYS);
|
||||
gpd->runtime.playing = short(pd->playing);
|
||||
|
||||
/* When render in background the active frame could not be properly set due thread priority,
|
||||
* better set again. This is not required in viewport. */
|
||||
if (txl->render_depth_tx) {
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
gpl->actframe = BKE_gpencil_layer_frame_get(gpl, pd->cfra, GP_GETFRAME_USE_PREV);
|
||||
}
|
||||
}
|
||||
|
||||
BKE_gpencil_visible_stroke_advanced_iter(is_final_render ? pd->view_layer : nullptr,
|
||||
ob,
|
||||
gpencil_layer_cache_populate,
|
||||
gpencil_stroke_cache_populate,
|
||||
&iter,
|
||||
do_onion,
|
||||
pd->cfra);
|
||||
|
||||
gpencil_drawcall_flush(&iter);
|
||||
|
||||
if (iter.do_sbuffer_call) {
|
||||
gpencil_sbuffer_cache_populate(&iter);
|
||||
}
|
||||
|
||||
gpencil_vfx_cache_populate(
|
||||
vedata, ob, iter.tgp_ob, (gpd != nullptr && GPENCIL_ANY_EDIT_MODE(gpd)));
|
||||
|
||||
if (pd->do_fast_drawing) {
|
||||
gpencil_sbuffer_cache_populate_fast(vedata, &iter);
|
||||
}
|
||||
}
|
||||
else if (ob->data && (ob->type == OB_GREASE_PENCIL) && (ob->dt >= OB_SOLID)) {
|
||||
if (ob->data && (ob->type == OB_GREASE_PENCIL) && (ob->dt >= OB_SOLID)) {
|
||||
GPENCIL_tObject *tgp_ob = grease_pencil_object_cache_populate(pd, txl, ob);
|
||||
gpencil_vfx_cache_populate(
|
||||
vedata, ob, tgp_ob, ELEM(ob->mode, OB_MODE_EDIT, OB_MODE_SCULPT, OB_MODE_WEIGHT_PAINT));
|
||||
|
||||
@@ -518,9 +518,6 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
|
||||
OVERLAY_metaball_cache_populate(data, ob);
|
||||
}
|
||||
break;
|
||||
case OB_GPENCIL_LEGACY:
|
||||
OVERLAY_gpencil_legacy_cache_populate(data, ob);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Non-Meshes */
|
||||
|
||||
@@ -322,52 +322,6 @@ void OVERLAY_gpencil_legacy_cache_init(OVERLAY_Data *vedata)
|
||||
}
|
||||
}
|
||||
|
||||
static void OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
View3D *v3d = draw_ctx->v3d;
|
||||
|
||||
/* Overlay is only for active object. */
|
||||
if (ob != draw_ctx->obact) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pd->edit_gpencil_wires_grp) {
|
||||
DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_wires_grp);
|
||||
DRW_shgroup_uniform_vec4_copy(grp, "gpEditColor", gpd->line_color);
|
||||
|
||||
blender::gpu::Batch *geom = DRW_cache_gpencil_edit_lines_get(ob, pd->cfra);
|
||||
DRW_shgroup_call_no_cull(pd->edit_gpencil_wires_grp, geom, ob);
|
||||
}
|
||||
|
||||
if (pd->edit_gpencil_points_grp) {
|
||||
const bool show_direction = (v3d->gp_flag & V3D_GP_SHOW_STROKE_DIRECTION) != 0;
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_points_grp);
|
||||
DRW_shgroup_uniform_float_copy(grp, "doStrokeEndpoints", show_direction);
|
||||
|
||||
blender::gpu::Batch *geom = DRW_cache_gpencil_edit_points_get(ob, pd->cfra);
|
||||
DRW_shgroup_call_no_cull(grp, geom, ob);
|
||||
}
|
||||
|
||||
if (pd->edit_gpencil_curve_handle_grp) {
|
||||
blender::gpu::Batch *geom = DRW_cache_gpencil_edit_curve_handles_get(ob, pd->cfra);
|
||||
if (geom) {
|
||||
DRW_shgroup_call_no_cull(pd->edit_gpencil_curve_handle_grp, geom, ob);
|
||||
}
|
||||
}
|
||||
|
||||
if (pd->edit_gpencil_curve_points_grp) {
|
||||
blender::gpu::Batch *geom = DRW_cache_gpencil_edit_curve_points_get(ob, pd->cfra);
|
||||
if (geom) {
|
||||
DRW_shgroup_call_no_cull(pd->edit_gpencil_curve_points_grp, geom, ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void overlay_gpencil_draw_stroke_color_name(bGPDlayer * /*gpl*/,
|
||||
bGPDframe * /*gpf*/,
|
||||
bGPDstroke *gps,
|
||||
@@ -427,30 +381,6 @@ static void OVERLAY_gpencil_color_names(Object *ob)
|
||||
nullptr, ob, nullptr, overlay_gpencil_draw_stroke_color_name, ob, false, cfra);
|
||||
}
|
||||
|
||||
void OVERLAY_gpencil_legacy_cache_populate(OVERLAY_Data *vedata, Object *ob)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
View3D *v3d = draw_ctx->v3d;
|
||||
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
if (gpd == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GPENCIL_ANY_MODE(gpd)) {
|
||||
OVERLAY_edit_gpencil_cache_populate(vedata, ob);
|
||||
}
|
||||
|
||||
/* don't show object extras in set's */
|
||||
if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
|
||||
if ((v3d->gp_flag & V3D_GP_SHOW_MATERIAL_NAME) && (ob->mode == OB_MODE_EDIT_GPENCIL_LEGACY) &&
|
||||
DRW_state_show_text())
|
||||
{
|
||||
OVERLAY_gpencil_color_names(ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OVERLAY_gpencil_legacy_draw(OVERLAY_Data *vedata)
|
||||
{
|
||||
OVERLAY_PassList *psl = vedata->psl;
|
||||
|
||||
@@ -186,97 +186,6 @@ struct iterData {
|
||||
float plane[4];
|
||||
};
|
||||
|
||||
static void gpencil_layer_cache_populate(bGPDlayer *gpl,
|
||||
bGPDframe * /*gpf*/,
|
||||
bGPDstroke * /*gps*/,
|
||||
void *thunk)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
iterData *iter = (iterData *)thunk;
|
||||
bGPdata *gpd = (bGPdata *)iter->ob->data;
|
||||
|
||||
const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0;
|
||||
const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D);
|
||||
|
||||
float object_scale = mat4_to_scale(iter->ob->object_to_world().ptr());
|
||||
/* Negate thickness sign to tag that strokes are in screen space.
|
||||
* Convert to world units (by default, 1 meter = 2000 pixels). */
|
||||
float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f);
|
||||
|
||||
blender::gpu::VertBuf *position_tx = DRW_cache_gpencil_position_buffer_get(iter->ob, iter->cfra);
|
||||
blender::gpu::VertBuf *color_tx = DRW_cache_gpencil_color_buffer_get(iter->ob, iter->cfra);
|
||||
|
||||
DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", is_stroke_order_3d);
|
||||
DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", object_scale);
|
||||
DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", float(gpl->line_change));
|
||||
DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale);
|
||||
DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane);
|
||||
DRW_shgroup_buffer_texture(grp, "gp_pos_tx", position_tx);
|
||||
DRW_shgroup_buffer_texture(grp, "gp_col_tx", color_tx);
|
||||
}
|
||||
|
||||
static void gpencil_stroke_cache_populate(bGPDlayer * /*gpl*/,
|
||||
bGPDframe * /*gpf*/,
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
iterData *iter = (iterData *)thunk;
|
||||
|
||||
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1);
|
||||
|
||||
bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
|
||||
bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
|
||||
/* TODO: What about simplify Fill? */
|
||||
bool show_fill = (gps->tot_triangles > 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0;
|
||||
|
||||
if (hide_material) {
|
||||
return;
|
||||
}
|
||||
|
||||
blender::gpu::Batch *geom = DRW_cache_gpencil_get(iter->ob, iter->cfra);
|
||||
|
||||
if (show_fill) {
|
||||
int vfirst = gps->runtime.fill_start * 3;
|
||||
int vcount = gps->tot_triangles * 3;
|
||||
DRW_shgroup_call_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount);
|
||||
}
|
||||
|
||||
if (show_stroke) {
|
||||
int vfirst = gps->runtime.stroke_start * 3;
|
||||
bool is_cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2);
|
||||
int vcount = (gps->totpoints + int(is_cyclic)) * 2 * 3;
|
||||
DRW_shgroup_call_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount);
|
||||
}
|
||||
}
|
||||
|
||||
static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob)
|
||||
{
|
||||
/* No outlines in edit mode. */
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
if (gpd && GPENCIL_ANY_MODE(gpd)) {
|
||||
return;
|
||||
}
|
||||
|
||||
iterData iter{};
|
||||
iter.ob = ob;
|
||||
iter.stroke_grp = pd->outlines_gpencil_grp;
|
||||
iter.cfra = pd->cfra;
|
||||
|
||||
if (gpd->draw_mode == GP_DRAWMODE_2D) {
|
||||
gpencil_depth_plane(ob, iter.plane);
|
||||
}
|
||||
|
||||
BKE_gpencil_visible_stroke_advanced_iter(nullptr,
|
||||
ob,
|
||||
gpencil_layer_cache_populate,
|
||||
gpencil_stroke_cache_populate,
|
||||
&iter,
|
||||
false,
|
||||
pd->cfra);
|
||||
}
|
||||
|
||||
static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene, Object *ob)
|
||||
{
|
||||
using namespace blender;
|
||||
@@ -413,11 +322,6 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
|
||||
return;
|
||||
}
|
||||
|
||||
if (ob->type == OB_GPENCIL_LEGACY) {
|
||||
OVERLAY_outline_gpencil(pd, ob);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ob->type == OB_GREASE_PENCIL) {
|
||||
OVERLAY_outline_grease_pencil(pd, draw_ctx->scene, ob);
|
||||
return;
|
||||
|
||||
@@ -608,7 +608,6 @@ void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata);
|
||||
|
||||
void OVERLAY_edit_gpencil_legacy_cache_init(OVERLAY_Data *vedata);
|
||||
void OVERLAY_gpencil_legacy_cache_init(OVERLAY_Data *vedata);
|
||||
void OVERLAY_gpencil_legacy_cache_populate(OVERLAY_Data *vedata, Object *ob);
|
||||
void OVERLAY_gpencil_legacy_draw(OVERLAY_Data *vedata);
|
||||
void OVERLAY_edit_gpencil_legacy_draw(OVERLAY_Data *vedata);
|
||||
|
||||
|
||||
@@ -890,8 +890,6 @@ blender::gpu::Batch *DRW_cache_object_face_wireframe_get(const Scene *scene, Obj
|
||||
return DRW_pointcloud_batch_cache_get_dots(ob);
|
||||
case OB_VOLUME:
|
||||
return DRW_cache_volume_face_wireframe_get(ob);
|
||||
case OB_GPENCIL_LEGACY:
|
||||
return DRW_cache_gpencil_face_wireframe_get(ob);
|
||||
case OB_GREASE_PENCIL:
|
||||
return DRW_cache_grease_pencil_face_wireframe_get(scene, ob);
|
||||
default:
|
||||
@@ -961,8 +959,6 @@ int DRW_cache_object_material_count_get(const Object *ob)
|
||||
return DRW_pointcloud_material_count_get(static_cast<const PointCloud *>(ob->data));
|
||||
case OB_VOLUME:
|
||||
return DRW_volume_material_count_get(static_cast<const Volume *>(ob->data));
|
||||
case OB_GPENCIL_LEGACY:
|
||||
return DRW_gpencil_material_count_get(static_cast<const bGPdata *>(ob->data));
|
||||
default:
|
||||
BLI_assert(0);
|
||||
return 0;
|
||||
|
||||
@@ -258,23 +258,6 @@ DRWVolumeGrid *DRW_volume_batch_cache_get_grid(Volume *volume,
|
||||
blender::gpu::Batch *DRW_cache_volume_face_wireframe_get(Object *ob);
|
||||
blender::gpu::Batch *DRW_cache_volume_selection_surface_get(Object *ob);
|
||||
|
||||
/* GPencil (legacy) */
|
||||
|
||||
blender::gpu::Batch *DRW_cache_gpencil_get(Object *ob, int cfra);
|
||||
gpu::VertBuf *DRW_cache_gpencil_position_buffer_get(Object *ob, int cfra);
|
||||
gpu::VertBuf *DRW_cache_gpencil_color_buffer_get(Object *ob, int cfra);
|
||||
blender::gpu::Batch *DRW_cache_gpencil_edit_lines_get(Object *ob, int cfra);
|
||||
blender::gpu::Batch *DRW_cache_gpencil_edit_points_get(Object *ob, int cfra);
|
||||
blender::gpu::Batch *DRW_cache_gpencil_edit_curve_handles_get(Object *ob, int cfra);
|
||||
blender::gpu::Batch *DRW_cache_gpencil_edit_curve_points_get(Object *ob, int cfra);
|
||||
blender::gpu::Batch *DRW_cache_gpencil_sbuffer_get(Object *ob, bool show_fill);
|
||||
gpu::VertBuf *DRW_cache_gpencil_sbuffer_position_buffer_get(Object *ob, bool show_fill);
|
||||
gpu::VertBuf *DRW_cache_gpencil_sbuffer_color_buffer_get(Object *ob, bool show_fill);
|
||||
int DRW_gpencil_material_count_get(const bGPdata *gpd);
|
||||
|
||||
blender::gpu::Batch *DRW_cache_gpencil_face_wireframe_get(Object *ob);
|
||||
|
||||
bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob);
|
||||
/**
|
||||
* Sbuffer batches are temporary. We need to clear it after drawing.
|
||||
*/
|
||||
|
||||
@@ -66,57 +66,10 @@ struct GpencilBatchCache {
|
||||
|
||||
namespace blender::draw {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Types
|
||||
* \{ */
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Utilities
|
||||
* \{ */
|
||||
|
||||
static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
if (cache == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cfra != cache->cache_frame) {
|
||||
valid = false;
|
||||
}
|
||||
else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
|
||||
valid = false;
|
||||
}
|
||||
else if (cache->is_dirty) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
|
||||
GpencilBatchCache *cache = gpd->runtime.gpencil_cache;
|
||||
|
||||
if (!cache) {
|
||||
cache = gpd->runtime.gpencil_cache = (GpencilBatchCache *)MEM_callocN(sizeof(*cache),
|
||||
__func__);
|
||||
}
|
||||
else {
|
||||
memset(cache, 0, sizeof(*cache));
|
||||
}
|
||||
|
||||
cache->is_dirty = true;
|
||||
cache->cache_frame = cfra;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
|
||||
{
|
||||
if (!cache) {
|
||||
@@ -140,19 +93,6 @@ static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
|
||||
cache->is_dirty = true;
|
||||
}
|
||||
|
||||
static GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
|
||||
GpencilBatchCache *cache = gpd->runtime.gpencil_cache;
|
||||
if (!gpencil_batch_cache_valid(cache, gpd, cfra)) {
|
||||
gpencil_batch_cache_clear(cache);
|
||||
return gpencil_batch_cache_init(ob, cfra);
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -173,539 +113,10 @@ void DRW_gpencil_batch_cache_free(bGPdata *gpd)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vertex Formats
|
||||
* \{ */
|
||||
|
||||
/* MUST match the format below. */
|
||||
struct gpStrokeVert {
|
||||
/** Position and thickness packed in the same attribute. */
|
||||
float pos[3], thickness;
|
||||
/** Material Index, Stroke Index, Point Index, Packed aspect + hardness + rotation. */
|
||||
int32_t mat, stroke_id, point_id, packed_asp_hard_rot;
|
||||
/** UV and strength packed in the same attribute. */
|
||||
float uv_fill[2], u_stroke, strength;
|
||||
};
|
||||
|
||||
static GPUVertFormat *gpencil_stroke_format()
|
||||
{
|
||||
static GPUVertFormat format = {0};
|
||||
if (format.attr_len == 0) {
|
||||
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
GPU_vertformat_attr_add(&format, "ma", GPU_COMP_I32, 4, GPU_FETCH_INT);
|
||||
GPU_vertformat_attr_add(&format, "uv", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
}
|
||||
return &format;
|
||||
}
|
||||
|
||||
/* MUST match the format below. */
|
||||
struct gpEditVert {
|
||||
uint vflag;
|
||||
float weight;
|
||||
};
|
||||
|
||||
static GPUVertFormat *gpencil_edit_stroke_format()
|
||||
{
|
||||
static GPUVertFormat format = {0};
|
||||
if (format.attr_len == 0) {
|
||||
GPU_vertformat_attr_add(&format, "vflag", GPU_COMP_U32, 1, GPU_FETCH_INT);
|
||||
GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
||||
}
|
||||
return &format;
|
||||
}
|
||||
|
||||
/* MUST match the format below. */
|
||||
struct gpEditCurveVert {
|
||||
float pos[3];
|
||||
uint32_t data;
|
||||
};
|
||||
|
||||
static GPUVertFormat *gpencil_edit_curve_format()
|
||||
{
|
||||
static GPUVertFormat format = {0};
|
||||
if (format.attr_len == 0) {
|
||||
/* initialize vertex formats */
|
||||
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
GPU_vertformat_attr_add(&format, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
|
||||
}
|
||||
return &format;
|
||||
}
|
||||
|
||||
/* MUST match the format below. */
|
||||
struct gpColorVert {
|
||||
float vcol[4]; /* Vertex color */
|
||||
float fcol[4]; /* Fill color */
|
||||
};
|
||||
|
||||
static GPUVertFormat *gpencil_color_format()
|
||||
{
|
||||
static GPUVertFormat format = {0};
|
||||
if (format.attr_len == 0) {
|
||||
GPU_vertformat_attr_add(&format, "col", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
GPU_vertformat_attr_add(&format, "fcol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
}
|
||||
return &format;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vertex Buffers
|
||||
* \{ */
|
||||
|
||||
struct gpIterData {
|
||||
bGPdata *gpd;
|
||||
gpStrokeVert *verts;
|
||||
gpColorVert *cols;
|
||||
GPUIndexBufBuilder ibo;
|
||||
int vert_len;
|
||||
int tri_len;
|
||||
int curve_len;
|
||||
};
|
||||
|
||||
static gpu::VertBuf *gpencil_dummy_buffer_get()
|
||||
{
|
||||
blender::gpu::Batch *batch = DRW_gpencil_dummy_buffer_get();
|
||||
return batch->verts[0];
|
||||
}
|
||||
|
||||
static int gpencil_stroke_is_cyclic(const bGPDstroke *gps)
|
||||
{
|
||||
return ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2);
|
||||
}
|
||||
|
||||
BLI_INLINE int32_t pack_rotation_aspect_hardness(float rot, float asp, float hard)
|
||||
{
|
||||
int32_t packed = 0;
|
||||
/* Aspect uses 9 bits */
|
||||
float asp_normalized = (asp > 1.0f) ? (1.0f / asp) : asp;
|
||||
packed |= int32_t(unit_float_to_uchar_clamp(asp_normalized));
|
||||
/* Store if inversed in the 9th bit. */
|
||||
if (asp > 1.0f) {
|
||||
packed |= 1 << 8;
|
||||
}
|
||||
/* Rotation uses 9 bits */
|
||||
/* Rotation are in [-90..90 degree] range, so we can encode the sign of the angle + the cosine
|
||||
* because the cosine will always be positive. */
|
||||
packed |= int32_t(unit_float_to_uchar_clamp(cosf(rot))) << 9;
|
||||
/* Store sine sign in 9th bit. */
|
||||
if (rot < 0.0f) {
|
||||
packed |= 1 << 17;
|
||||
}
|
||||
/* Hardness uses 8 bits */
|
||||
packed |= int32_t(unit_float_to_uchar_clamp(hard)) << 18;
|
||||
return packed;
|
||||
}
|
||||
|
||||
static void gpencil_buffer_add_point(GPUIndexBufBuilder *ibo,
|
||||
gpStrokeVert *verts,
|
||||
gpColorVert *cols,
|
||||
const bGPDstroke *gps,
|
||||
const bGPDspoint *pt,
|
||||
int v,
|
||||
bool is_endpoint)
|
||||
{
|
||||
/* NOTE: we use the sign of strength and thickness to pass cap flag. */
|
||||
const bool round_cap0 = (gps->caps[0] == GP_STROKE_CAP_ROUND);
|
||||
const bool round_cap1 = (gps->caps[1] == GP_STROKE_CAP_ROUND);
|
||||
gpStrokeVert *vert = &verts[v];
|
||||
gpColorVert *col = &cols[v];
|
||||
copy_v3_v3(vert->pos, &pt->x);
|
||||
copy_v2_v2(vert->uv_fill, pt->uv_fill);
|
||||
copy_v4_v4(col->vcol, pt->vert_color);
|
||||
copy_v4_v4(col->fcol, gps->vert_color_fill);
|
||||
|
||||
/* Encode fill opacity defined by opacity modifier in vertex color alpha. If
|
||||
* no opacity modifier, the value will be always 1.0f. The opacity factor can be any
|
||||
* value between 0.0f and 2.0f */
|
||||
col->fcol[3] = (int(col->fcol[3] * 10000.0f) * 10.0f) + gps->fill_opacity_fac;
|
||||
|
||||
vert->strength = (round_cap0) ? pt->strength : -pt->strength;
|
||||
vert->u_stroke = pt->uv_fac;
|
||||
vert->stroke_id = gps->runtime.vertex_start;
|
||||
vert->point_id = v;
|
||||
vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0f : -1.0f);
|
||||
/* Tag endpoint material to -1 so they get discarded by vertex shader. */
|
||||
vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GPENCIL_MATERIAL_BUFFER_LEN);
|
||||
|
||||
float aspect_ratio = gps->aspect_ratio[0] / max_ff(gps->aspect_ratio[1], 1e-8);
|
||||
|
||||
vert->packed_asp_hard_rot = pack_rotation_aspect_hardness(
|
||||
pt->uv_rot, aspect_ratio, gps->hardness);
|
||||
|
||||
if (!is_endpoint) {
|
||||
/* Issue a Quad per point. */
|
||||
/* The attribute loading uses a different shader and will undo this bit packing. */
|
||||
int v_mat = (v << GP_VERTEX_ID_SHIFT) | GP_IS_STROKE_VERTEX_BIT;
|
||||
GPU_indexbuf_add_tri_verts(ibo, v_mat + 0, v_mat + 1, v_mat + 2);
|
||||
GPU_indexbuf_add_tri_verts(ibo, v_mat + 2, v_mat + 1, v_mat + 3);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpencil_buffer_add_stroke(GPUIndexBufBuilder *ibo,
|
||||
gpStrokeVert *verts,
|
||||
gpColorVert *cols,
|
||||
const bGPDstroke *gps)
|
||||
{
|
||||
const bGPDspoint *pts = gps->points;
|
||||
int pts_len = gps->totpoints;
|
||||
bool is_cyclic = gpencil_stroke_is_cyclic(gps);
|
||||
int v = gps->runtime.vertex_start;
|
||||
|
||||
/* First point for adjacency (not drawn). */
|
||||
int adj_idx = (is_cyclic) ? (pts_len - 1) : min_ii(pts_len - 1, 1);
|
||||
gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[adj_idx], v++, true);
|
||||
|
||||
for (int i = 0; i < pts_len; i++) {
|
||||
gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[i], v++, false);
|
||||
}
|
||||
/* Draw line to first point to complete the loop for cyclic strokes. */
|
||||
if (is_cyclic) {
|
||||
gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[0], v, false);
|
||||
/* UV factor needs to be adjusted for the last point to not be equal to the UV factor of the
|
||||
* first point. It should be the factor of the last point plus the distance from the last point
|
||||
* to the first.
|
||||
*/
|
||||
gpStrokeVert *vert = &verts[v];
|
||||
vert->u_stroke = verts[v - 1].u_stroke + len_v3v3(&pts[pts_len - 1].x, &pts[0].x);
|
||||
v++;
|
||||
}
|
||||
/* Last adjacency point (not drawn). */
|
||||
adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2);
|
||||
gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[adj_idx], v++, true);
|
||||
}
|
||||
|
||||
static void gpencil_buffer_add_fill(GPUIndexBufBuilder *ibo, const bGPDstroke *gps)
|
||||
{
|
||||
int tri_len = gps->tot_triangles;
|
||||
int v = gps->runtime.vertex_start + 1;
|
||||
for (int i = 0; i < tri_len; i++) {
|
||||
uint *tri = gps->triangles[i].verts;
|
||||
/* The attribute loading uses a different shader and will undo this bit packing. */
|
||||
GPU_indexbuf_add_tri_verts(ibo,
|
||||
(v + tri[0]) << GP_VERTEX_ID_SHIFT,
|
||||
(v + tri[1]) << GP_VERTEX_ID_SHIFT,
|
||||
(v + tri[2]) << GP_VERTEX_ID_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpencil_stroke_iter_cb(bGPDlayer * /*gpl*/,
|
||||
bGPDframe * /*gpf*/,
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
gpIterData *iter = (gpIterData *)thunk;
|
||||
if (gps->tot_triangles > 0) {
|
||||
gpencil_buffer_add_fill(&iter->ibo, gps);
|
||||
}
|
||||
gpencil_buffer_add_stroke(&iter->ibo, iter->verts, iter->cols, gps);
|
||||
}
|
||||
|
||||
static void gpencil_object_verts_count_cb(bGPDlayer * /*gpl*/,
|
||||
bGPDframe * /*gpf*/,
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
gpIterData *iter = (gpIterData *)thunk;
|
||||
int stroke_vert_len = gps->totpoints + gpencil_stroke_is_cyclic(gps);
|
||||
gps->runtime.vertex_start = iter->vert_len;
|
||||
/* Add additional padding at the start and end. */
|
||||
iter->vert_len += 1 + stroke_vert_len + 1;
|
||||
/* Store first index offset. */
|
||||
gps->runtime.fill_start = iter->tri_len;
|
||||
iter->tri_len += gps->tot_triangles;
|
||||
gps->runtime.stroke_start = iter->tri_len;
|
||||
iter->tri_len += stroke_vert_len * 2;
|
||||
}
|
||||
|
||||
static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
|
||||
if (cache->vbo == nullptr) {
|
||||
/* Should be discarded together. */
|
||||
BLI_assert(cache->vbo == nullptr && cache->ibo == nullptr);
|
||||
BLI_assert(cache->geom_batch == nullptr);
|
||||
/* TODO/PERF: Could be changed to only do it if needed.
|
||||
* For now it's simpler to assume we always need it
|
||||
* since multiple viewport could or could not need it.
|
||||
* Ideally we should have a dedicated onion skin geom batch. */
|
||||
/* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */
|
||||
bool do_onion = true;
|
||||
|
||||
/* First count how many vertices and triangles are needed for the whole object. */
|
||||
gpIterData iter = {};
|
||||
iter.gpd = gpd;
|
||||
iter.verts = nullptr;
|
||||
iter.ibo = {0};
|
||||
iter.vert_len = 0;
|
||||
iter.tri_len = 0;
|
||||
iter.curve_len = 0;
|
||||
BKE_gpencil_visible_stroke_advanced_iter(
|
||||
nullptr, ob, nullptr, gpencil_object_verts_count_cb, &iter, do_onion, cfra);
|
||||
|
||||
GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY;
|
||||
/* Create VBOs. */
|
||||
GPUVertFormat *format = gpencil_stroke_format();
|
||||
GPUVertFormat *format_col = gpencil_color_format();
|
||||
cache->vbo = GPU_vertbuf_create_with_format_ex(*format, vbo_flag);
|
||||
cache->vbo_col = GPU_vertbuf_create_with_format_ex(*format_col, vbo_flag);
|
||||
/* Add extra space at the end of the buffer because of quad load. */
|
||||
GPU_vertbuf_data_alloc(*cache->vbo, iter.vert_len + 2);
|
||||
GPU_vertbuf_data_alloc(*cache->vbo_col, iter.vert_len + 2);
|
||||
iter.verts = cache->vbo->data<gpStrokeVert>().data();
|
||||
iter.cols = cache->vbo_col->data<gpColorVert>().data();
|
||||
/* Create IBO. */
|
||||
GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, 0xFFFFFFFFu);
|
||||
|
||||
/* Fill buffers with data. */
|
||||
BKE_gpencil_visible_stroke_advanced_iter(
|
||||
nullptr, ob, nullptr, gpencil_stroke_iter_cb, &iter, do_onion, cfra);
|
||||
|
||||
/* Mark last 2 verts as invalid. */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
iter.verts[iter.vert_len + i].mat = -1;
|
||||
}
|
||||
/* Also mark first vert as invalid. */
|
||||
iter.verts[0].mat = -1;
|
||||
|
||||
/* Finish the IBO. */
|
||||
cache->ibo = GPU_indexbuf_build(&iter.ibo);
|
||||
/* Create the batches */
|
||||
cache->geom_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo);
|
||||
/* Allow creation of buffer texture. */
|
||||
GPU_vertbuf_use(cache->vbo);
|
||||
GPU_vertbuf_use(cache->vbo_col);
|
||||
|
||||
gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
|
||||
cache->is_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
blender::gpu::Batch *DRW_cache_gpencil_get(Object *ob, int cfra)
|
||||
{
|
||||
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
|
||||
gpencil_batches_ensure(ob, cache, cfra);
|
||||
|
||||
return cache->geom_batch;
|
||||
}
|
||||
|
||||
gpu::VertBuf *DRW_cache_gpencil_position_buffer_get(Object *ob, int cfra)
|
||||
{
|
||||
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
|
||||
gpencil_batches_ensure(ob, cache, cfra);
|
||||
|
||||
return cache->vbo;
|
||||
}
|
||||
|
||||
gpu::VertBuf *DRW_cache_gpencil_color_buffer_get(Object *ob, int cfra)
|
||||
{
|
||||
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
|
||||
gpencil_batches_ensure(ob, cache, cfra);
|
||||
|
||||
return cache->vbo_col;
|
||||
}
|
||||
|
||||
static void gpencil_lines_indices_cb(bGPDlayer * /*gpl*/,
|
||||
bGPDframe * /*gpf*/,
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
gpIterData *iter = (gpIterData *)thunk;
|
||||
int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps);
|
||||
|
||||
int start = gps->runtime.vertex_start + 1;
|
||||
int end = start + pts_len;
|
||||
for (int i = start; i < end; i++) {
|
||||
GPU_indexbuf_add_generic_vert(&iter->ibo, i);
|
||||
}
|
||||
GPU_indexbuf_add_primitive_restart(&iter->ibo);
|
||||
}
|
||||
|
||||
blender::gpu::Batch *DRW_cache_gpencil_face_wireframe_get(Object *ob)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
int cfra = DEG_get_ctime(draw_ctx->depsgraph);
|
||||
|
||||
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
|
||||
gpencil_batches_ensure(ob, cache, cfra);
|
||||
|
||||
if (cache->lines_batch == nullptr) {
|
||||
gpu::VertBuf *vbo = cache->vbo;
|
||||
|
||||
gpIterData iter = {};
|
||||
iter.gpd = (bGPdata *)ob->data;
|
||||
iter.ibo = {0};
|
||||
|
||||
uint vert_len = GPU_vertbuf_get_vertex_len(vbo);
|
||||
GPU_indexbuf_init_ex(&iter.ibo, GPU_PRIM_LINE_STRIP, vert_len, vert_len);
|
||||
|
||||
/* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */
|
||||
bool do_onion = true;
|
||||
BKE_gpencil_visible_stroke_advanced_iter(
|
||||
nullptr, ob, nullptr, gpencil_lines_indices_cb, &iter, do_onion, cfra);
|
||||
|
||||
blender::gpu::IndexBuf *ibo = GPU_indexbuf_build(&iter.ibo);
|
||||
|
||||
cache->lines_batch = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, ibo, GPU_BATCH_OWNS_INDEX);
|
||||
}
|
||||
return cache->lines_batch;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Sbuffer stroke batches.
|
||||
* \{ */
|
||||
|
||||
bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
Brush *brush = gpd->runtime.sbuffer_brush;
|
||||
/* Convert the sbuffer to a bGPDstroke. */
|
||||
if (gpd->runtime.sbuffer_gps == nullptr) {
|
||||
bGPDstroke *gps = (bGPDstroke *)MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer");
|
||||
gps->totpoints = gpd->runtime.sbuffer_used;
|
||||
gps->mat_nr = max_ii(0, gpd->runtime.matid - 1);
|
||||
gps->flag = gpd->runtime.sbuffer_sflag;
|
||||
gps->thickness = brush->size;
|
||||
gps->hardness = brush->gpencil_settings->hardness;
|
||||
copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
|
||||
|
||||
gps->fill_opacity_fac = gpd->runtime.fill_opacity_fac;
|
||||
|
||||
gps->tot_triangles = max_ii(0, gpd->runtime.sbuffer_used - 2);
|
||||
gps->caps[0] = gps->caps[1] = GP_STROKE_CAP_ROUND;
|
||||
gps->runtime.vertex_start = 0;
|
||||
gps->runtime.fill_start = 0;
|
||||
gps->runtime.stroke_start = 0;
|
||||
copy_v4_v4(gps->vert_color_fill, gpd->runtime.vert_color_fill);
|
||||
/* Caps. */
|
||||
gps->caps[0] = gps->caps[1] = short(brush->gpencil_settings->caps_type);
|
||||
|
||||
gpd->runtime.sbuffer_gps = gps;
|
||||
}
|
||||
return gpd->runtime.sbuffer_gps;
|
||||
}
|
||||
|
||||
static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_fill)
|
||||
{
|
||||
tGPspoint *tpoints = (tGPspoint *)gpd->runtime.sbuffer;
|
||||
bGPDstroke *gps = gpd->runtime.sbuffer_gps;
|
||||
int vert_len = gpd->runtime.sbuffer_used;
|
||||
|
||||
/* DRW_cache_gpencil_sbuffer_stroke_data_get need to have been called previously. */
|
||||
BLI_assert(gps != nullptr);
|
||||
|
||||
if (gpd->runtime.sbuffer_batch == nullptr) {
|
||||
gps->points = (bGPDspoint *)MEM_mallocN(vert_len * sizeof(*gps->points), __func__);
|
||||
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
Scene *scene = draw_ctx->scene;
|
||||
ARegion *region = draw_ctx->region;
|
||||
Object *ob = draw_ctx->obact;
|
||||
|
||||
BLI_assert(ob && (ob->type == OB_GPENCIL_LEGACY));
|
||||
|
||||
/* Get origin to reproject points. */
|
||||
float origin[3];
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
ED_gpencil_drawing_reference_get(scene, ob, ts->gpencil_v3d_align, origin);
|
||||
|
||||
for (int i = 0; i < vert_len; i++) {
|
||||
ED_gpencil_tpoint_to_point(region, origin, &tpoints[i], &gps->points[i]);
|
||||
mul_m4_v3(ob->world_to_object().ptr(), &gps->points[i].x);
|
||||
bGPDspoint *pt = &gps->points[i];
|
||||
copy_v4_v4(pt->vert_color, tpoints[i].vert_color);
|
||||
}
|
||||
/* Calc uv data along the stroke. */
|
||||
BKE_gpencil_stroke_uv_update(gps);
|
||||
|
||||
int tri_len = gps->tot_triangles + (gps->totpoints + gpencil_stroke_is_cyclic(gps)) * 2;
|
||||
/* Create IBO. */
|
||||
GPUIndexBufBuilder ibo_builder;
|
||||
GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, tri_len, 0xFFFFFFFFu);
|
||||
/* Create VBO. */
|
||||
GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY;
|
||||
GPUVertFormat *format = gpencil_stroke_format();
|
||||
GPUVertFormat *format_color = gpencil_color_format();
|
||||
gpu::VertBuf *vbo = GPU_vertbuf_create_with_format_ex(*format, vbo_flag);
|
||||
gpu::VertBuf *vbo_col = GPU_vertbuf_create_with_format_ex(*format_color, vbo_flag);
|
||||
/* Add extra space at the start and end the buffer because of quad load and cyclic. */
|
||||
GPU_vertbuf_data_alloc(*vbo, 1 + vert_len + 1 + 2);
|
||||
GPU_vertbuf_data_alloc(*vbo_col, 1 + vert_len + 1 + 2);
|
||||
gpStrokeVert *verts = vbo->data<gpStrokeVert>().data();
|
||||
gpColorVert *cols = vbo_col->data<gpColorVert>().data();
|
||||
|
||||
/* Create fill indices. */
|
||||
if (do_fill && gps->tot_triangles > 0) {
|
||||
float(*tpoints2d)[2] = (float(*)[2])MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__);
|
||||
/* Triangulate in 2D. */
|
||||
for (int i = 0; i < vert_len; i++) {
|
||||
copy_v2_v2(tpoints2d[i], tpoints[i].m_xy);
|
||||
}
|
||||
/* Compute directly inside the IBO data buffer. */
|
||||
/* OPTI: This is a bottleneck if the stroke is very long. */
|
||||
BLI_polyfill_calc(tpoints2d, uint(vert_len), 0, (uint(*)[3])ibo_builder.data);
|
||||
/* Add stroke start offset and shift. */
|
||||
for (int i = 0; i < gps->tot_triangles * 3; i++) {
|
||||
ibo_builder.data[i] = (ibo_builder.data[i] + 1) << GP_VERTEX_ID_SHIFT;
|
||||
}
|
||||
/* HACK since we didn't use the builder API to avoid another malloc and copy,
|
||||
* we need to set the number of indices manually. */
|
||||
ibo_builder.index_len = gps->tot_triangles * 3;
|
||||
ibo_builder.index_min = 0;
|
||||
/* For this case, do not allow index compaction to avoid yet another preprocessing step. */
|
||||
ibo_builder.index_max = 0xFFFFFFFFu - 1u;
|
||||
|
||||
gps->runtime.stroke_start = gps->tot_triangles;
|
||||
|
||||
MEM_freeN(tpoints2d);
|
||||
}
|
||||
|
||||
/* Fill buffers with data. */
|
||||
gpencil_buffer_add_stroke(&ibo_builder, verts, cols, gps);
|
||||
|
||||
blender::gpu::Batch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS,
|
||||
gpencil_dummy_buffer_get(),
|
||||
GPU_indexbuf_build(&ibo_builder),
|
||||
GPU_BATCH_OWNS_INDEX);
|
||||
|
||||
gpd->runtime.sbuffer_position_buf = vbo;
|
||||
gpd->runtime.sbuffer_color_buf = vbo_col;
|
||||
gpd->runtime.sbuffer_batch = batch;
|
||||
|
||||
MEM_freeN(gps->points);
|
||||
}
|
||||
}
|
||||
|
||||
blender::gpu::Batch *DRW_cache_gpencil_sbuffer_get(Object *ob, bool show_fill)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
/* Fill batch also need stroke batch to be created (vbo is shared). */
|
||||
gpencil_sbuffer_stroke_ensure(gpd, show_fill);
|
||||
|
||||
return gpd->runtime.sbuffer_batch;
|
||||
}
|
||||
|
||||
gpu::VertBuf *DRW_cache_gpencil_sbuffer_position_buffer_get(Object *ob, bool show_fill)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
/* Fill batch also need stroke batch to be created (vbo is shared). */
|
||||
gpencil_sbuffer_stroke_ensure(gpd, show_fill);
|
||||
|
||||
return gpd->runtime.sbuffer_position_buf;
|
||||
}
|
||||
|
||||
gpu::VertBuf *DRW_cache_gpencil_sbuffer_color_buffer_get(Object *ob, bool show_fill)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
/* Fill batch also need stroke batch to be created (vbo is shared). */
|
||||
gpencil_sbuffer_stroke_ensure(gpd, show_fill);
|
||||
|
||||
return gpd->runtime.sbuffer_color_buf;
|
||||
}
|
||||
|
||||
void DRW_cache_gpencil_sbuffer_clear(Object *ob)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
@@ -717,285 +128,4 @@ void DRW_cache_gpencil_sbuffer_clear(Object *ob)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Edit GPencil Batches
|
||||
* \{ */
|
||||
|
||||
#define GP_EDIT_POINT_SELECTED (1 << 0)
|
||||
#define GP_EDIT_STROKE_SELECTED (1 << 1)
|
||||
#define GP_EDIT_MULTIFRAME (1 << 2)
|
||||
#define GP_EDIT_STROKE_START (1 << 3)
|
||||
#define GP_EDIT_STROKE_END (1 << 4)
|
||||
#define GP_EDIT_POINT_DIMMED (1 << 5)
|
||||
|
||||
struct gpEditIterData {
|
||||
gpEditVert *verts;
|
||||
int vgindex;
|
||||
};
|
||||
|
||||
struct gpEditCurveIterData {
|
||||
gpEditCurveVert *verts;
|
||||
int vgindex;
|
||||
};
|
||||
|
||||
static uint32_t gpencil_point_edit_flag(const bool layer_lock,
|
||||
const bGPDspoint *pt,
|
||||
int v,
|
||||
int v_len)
|
||||
{
|
||||
uint32_t sflag = 0;
|
||||
SET_FLAG_FROM_TEST(sflag, (!layer_lock) && pt->flag & GP_SPOINT_SELECT, GP_EDIT_POINT_SELECTED);
|
||||
SET_FLAG_FROM_TEST(sflag, v == 0, GP_EDIT_STROKE_START);
|
||||
SET_FLAG_FROM_TEST(sflag, v == (v_len - 1), GP_EDIT_STROKE_END);
|
||||
SET_FLAG_FROM_TEST(sflag, pt->runtime.pt_orig == nullptr, GP_EDIT_POINT_DIMMED);
|
||||
return sflag;
|
||||
}
|
||||
|
||||
static float gpencil_point_edit_weight(const MDeformVert *dvert, int v, int vgindex)
|
||||
{
|
||||
return (dvert && dvert[v].dw) ? BKE_defvert_find_weight(&dvert[v], vgindex) : -1.0f;
|
||||
}
|
||||
|
||||
static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl,
|
||||
bGPDframe *gpf,
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
gpEditIterData *iter = (gpEditIterData *)thunk;
|
||||
const int v_len = gps->totpoints;
|
||||
const int v = gps->runtime.vertex_start + 1;
|
||||
MDeformVert *dvert = ((iter->vgindex > -1) && gps->dvert) ? gps->dvert : nullptr;
|
||||
gpEditVert *vert_ptr = iter->verts + v;
|
||||
|
||||
const bool layer_lock = (gpl->flag & GP_LAYER_LOCKED);
|
||||
uint32_t sflag = 0;
|
||||
SET_FLAG_FROM_TEST(
|
||||
sflag, (!layer_lock) && gps->flag & GP_STROKE_SELECT, GP_EDIT_STROKE_SELECTED);
|
||||
SET_FLAG_FROM_TEST(sflag, gpf->runtime.onion_id != 0.0f, GP_EDIT_MULTIFRAME);
|
||||
|
||||
for (int i = 0; i < v_len; i++) {
|
||||
vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[i], i, v_len);
|
||||
vert_ptr->weight = gpencil_point_edit_weight(dvert, i, iter->vgindex);
|
||||
vert_ptr++;
|
||||
}
|
||||
|
||||
if (gpencil_stroke_is_cyclic(gps)) {
|
||||
/* Draw line to first point to complete the loop for cyclic strokes. */
|
||||
vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[0], 0, v_len);
|
||||
vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpencil_edit_curve_stroke_count_cb(bGPDlayer *gpl,
|
||||
bGPDframe * /*gpf*/,
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
if (gpl->flag & GP_LAYER_LOCKED) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpIterData *iter = (gpIterData *)thunk;
|
||||
|
||||
if (gps->editcurve == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store first index offset */
|
||||
gps->runtime.curve_start = iter->curve_len;
|
||||
iter->curve_len += gps->editcurve->tot_curve_points * 4;
|
||||
}
|
||||
|
||||
static uint32_t gpencil_beztriple_vflag_get(char flag,
|
||||
char col_id,
|
||||
bool handle_point,
|
||||
const bool handle_selected)
|
||||
{
|
||||
uint32_t vflag = 0;
|
||||
SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERT_SELECTED);
|
||||
SET_FLAG_FROM_TEST(vflag, handle_point, BEZIER_HANDLE);
|
||||
SET_FLAG_FROM_TEST(vflag, handle_selected, VFLAG_VERT_SELECTED_BEZT_HANDLE);
|
||||
vflag |= VFLAG_VERT_GPENCIL_BEZT_HANDLE;
|
||||
|
||||
/* Handle color id. */
|
||||
vflag |= col_id << COLOR_SHIFT;
|
||||
return vflag;
|
||||
}
|
||||
|
||||
static void gpencil_edit_curve_stroke_iter_cb(bGPDlayer *gpl,
|
||||
bGPDframe * /*gpf*/,
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
if (gpl->flag & GP_LAYER_LOCKED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gps->editcurve == nullptr) {
|
||||
return;
|
||||
}
|
||||
bGPDcurve *editcurve = gps->editcurve;
|
||||
gpEditCurveIterData *iter = (gpEditCurveIterData *)thunk;
|
||||
const int v = gps->runtime.curve_start;
|
||||
gpEditCurveVert *vert_ptr = iter->verts + v;
|
||||
/* Hide points when the curve is unselected. Passing the control point
|
||||
* as handle produces the point shader skip it if you are not in ALL mode. */
|
||||
const bool hide = !(editcurve->flag & GP_CURVE_SELECT);
|
||||
|
||||
for (int i = 0; i < editcurve->tot_curve_points; i++) {
|
||||
BezTriple *bezt = &editcurve->curve_points[i].bezt;
|
||||
const bool handle_selected = BEZT_ISSEL_ANY(bezt);
|
||||
const uint32_t vflag[3] = {
|
||||
gpencil_beztriple_vflag_get(bezt->f1, bezt->h1, true, handle_selected),
|
||||
gpencil_beztriple_vflag_get(bezt->f2, bezt->h1, hide, handle_selected),
|
||||
gpencil_beztriple_vflag_get(bezt->f3, bezt->h2, true, handle_selected),
|
||||
};
|
||||
|
||||
/* First segment. */
|
||||
mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[0]);
|
||||
vert_ptr->data = vflag[0];
|
||||
vert_ptr++;
|
||||
|
||||
mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[1]);
|
||||
vert_ptr->data = vflag[1];
|
||||
vert_ptr++;
|
||||
|
||||
/* Second segment. */
|
||||
mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[1]);
|
||||
vert_ptr->data = vflag[1];
|
||||
vert_ptr++;
|
||||
|
||||
mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[2]);
|
||||
vert_ptr->data = vflag[2];
|
||||
vert_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
|
||||
if (cache->edit_vbo == nullptr) {
|
||||
/* TODO/PERF: Could be changed to only do it if needed.
|
||||
* For now it's simpler to assume we always need it
|
||||
* since multiple viewport could or could not need it.
|
||||
* Ideally we should have a dedicated onion skin geom batch. */
|
||||
/* IMPORTANT: Keep in sync with gpencil_batches_ensure() */
|
||||
bool do_onion = true;
|
||||
|
||||
/* Vertex counting has already been done for cache->vbo. */
|
||||
BLI_assert(cache->vbo);
|
||||
int vert_len = GPU_vertbuf_get_vertex_len(cache->vbo);
|
||||
|
||||
gpEditIterData iter;
|
||||
iter.vgindex = gpd->vertex_group_active_index - 1;
|
||||
if (!BLI_findlink(&gpd->vertex_group_names, iter.vgindex)) {
|
||||
iter.vgindex = -1;
|
||||
}
|
||||
|
||||
/* Create VBO. */
|
||||
GPUVertFormat *format = gpencil_edit_stroke_format();
|
||||
cache->edit_vbo = GPU_vertbuf_create_with_format(*format);
|
||||
/* Add extra space at the end of the buffer because of quad load. */
|
||||
GPU_vertbuf_data_alloc(*cache->edit_vbo, vert_len);
|
||||
iter.verts = cache->edit_vbo->data<gpEditVert>().data();
|
||||
|
||||
/* Fill buffers with data. */
|
||||
BKE_gpencil_visible_stroke_advanced_iter(
|
||||
nullptr, ob, nullptr, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra);
|
||||
|
||||
/* Create the batches */
|
||||
cache->edit_points_batch = GPU_batch_create(GPU_PRIM_POINTS, cache->vbo, nullptr);
|
||||
GPU_batch_vertbuf_add(cache->edit_points_batch, cache->edit_vbo, false);
|
||||
|
||||
cache->edit_lines_batch = GPU_batch_create(GPU_PRIM_LINE_STRIP, cache->vbo, nullptr);
|
||||
GPU_batch_vertbuf_add(cache->edit_lines_batch, cache->edit_vbo, false);
|
||||
}
|
||||
|
||||
/* Curve Handles and Points for Editing. */
|
||||
if (cache->edit_curve_vbo == nullptr) {
|
||||
gpIterData iterdata = {};
|
||||
iterdata.gpd = gpd;
|
||||
iterdata.verts = nullptr;
|
||||
iterdata.ibo = {0};
|
||||
iterdata.vert_len = 0;
|
||||
iterdata.tri_len = 0;
|
||||
iterdata.curve_len = 0;
|
||||
|
||||
/* Create VBO. */
|
||||
GPUVertFormat *format = gpencil_edit_curve_format();
|
||||
cache->edit_curve_vbo = GPU_vertbuf_create_with_format(*format);
|
||||
|
||||
/* Count data. */
|
||||
BKE_gpencil_visible_stroke_advanced_iter(
|
||||
nullptr, ob, nullptr, gpencil_edit_curve_stroke_count_cb, &iterdata, false, cfra);
|
||||
|
||||
gpEditCurveIterData iter;
|
||||
int vert_len = iterdata.curve_len;
|
||||
if (vert_len > 0) {
|
||||
|
||||
GPU_vertbuf_data_alloc(*cache->edit_curve_vbo, vert_len);
|
||||
iter.verts = cache->edit_curve_vbo->data<gpEditCurveVert>().data();
|
||||
|
||||
/* Fill buffers with data. */
|
||||
BKE_gpencil_visible_stroke_advanced_iter(
|
||||
nullptr, ob, nullptr, gpencil_edit_curve_stroke_iter_cb, &iter, false, cfra);
|
||||
|
||||
cache->edit_curve_handles_batch = GPU_batch_create(
|
||||
GPU_PRIM_LINES, cache->edit_curve_vbo, nullptr);
|
||||
GPU_batch_vertbuf_add(cache->edit_curve_handles_batch, cache->edit_curve_vbo, false);
|
||||
|
||||
cache->edit_curve_points_batch = GPU_batch_create(
|
||||
GPU_PRIM_POINTS, cache->edit_curve_vbo, nullptr);
|
||||
GPU_batch_vertbuf_add(cache->edit_curve_points_batch, cache->edit_curve_vbo, false);
|
||||
}
|
||||
|
||||
gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
|
||||
cache->is_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
blender::gpu::Batch *DRW_cache_gpencil_edit_lines_get(Object *ob, int cfra)
|
||||
{
|
||||
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
|
||||
gpencil_batches_ensure(ob, cache, cfra);
|
||||
gpencil_edit_batches_ensure(ob, cache, cfra);
|
||||
|
||||
return cache->edit_lines_batch;
|
||||
}
|
||||
|
||||
blender::gpu::Batch *DRW_cache_gpencil_edit_points_get(Object *ob, int cfra)
|
||||
{
|
||||
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
|
||||
gpencil_batches_ensure(ob, cache, cfra);
|
||||
gpencil_edit_batches_ensure(ob, cache, cfra);
|
||||
|
||||
return cache->edit_points_batch;
|
||||
}
|
||||
|
||||
blender::gpu::Batch *DRW_cache_gpencil_edit_curve_handles_get(Object *ob, int cfra)
|
||||
{
|
||||
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
|
||||
gpencil_batches_ensure(ob, cache, cfra);
|
||||
gpencil_edit_batches_ensure(ob, cache, cfra);
|
||||
|
||||
return cache->edit_curve_handles_batch;
|
||||
}
|
||||
|
||||
blender::gpu::Batch *DRW_cache_gpencil_edit_curve_points_get(Object *ob, int cfra)
|
||||
{
|
||||
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
|
||||
gpencil_batches_ensure(ob, cache, cfra);
|
||||
gpencil_edit_batches_ensure(ob, cache, cfra);
|
||||
|
||||
return cache->edit_curve_points_batch;
|
||||
}
|
||||
|
||||
int DRW_gpencil_material_count_get(const bGPdata *gpd)
|
||||
{
|
||||
return max_ii(1, gpd->totcol);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::draw
|
||||
|
||||
@@ -35,7 +35,6 @@ set(SRC
|
||||
eyedroppers/eyedropper_datablock.cc
|
||||
eyedroppers/eyedropper_depth.cc
|
||||
eyedroppers/eyedropper_driver.cc
|
||||
eyedroppers/eyedropper_gpencil_color.cc
|
||||
eyedroppers/eyedropper_grease_pencil_color.cc
|
||||
eyedroppers/interface_eyedropper.cc
|
||||
interface.cc
|
||||
|
||||
@@ -1,374 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2009 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edinterface
|
||||
*
|
||||
* Eyedropper (RGB Color)
|
||||
*
|
||||
* Defines:
|
||||
* - #UI_OT_eyedropper_gpencil_color
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "DNA_gpencil_legacy_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_gpencil_legacy.h"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_paint.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
|
||||
#include "IMB_colormanagement.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
|
||||
#include "ED_screen.hh"
|
||||
#include "ED_undo.hh"
|
||||
|
||||
#include "DEG_depsgraph_build.hh"
|
||||
|
||||
#include "eyedropper_intern.hh"
|
||||
#include "interface_intern.hh"
|
||||
|
||||
enum eGP_EyeMode {
|
||||
GP_EYE_MATERIAL = 0,
|
||||
GP_EYE_PALETTE = 1,
|
||||
};
|
||||
|
||||
struct EyedropperGPencil {
|
||||
ColorManagedDisplay *display;
|
||||
/** color under cursor RGB */
|
||||
float color[3];
|
||||
/** Mode */
|
||||
eGP_EyeMode mode;
|
||||
};
|
||||
|
||||
/* Helper: Draw status message while the user is running the operator */
|
||||
static void eyedropper_gpencil_status_indicators(bContext *C)
|
||||
{
|
||||
char msg_str[UI_MAX_DRAW_STR];
|
||||
STRNCPY(msg_str, IFACE_("LMB: Stroke - Shift: Fill - Shift+Ctrl: Stroke + Fill"));
|
||||
|
||||
ED_workspace_status_text(C, msg_str);
|
||||
}
|
||||
|
||||
/* Initialize. */
|
||||
static bool eyedropper_gpencil_init(bContext *C, wmOperator *op)
|
||||
{
|
||||
EyedropperGPencil *eye = MEM_cnew<EyedropperGPencil>(__func__);
|
||||
|
||||
op->customdata = eye;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
const char *display_device;
|
||||
display_device = scene->display_settings.display_device;
|
||||
eye->display = IMB_colormanagement_display_get_named(display_device);
|
||||
|
||||
eye->mode = (eGP_EyeMode)RNA_enum_get(op->ptr, "mode");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Exit and free memory. */
|
||||
static void eyedropper_gpencil_exit(bContext *C, wmOperator *op)
|
||||
{
|
||||
/* Clear status message area. */
|
||||
ED_workspace_status_text(C, nullptr);
|
||||
|
||||
MEM_SAFE_FREE(op->customdata);
|
||||
}
|
||||
|
||||
static void eyedropper_add_material(bContext *C,
|
||||
const float col_conv[4],
|
||||
const bool only_stroke,
|
||||
const bool only_fill,
|
||||
const bool both)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
Material *ma = nullptr;
|
||||
|
||||
bool found = false;
|
||||
|
||||
/* Look for a similar material in grease pencil slots. */
|
||||
short *totcol = BKE_object_material_len_p(ob);
|
||||
for (short i = 0; i < *totcol; i++) {
|
||||
ma = BKE_object_material_get(ob, i + 1);
|
||||
if (ma == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MaterialGPencilStyle *gp_style = ma->gp_style;
|
||||
if (gp_style != nullptr) {
|
||||
/* Check stroke color. */
|
||||
bool found_stroke = compare_v3v3(gp_style->stroke_rgba, col_conv, 0.01f) &&
|
||||
(gp_style->flag & GP_MATERIAL_STROKE_SHOW);
|
||||
/* Check fill color. */
|
||||
bool found_fill = compare_v3v3(gp_style->fill_rgba, col_conv, 0.01f) &&
|
||||
(gp_style->flag & GP_MATERIAL_FILL_SHOW);
|
||||
|
||||
if ((only_stroke) && (found_stroke) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
|
||||
found = true;
|
||||
}
|
||||
else if ((only_fill) && (found_fill) && ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0)) {
|
||||
found = true;
|
||||
}
|
||||
else if ((both) && (found_stroke) && (found_fill)) {
|
||||
found = true;
|
||||
}
|
||||
|
||||
/* Found existing material. */
|
||||
if (found) {
|
||||
ob->actcol = i + 1;
|
||||
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, nullptr);
|
||||
WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If material was not found add a new material with stroke and/or fill color
|
||||
* depending of the secondary key (LMB: Stroke, Shift: Fill, Shift+Ctrl: Stroke/Fill)
|
||||
*/
|
||||
int idx;
|
||||
Material *ma_new = BKE_gpencil_object_material_new(bmain, ob, "Material", &idx);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, &ob->id);
|
||||
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, nullptr);
|
||||
DEG_relations_tag_update(bmain);
|
||||
|
||||
BLI_assert(ma_new != nullptr);
|
||||
|
||||
MaterialGPencilStyle *gp_style_new = ma_new->gp_style;
|
||||
BLI_assert(gp_style_new != nullptr);
|
||||
|
||||
/* Only create Stroke (default option). */
|
||||
if (only_stroke) {
|
||||
/* Stroke color. */
|
||||
gp_style_new->flag |= GP_MATERIAL_STROKE_SHOW;
|
||||
gp_style_new->flag &= ~GP_MATERIAL_FILL_SHOW;
|
||||
copy_v3_v3(gp_style_new->stroke_rgba, col_conv);
|
||||
zero_v4(gp_style_new->fill_rgba);
|
||||
}
|
||||
/* Fill Only. */
|
||||
else if (only_fill) {
|
||||
/* Fill color. */
|
||||
gp_style_new->flag &= ~GP_MATERIAL_STROKE_SHOW;
|
||||
gp_style_new->flag |= GP_MATERIAL_FILL_SHOW;
|
||||
zero_v4(gp_style_new->stroke_rgba);
|
||||
copy_v3_v3(gp_style_new->fill_rgba, col_conv);
|
||||
}
|
||||
/* Stroke and Fill. */
|
||||
else if (both) {
|
||||
gp_style_new->flag |= GP_MATERIAL_STROKE_SHOW | GP_MATERIAL_FILL_SHOW;
|
||||
copy_v3_v3(gp_style_new->stroke_rgba, col_conv);
|
||||
copy_v3_v3(gp_style_new->fill_rgba, col_conv);
|
||||
}
|
||||
/* Push undo for new created material. */
|
||||
ED_undo_push(C, "Add Grease Pencil Material");
|
||||
}
|
||||
|
||||
/* Create a new palette color and palette if needed. */
|
||||
static void eyedropper_add_palette_color(bContext *C, const float col_conv[4])
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
GpPaint *gp_paint = ts->gp_paint;
|
||||
GpVertexPaint *gp_vertexpaint = ts->gp_vertexpaint;
|
||||
Paint *paint = &gp_paint->paint;
|
||||
Paint *vertexpaint = &gp_vertexpaint->paint;
|
||||
|
||||
/* Check for Palette in Draw and Vertex Paint Mode. */
|
||||
if (paint->palette == nullptr) {
|
||||
Palette *palette = BKE_palette_add(bmain, "Grease Pencil");
|
||||
id_us_min(&palette->id);
|
||||
|
||||
BKE_paint_palette_set(paint, palette);
|
||||
|
||||
if (vertexpaint->palette == nullptr) {
|
||||
BKE_paint_palette_set(vertexpaint, palette);
|
||||
}
|
||||
}
|
||||
/* Check if the color exist already. */
|
||||
Palette *palette = paint->palette;
|
||||
LISTBASE_FOREACH (PaletteColor *, palcolor, &palette->colors) {
|
||||
if (compare_v3v3(palcolor->rgb, col_conv, 0.01f)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create Colors. */
|
||||
PaletteColor *palcol = BKE_palette_color_add(palette);
|
||||
if (palcol) {
|
||||
copy_v3_v3(palcol->rgb, col_conv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the material or the palette color. */
|
||||
static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, EyedropperGPencil *eye)
|
||||
{
|
||||
|
||||
const bool only_stroke = (event->modifier & (KM_CTRL | KM_SHIFT)) == 0;
|
||||
const bool only_fill = ((event->modifier & KM_CTRL) == 0 && (event->modifier & KM_SHIFT));
|
||||
const bool both = ((event->modifier & KM_CTRL) && (event->modifier & KM_SHIFT));
|
||||
|
||||
float col_conv[4];
|
||||
|
||||
/* Convert from linear rgb space to display space because palette colors are in display
|
||||
* space, and this conversion is needed to undo the conversion to linear performed by
|
||||
* eyedropper_color_sample_fl. */
|
||||
if ((eye->display) && (eye->mode == GP_EYE_PALETTE)) {
|
||||
copy_v3_v3(col_conv, eye->color);
|
||||
IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(col_conv, eye->color);
|
||||
}
|
||||
|
||||
/* Add material or Palette color. */
|
||||
if (eye->mode == GP_EYE_MATERIAL) {
|
||||
eyedropper_add_material(C, col_conv, only_stroke, only_fill, both);
|
||||
}
|
||||
else {
|
||||
eyedropper_add_palette_color(C, col_conv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sample the color below cursor. */
|
||||
static void eyedropper_gpencil_color_sample(bContext *C, EyedropperGPencil *eye, const int m_xy[2])
|
||||
{
|
||||
eyedropper_color_sample_fl(C, nullptr, m_xy, eye->color);
|
||||
}
|
||||
|
||||
/* Cancel operator. */
|
||||
static void eyedropper_gpencil_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
eyedropper_gpencil_exit(C, op);
|
||||
}
|
||||
|
||||
/* Main modal status check. */
|
||||
static int eyedropper_gpencil_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
EyedropperGPencil *eye = (EyedropperGPencil *)op->customdata;
|
||||
/* Handle modal keymap */
|
||||
switch (event->type) {
|
||||
case EVT_MODAL_MAP: {
|
||||
switch (event->val) {
|
||||
case EYE_MODAL_SAMPLE_BEGIN: {
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
case EYE_MODAL_CANCEL: {
|
||||
eyedropper_gpencil_cancel(C, op);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
case EYE_MODAL_SAMPLE_CONFIRM: {
|
||||
eyedropper_gpencil_color_sample(C, eye, event->xy);
|
||||
|
||||
/* Create material. */
|
||||
eyedropper_gpencil_color_set(C, event, eye);
|
||||
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, nullptr);
|
||||
|
||||
eyedropper_gpencil_exit(C, op);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MOUSEMOVE:
|
||||
case INBETWEEN_MOUSEMOVE: {
|
||||
eyedropper_gpencil_color_sample(C, eye, event->xy);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
/* Modal Operator init */
|
||||
static int eyedropper_gpencil_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
/* Init. */
|
||||
if (eyedropper_gpencil_init(C, op)) {
|
||||
/* Add modal temp handler. */
|
||||
WM_event_add_modal_handler(C, op);
|
||||
/* Status message. */
|
||||
eyedropper_gpencil_status_indicators(C);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* Repeat operator */
|
||||
static int eyedropper_gpencil_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
/* init */
|
||||
if (eyedropper_gpencil_init(C, op)) {
|
||||
|
||||
/* cleanup */
|
||||
eyedropper_gpencil_exit(C, op);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
static bool eyedropper_gpencil_poll(bContext *C)
|
||||
{
|
||||
/* Only valid if the current active object is grease pencil. */
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
if ((obact == nullptr) || (obact->type != OB_GPENCIL_LEGACY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Test we have a window below. */
|
||||
return (CTX_wm_window(C) != nullptr);
|
||||
}
|
||||
|
||||
void UI_OT_eyedropper_gpencil_color(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem items_mode[] = {
|
||||
{GP_EYE_MATERIAL, "MATERIAL", 0, "Material", ""},
|
||||
{GP_EYE_PALETTE, "PALETTE", 0, "Palette", ""},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Grease Pencil Eyedropper";
|
||||
ot->idname = "UI_OT_eyedropper_gpencil_color";
|
||||
ot->description = "Sample a color from the Blender Window and create Grease Pencil material";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = eyedropper_gpencil_invoke;
|
||||
ot->modal = eyedropper_gpencil_modal;
|
||||
ot->cancel = eyedropper_gpencil_cancel;
|
||||
ot->exec = eyedropper_gpencil_exec;
|
||||
ot->poll = eyedropper_gpencil_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
|
||||
|
||||
/* properties */
|
||||
ot->prop = RNA_def_enum(ot->srna, "mode", items_mode, GP_EYE_MATERIAL, "Mode", "");
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_gpencil_legacy.h"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_paint.hh"
|
||||
@@ -203,7 +203,7 @@ static void eyedropper_add_material(bContext *C,
|
||||
* depending of the secondary key (LMB: Stroke, Shift: Fill, Shift+Ctrl: Stroke/Fill)
|
||||
*/
|
||||
int idx;
|
||||
Material *ma_new = BKE_gpencil_object_material_new(bmain, ob, "Material", &idx);
|
||||
Material *ma_new = BKE_grease_pencil_object_material_new(bmain, ob, "Material", &idx);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, &ob->id);
|
||||
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, nullptr);
|
||||
DEG_relations_tag_update(bmain);
|
||||
@@ -295,9 +295,9 @@ static void eyedropper_set_brush_color(bContext *C, const float3 &col_conv)
|
||||
}
|
||||
|
||||
/* Set the material or the palette color. */
|
||||
static void eyedropper_gpencil_color_set(bContext *C,
|
||||
const wmEvent *event,
|
||||
EyedropperGreasePencil *eye)
|
||||
static void eyedropper_grease_pencil_color_set(bContext *C,
|
||||
const wmEvent *event,
|
||||
EyedropperGreasePencil *eye)
|
||||
{
|
||||
const bool is_ctrl = (event->modifier & KM_CTRL) != 0;
|
||||
const bool is_shift = (event->modifier & KM_SHIFT) != 0;
|
||||
@@ -386,7 +386,7 @@ static int eyedropper_grease_pencil_modal(bContext *C, wmOperator *op, const wmE
|
||||
eyedropper_grease_pencil_color_sample(C, eye, event->xy);
|
||||
|
||||
/* Create material. */
|
||||
eyedropper_gpencil_color_set(C, event, eye);
|
||||
eyedropper_grease_pencil_color_set(C, event, eye);
|
||||
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, nullptr);
|
||||
|
||||
eyedropper_grease_pencil_exit(C, op);
|
||||
|
||||
@@ -56,7 +56,6 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
|
||||
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_bone");
|
||||
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
|
||||
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver");
|
||||
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_gpencil_color");
|
||||
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_grease_pencil_color");
|
||||
|
||||
return keymap;
|
||||
|
||||
@@ -1570,10 +1570,6 @@ void UI_OT_eyedropper_depth(wmOperatorType *ot);
|
||||
|
||||
void UI_OT_eyedropper_driver(wmOperatorType *ot);
|
||||
|
||||
/* interface_eyedropper_gpencil_color.c */
|
||||
|
||||
void UI_OT_eyedropper_gpencil_color(wmOperatorType *ot);
|
||||
|
||||
/* eyedropper_grease_pencil_color.cc */
|
||||
|
||||
void UI_OT_eyedropper_grease_pencil_color(wmOperatorType *ot);
|
||||
|
||||
@@ -2845,7 +2845,6 @@ void ED_operatortypes_ui()
|
||||
WM_operatortype_append(UI_OT_eyedropper_id);
|
||||
WM_operatortype_append(UI_OT_eyedropper_depth);
|
||||
WM_operatortype_append(UI_OT_eyedropper_driver);
|
||||
WM_operatortype_append(UI_OT_eyedropper_gpencil_color);
|
||||
WM_operatortype_append(UI_OT_eyedropper_bone);
|
||||
WM_operatortype_append(UI_OT_eyedropper_grease_pencil_color);
|
||||
}
|
||||
|
||||
@@ -171,24 +171,6 @@ static void stats_object(Object *ob,
|
||||
stats->totlampsel++;
|
||||
}
|
||||
break;
|
||||
case OB_GPENCIL_LEGACY: {
|
||||
if (is_selected) {
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
if (!BLI_gset_add(objects_gset, gpd)) {
|
||||
break;
|
||||
}
|
||||
/* GPXX Review if we can move to other place when object change
|
||||
* maybe to depsgraph evaluation
|
||||
*/
|
||||
BKE_gpencil_stats_update(gpd);
|
||||
|
||||
stats->totgplayer += gpd->totlayer;
|
||||
stats->totgpframe += gpd->totframe;
|
||||
stats->totgpstroke += gpd->totstroke;
|
||||
stats->totgppoint += gpd->totpoint;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OB_GREASE_PENCIL: {
|
||||
if (!is_selected) {
|
||||
break;
|
||||
|
||||
@@ -5,19 +5,18 @@
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_crazyspace.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_gpencil_legacy.h"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_scene.hh"
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "DNA_grease_pencil_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
@@ -126,12 +125,13 @@ int GreasePencilImporter::create_material(const StringRefNull name,
|
||||
{
|
||||
const ColorGeometry4f default_stroke_color = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
const ColorGeometry4f default_fill_color = {0.5f, 0.5f, 0.5f, 1.0f};
|
||||
int mat_index = BKE_gpencil_object_material_index_get_by_name(object_, name.c_str());
|
||||
int mat_index = BKE_grease_pencil_object_material_index_get_by_name(object_, name.c_str());
|
||||
/* Stroke and Fill material. */
|
||||
if (mat_index == -1) {
|
||||
Main *bmain = CTX_data_main(&context_.C);
|
||||
int new_idx;
|
||||
Material *mat_gp = BKE_gpencil_object_material_new(bmain, object_, name.c_str(), &new_idx);
|
||||
Material *mat_gp = BKE_grease_pencil_object_material_new(
|
||||
bmain, object_, name.c_str(), &new_idx);
|
||||
MaterialGPencilStyle *gp_style = mat_gp->gp_style;
|
||||
gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
|
||||
gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
|
||||
|
||||
@@ -333,9 +333,6 @@ typedef struct bGPDstroke {
|
||||
/** Curve used to edit the stroke using Bezier handlers. */
|
||||
struct bGPDcurve *editcurve;
|
||||
|
||||
/* NOTE: When adding new members, make sure to add them to BKE_gpencil_stroke_copy_settings as
|
||||
* well! */
|
||||
|
||||
bGPDstroke_Runtime runtime;
|
||||
void *_pad5;
|
||||
} bGPDstroke;
|
||||
@@ -429,9 +426,6 @@ typedef struct bGPDframe {
|
||||
/** Keyframe type (eBezTriple_KeyframeType). */
|
||||
short key_type;
|
||||
|
||||
/* NOTE: When adding new members, make sure to add them to BKE_gpencil_frame_copy_settings as
|
||||
* well! */
|
||||
|
||||
bGPDframe_Runtime runtime;
|
||||
} bGPDframe;
|
||||
|
||||
@@ -561,9 +555,6 @@ typedef struct bGPDlayer {
|
||||
float layer_mat[4][4], layer_invmat[4][4];
|
||||
char _pad3[4];
|
||||
|
||||
/* NOTE: When adding new members, make sure to add them to BKE_gpencil_layer_copy_settings as
|
||||
* well! */
|
||||
|
||||
bGPDlayer_Runtime runtime;
|
||||
} bGPDlayer;
|
||||
|
||||
@@ -769,9 +760,6 @@ typedef struct bGPdata {
|
||||
|
||||
bGPgrid grid;
|
||||
|
||||
/* NOTE: When adding new members, make sure to add them to BKE_gpencil_data_copy_settings as
|
||||
* well! */
|
||||
|
||||
bGPdata_Runtime runtime;
|
||||
} bGPdata;
|
||||
|
||||
|
||||
@@ -800,31 +800,6 @@ static bool rna_Object_update_from_editmode(Object *ob, Main *bmain)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool rna_Object_generate_gpencil_strokes(Object *ob,
|
||||
bContext *C,
|
||||
ReportList *reports,
|
||||
Object *ob_gpencil,
|
||||
bool use_collections,
|
||||
float scale_thickness,
|
||||
float sample)
|
||||
{
|
||||
if (ob->type != OB_CURVES_LEGACY) {
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"Object '%s' is not valid for this operation! Only curves are supported",
|
||||
ob->id.name + 2);
|
||||
return false;
|
||||
}
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
BKE_gpencil_convert_curve(
|
||||
bmain, scene, ob_gpencil, ob, use_collections, scale_thickness, sample);
|
||||
|
||||
WM_main_add_notifier(NC_GPENCIL | ND_DATA, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
#else /* RNA_RUNTIME */
|
||||
|
||||
void RNA_api_object(StructRNA *srna)
|
||||
@@ -1356,25 +1331,6 @@ void RNA_api_object(StructRNA *srna)
|
||||
RNA_def_function_ui_description(func,
|
||||
"Release memory used by caches associated with this object. "
|
||||
"Intended to be used by render engines only.");
|
||||
|
||||
/* Convert curve object to gpencil strokes. */
|
||||
func = RNA_def_function(srna, "generate_gpencil_strokes", "rna_Object_generate_gpencil_strokes");
|
||||
RNA_def_function_ui_description(func, "Convert a curve object to grease pencil strokes.");
|
||||
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
|
||||
|
||||
parm = RNA_def_pointer(func,
|
||||
"grease_pencil_object",
|
||||
"Object",
|
||||
"",
|
||||
"Grease Pencil object used to create new strokes");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
||||
parm = RNA_def_boolean(func, "use_collections", true, "", "Use Collections");
|
||||
parm = RNA_def_float(
|
||||
func, "scale_thickness", 1.0f, 0.0f, FLT_MAX, "", "Thickness scaling factor", 0.0f, 100.0f);
|
||||
parm = RNA_def_float(
|
||||
func, "sample", 0.0f, 0.0f, FLT_MAX, "", "Sample distance, zero to disable", 0.0f, 100.0f);
|
||||
parm = RNA_def_boolean(func, "result", false, "", "Result");
|
||||
RNA_def_function_return(func, parm);
|
||||
}
|
||||
|
||||
#endif /* RNA_RUNTIME */
|
||||
|
||||
@@ -871,7 +871,6 @@ struct GreasePencilLineartModifierData;
|
||||
struct LineartData;
|
||||
struct Scene;
|
||||
|
||||
void MOD_lineart_destroy_render_data(struct LineartGpencilModifierData *lmd_legacy);
|
||||
void MOD_lineart_destroy_render_data_v3(struct GreasePencilLineartModifierData *lmd);
|
||||
|
||||
void MOD_lineart_chain_feature_lines(LineartData *ld);
|
||||
@@ -902,10 +901,6 @@ void MOD_lineart_finalize_chains(LineartData *ld);
|
||||
*
|
||||
* \return True when a change is made.
|
||||
*/
|
||||
bool MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph,
|
||||
struct LineartGpencilModifierData *lmd_legacy,
|
||||
struct LineartCache **cached_result,
|
||||
bool enable_stroke_depth_offset);
|
||||
bool MOD_lineart_compute_feature_lines_v3(struct Depsgraph *depsgraph,
|
||||
struct GreasePencilLineartModifierData &lmd,
|
||||
struct LineartCache **cached_result,
|
||||
@@ -921,32 +916,6 @@ LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartData *ld, doubl
|
||||
*/
|
||||
LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y);
|
||||
|
||||
/**
|
||||
* Wrapper for external calls.
|
||||
*/
|
||||
void MOD_lineart_gpencil_generate(LineartCache *cache,
|
||||
struct Depsgraph *depsgraph,
|
||||
struct Object *ob,
|
||||
struct bGPDlayer *gpl,
|
||||
struct bGPDframe *gpf,
|
||||
int8_t source_type,
|
||||
void *source_reference,
|
||||
int level_start,
|
||||
int level_end,
|
||||
int mat_nr,
|
||||
int16_t edge_types,
|
||||
uint8_t mask_switches,
|
||||
uint8_t material_mask_bits,
|
||||
uint8_t intersection_mask,
|
||||
int16_t thickness,
|
||||
float opacity,
|
||||
uint8_t shadow_selection,
|
||||
uint8_t silhouette_mode,
|
||||
const char *source_vgname,
|
||||
const char *vgname,
|
||||
int modifier_flags,
|
||||
int modifier_calculation_flags);
|
||||
|
||||
namespace blender::bke::greasepencil {
|
||||
class Drawing;
|
||||
}
|
||||
|
||||
@@ -3576,14 +3576,6 @@ void MOD_lineart_destroy_render_data_v3(GreasePencilLineartModifierData *lmd)
|
||||
}
|
||||
}
|
||||
|
||||
void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd_legacy)
|
||||
{
|
||||
GreasePencilLineartModifierData lmd;
|
||||
greasepencil::convert::lineart_wrap_v3(lmd_legacy, &lmd);
|
||||
MOD_lineart_destroy_render_data_v3(&lmd);
|
||||
greasepencil::convert::lineart_unwrap_v3(lmd_legacy, &lmd);
|
||||
}
|
||||
|
||||
LineartCache *MOD_lineart_init_cache()
|
||||
{
|
||||
LineartCache *lc = static_cast<LineartCache *>(
|
||||
@@ -5229,327 +5221,11 @@ bool MOD_lineart_compute_feature_lines_v3(Depsgraph *depsgraph,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
|
||||
LineartGpencilModifierData *lmd_legacy,
|
||||
LineartCache **cached_result,
|
||||
bool enable_stroke_depth_offset)
|
||||
{
|
||||
bool ret = false;
|
||||
GreasePencilLineartModifierData lmd;
|
||||
greasepencil::convert::lineart_wrap_v3(lmd_legacy, &lmd);
|
||||
ret = MOD_lineart_compute_feature_lines_v3(
|
||||
depsgraph, lmd, cached_result, enable_stroke_depth_offset);
|
||||
greasepencil::convert::lineart_unwrap_v3(lmd_legacy, &lmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lineart_gpencil_generate(LineartCache *cache,
|
||||
Depsgraph *depsgraph,
|
||||
Object *gpencil_object,
|
||||
float (*gp_obmat_inverse)[4],
|
||||
bGPDlayer * /*gpl*/,
|
||||
bGPDframe *gpf,
|
||||
int level_start,
|
||||
int level_end,
|
||||
int material_nr,
|
||||
Object *source_object,
|
||||
Collection *source_collection,
|
||||
int types,
|
||||
uchar mask_switches,
|
||||
uchar material_mask_bits,
|
||||
uchar intersection_mask,
|
||||
int16_t thickness,
|
||||
float opacity,
|
||||
uchar shaodow_selection,
|
||||
uchar silhouette_mode,
|
||||
const char *source_vgname,
|
||||
const char *vgname,
|
||||
int modifier_flags,
|
||||
int modifier_calculation_flags)
|
||||
{
|
||||
if (cache == nullptr) {
|
||||
if (G.debug_value == 4000) {
|
||||
printf("nullptr Lineart cache!\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int stroke_count = 0;
|
||||
int color_idx = 0;
|
||||
|
||||
Object *orig_ob = nullptr;
|
||||
if (source_object) {
|
||||
orig_ob = source_object->id.orig_id ? (Object *)source_object->id.orig_id : source_object;
|
||||
}
|
||||
|
||||
Collection *orig_col = nullptr;
|
||||
if (source_collection) {
|
||||
orig_col = source_collection->id.orig_id ? (Collection *)source_collection->id.orig_id :
|
||||
source_collection;
|
||||
}
|
||||
|
||||
/* (!orig_col && !orig_ob) means the whole scene is selected. */
|
||||
|
||||
int enabled_types = cache->all_enabled_edge_types;
|
||||
bool invert_input = modifier_calculation_flags & MOD_LINEART_INVERT_SOURCE_VGROUP;
|
||||
bool match_output = modifier_calculation_flags & MOD_LINEART_MATCH_OUTPUT_VGROUP;
|
||||
bool inverse_silhouette = modifier_flags & MOD_LINEART_INVERT_SILHOUETTE_FILTER;
|
||||
|
||||
LISTBASE_FOREACH (LineartEdgeChain *, ec, &cache->chains) {
|
||||
|
||||
if (ec->picked) {
|
||||
continue;
|
||||
}
|
||||
if (!(ec->type & (types & enabled_types))) {
|
||||
continue;
|
||||
}
|
||||
if (ec->level > level_end || ec->level < level_start) {
|
||||
continue;
|
||||
}
|
||||
if (orig_ob && orig_ob != ec->object_ref) {
|
||||
continue;
|
||||
}
|
||||
if (orig_col && ec->object_ref) {
|
||||
if (BKE_collection_has_object_recursive_instanced(orig_col, (Object *)ec->object_ref)) {
|
||||
if (modifier_flags & MOD_LINEART_INVERT_COLLECTION) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(modifier_flags & MOD_LINEART_INVERT_COLLECTION)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mask_switches & MOD_LINEART_MATERIAL_MASK_ENABLE) {
|
||||
if (mask_switches & MOD_LINEART_MATERIAL_MASK_MATCH) {
|
||||
if (ec->material_mask_bits != material_mask_bits) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(ec->material_mask_bits & material_mask_bits)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ec->type & MOD_LINEART_EDGE_FLAG_INTERSECTION) {
|
||||
if (mask_switches & MOD_LINEART_INTERSECTION_MATCH) {
|
||||
if (ec->intersection_mask != intersection_mask) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((intersection_mask) && !(ec->intersection_mask & intersection_mask)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shaodow_selection) {
|
||||
if (ec->shadow_mask_bits != LRT_SHADOW_MASK_UNDEFINED) {
|
||||
/* TODO(@Yiming): Give a behavior option for how to display undefined shadow info. */
|
||||
if (shaodow_selection == LINEART_SHADOW_FILTER_ILLUMINATED &&
|
||||
!(ec->shadow_mask_bits & LRT_SHADOW_MASK_ILLUMINATED))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (shaodow_selection == LINEART_SHADOW_FILTER_SHADED &&
|
||||
!(ec->shadow_mask_bits & LRT_SHADOW_MASK_SHADED))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (shaodow_selection == LINEART_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES) {
|
||||
uint32_t test_bits = ec->shadow_mask_bits & LRT_SHADOW_TEST_SHAPE_BITS;
|
||||
if ((test_bits != LRT_SHADOW_MASK_ILLUMINATED) &&
|
||||
(test_bits != (LRT_SHADOW_MASK_SHADED | LRT_SHADOW_MASK_ILLUMINATED_SHAPE)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (silhouette_mode && (ec->type & (MOD_LINEART_EDGE_FLAG_CONTOUR))) {
|
||||
bool is_silhouette = false;
|
||||
if (orig_col) {
|
||||
if (!ec->silhouette_backdrop) {
|
||||
is_silhouette = true;
|
||||
}
|
||||
else if (!BKE_collection_has_object_recursive_instanced(orig_col, ec->silhouette_backdrop))
|
||||
{
|
||||
is_silhouette = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((!orig_ob) && (!ec->silhouette_backdrop)) {
|
||||
is_silhouette = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((silhouette_mode == LINEART_SILHOUETTE_FILTER_INDIVIDUAL || orig_ob) &&
|
||||
ec->silhouette_backdrop != ec->object_ref)
|
||||
{
|
||||
is_silhouette = true;
|
||||
}
|
||||
|
||||
if (inverse_silhouette) {
|
||||
is_silhouette = !is_silhouette;
|
||||
}
|
||||
if (!is_silhouette) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Preserved: If we ever do asynchronous generation, this picked flag should be set here. */
|
||||
// ec->picked = 1;
|
||||
|
||||
const int count = MOD_lineart_chain_count(ec);
|
||||
if (count < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bGPDstroke *gps = BKE_gpencil_stroke_add(gpf, color_idx, count, thickness, false);
|
||||
|
||||
int i;
|
||||
LISTBASE_FOREACH_INDEX (LineartEdgeChainItem *, eci, &ec->chain, i) {
|
||||
bGPDspoint *point = &gps->points[i];
|
||||
mul_v3_m4v3(&point->x, gp_obmat_inverse, eci->gpos);
|
||||
point->pressure = 1.0f;
|
||||
point->strength = opacity;
|
||||
}
|
||||
|
||||
BKE_gpencil_dvert_ensure(gps);
|
||||
gps->mat_nr = max_ii(material_nr, 0);
|
||||
|
||||
if (source_vgname && vgname) {
|
||||
Object *eval_ob = DEG_get_evaluated_object(depsgraph, ec->object_ref);
|
||||
int gpdg = -1;
|
||||
if (match_output || (gpdg = BKE_object_defgroup_name_index(gpencil_object, vgname)) >= 0) {
|
||||
if (eval_ob && eval_ob->type == OB_MESH) {
|
||||
int dindex = 0;
|
||||
Mesh *mesh = BKE_object_get_evaluated_mesh(eval_ob);
|
||||
MDeformVert *dvert = mesh->deform_verts_for_write().data();
|
||||
if (dvert) {
|
||||
LISTBASE_FOREACH (bDeformGroup *, db, &mesh->vertex_group_names) {
|
||||
if ((!source_vgname) || strstr(db->name, source_vgname) == db->name) {
|
||||
if (match_output) {
|
||||
gpdg = BKE_object_defgroup_name_index(gpencil_object, db->name);
|
||||
if (gpdg < 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int sindex = 0, vindex;
|
||||
LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
|
||||
vindex = eci->index;
|
||||
if (vindex >= mesh->verts_num) {
|
||||
break;
|
||||
}
|
||||
MDeformWeight *mdw = BKE_defvert_ensure_index(&dvert[vindex], dindex);
|
||||
MDeformWeight *gdw = BKE_defvert_ensure_index(&gps->dvert[sindex], gpdg);
|
||||
|
||||
float use_weight = mdw->weight;
|
||||
if (invert_input) {
|
||||
use_weight = 1 - use_weight;
|
||||
}
|
||||
gdw->weight = std::max(use_weight, gdw->weight);
|
||||
|
||||
sindex++;
|
||||
}
|
||||
}
|
||||
dindex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (G.debug_value == 4000) {
|
||||
BKE_gpencil_stroke_set_random_color(gps);
|
||||
}
|
||||
BKE_gpencil_stroke_geometry_update(static_cast<bGPdata *>(gpencil_object->data), gps);
|
||||
stroke_count++;
|
||||
}
|
||||
|
||||
if (G.debug_value == 4000) {
|
||||
printf("LRT: Generated %d strokes.\n", stroke_count);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct LineartChainWriteInfo {
|
||||
LineartEdgeChain *chain;
|
||||
int point_count;
|
||||
} LineartChainWriteInfo;
|
||||
|
||||
void MOD_lineart_gpencil_generate(LineartCache *cache,
|
||||
Depsgraph *depsgraph,
|
||||
Object *ob,
|
||||
bGPDlayer *gpl,
|
||||
bGPDframe *gpf,
|
||||
int8_t source_type,
|
||||
void *source_reference,
|
||||
int level_start,
|
||||
int level_end,
|
||||
int mat_nr,
|
||||
int16_t edge_types,
|
||||
uchar mask_switches,
|
||||
uchar material_mask_bits,
|
||||
uchar intersection_mask,
|
||||
int16_t thickness,
|
||||
float opacity,
|
||||
uchar shadow_selection,
|
||||
uchar silhouette_mode,
|
||||
const char *source_vgname,
|
||||
const char *vgname,
|
||||
int modifier_flags,
|
||||
int modifier_calculation_flags)
|
||||
{
|
||||
|
||||
if (!gpl || !gpf || !ob) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object *source_object = nullptr;
|
||||
Collection *source_collection = nullptr;
|
||||
int16_t use_types = edge_types;
|
||||
if (source_type == LINEART_SOURCE_OBJECT) {
|
||||
if (!source_reference) {
|
||||
return;
|
||||
}
|
||||
source_object = (Object *)source_reference;
|
||||
}
|
||||
else if (source_type == LINEART_SOURCE_COLLECTION) {
|
||||
if (!source_reference) {
|
||||
return;
|
||||
}
|
||||
source_collection = (Collection *)source_reference;
|
||||
}
|
||||
|
||||
float gp_obmat_inverse[4][4];
|
||||
invert_m4_m4(gp_obmat_inverse, ob->object_to_world().ptr());
|
||||
lineart_gpencil_generate(cache,
|
||||
depsgraph,
|
||||
ob,
|
||||
gp_obmat_inverse,
|
||||
gpl,
|
||||
gpf,
|
||||
level_start,
|
||||
level_end,
|
||||
mat_nr,
|
||||
source_object,
|
||||
source_collection,
|
||||
use_types,
|
||||
mask_switches,
|
||||
material_mask_bits,
|
||||
intersection_mask,
|
||||
thickness,
|
||||
opacity,
|
||||
shadow_selection,
|
||||
silhouette_mode,
|
||||
source_vgname,
|
||||
vgname,
|
||||
modifier_flags,
|
||||
modifier_calculation_flags);
|
||||
}
|
||||
|
||||
void MOD_lineart_gpencil_generate_v3(const LineartCache *cache,
|
||||
const blender::float4x4 &inverse_mat,
|
||||
Depsgraph *depsgraph,
|
||||
|
||||
Reference in New Issue
Block a user