GSOC 2013 paint
authorAntony Riakiotakis <kalast@gmail.com>
Mon, 21 Jul 2014 10:02:05 +0000 (12:02 +0200)
committerAntony Riakiotakis <kalast@gmail.com>
Mon, 21 Jul 2014 10:02:05 +0000 (12:02 +0200)
Yep, at last it's here!

There are a few minor issues remaining but development can go on in
master after discussion at blender institute.

For full list of features see:

http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.72/Painting

Thanks to Sergey and Campbell for the extensive review and to the
countless artists that have given their input and reported issues during
development.

113 files changed:
SConstruct
release/scripts/startup/bl_ui/properties_paint_common.py
release/scripts/startup/bl_ui/space_image.py
release/scripts/startup/bl_ui/space_view3d.py
release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_blender.h
source/blender/blenkernel/BKE_brush.h
source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/BKE_main.h
source/blender/blenkernel/BKE_material.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/editderivedmesh.c
source/blender/blenkernel/intern/idcode.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/material.c
source/blender/blenkernel/intern/paint.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/blenkernel/intern/texture.c
source/blender/blenlib/BLI_math_color_blend.h
source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/intern/math_color_blend_inline.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/versioning_270.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/datafiles/CMakeLists.txt
source/blender/editors/datafiles/SConscript
source/blender/editors/include/ED_datafiles.h
source/blender/editors/include/ED_image.h
source/blender/editors/include/ED_paint.h
source/blender/editors/include/ED_transform.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/include/UI_icons.h
source/blender/editors/include/UI_interface.h
source/blender/editors/include/UI_resources.h
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_icons.c
source/blender/editors/interface/interface_intern.h
source/blender/editors/interface/interface_ops.c
source/blender/editors/interface/interface_templates.c
source/blender/editors/interface/interface_widgets.c
source/blender/editors/interface/resources.c
source/blender/editors/render/render_update.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/sculpt_paint/CMakeLists.txt
source/blender/editors/sculpt_paint/paint_cursor.c
source/blender/editors/sculpt_paint/paint_curve.c [new file with mode: 0644]
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_image_2d.c
source/blender/editors/sculpt_paint/paint_image_proj.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_ops.c
source/blender/editors/sculpt_paint/paint_stroke.c
source/blender/editors/sculpt_paint/paint_undo.c
source/blender/editors/sculpt_paint/paint_utils.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/sculpt_paint/sculpt_undo.c
source/blender/editors/space_api/spacetypes.c
source/blender/editors/space_image/image_edit.c
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_constraints.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_snap.c
source/blender/editors/uvedit/uvedit_draw.c
source/blender/editors/uvedit/uvedit_ops.c
source/blender/gpu/GPU_buffers.h
source/blender/gpu/GPU_draw.h
source/blender/gpu/intern/gpu_buffers.c
source/blender/gpu/intern/gpu_draw.c
source/blender/imbuf/IMB_imbuf.h
source/blender/imbuf/intern/rectop.c
source/blender/makesdna/DNA_ID.h
source/blender/makesdna/DNA_brush_types.h
source/blender/makesdna/DNA_material_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_space_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_brush.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_material.c
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_sculpt_paint.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_ui_api.c
source/blender/makesrna/intern/rna_userdef.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm.c
source/blender/windowmanager/intern/wm_dragdrop.c
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_window.c
source/blender/windowmanager/wm_event_types.h
source/blenderplayer/bad_level_call_stubs/stubs.c
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
source/gameengine/VideoTexture/ImageBuff.cpp

index 6abf91c3c13d1b1ead1279129e8243309e890a84..331158e89d29bb7105d8b43c26274ba450852ba5 100644 (file)
@@ -730,6 +730,8 @@ if B.targets != ['cudakernels']:
     data_to_c_simple("release/datafiles/brushicons/soften.png")
     data_to_c_simple("release/datafiles/brushicons/subtract.png")
     data_to_c_simple("release/datafiles/brushicons/texdraw.png")
+    data_to_c_simple("release/datafiles/brushicons/texfill.png")
+    data_to_c_simple("release/datafiles/brushicons/texmask.png")
     data_to_c_simple("release/datafiles/brushicons/thumb.png")
     data_to_c_simple("release/datafiles/brushicons/twist.png")
     data_to_c_simple("release/datafiles/brushicons/vertexdraw.png")
index 462ca2e85cafaec960c0e20a51494e738e0cb529..8359ae651ffb4875e0ff2491e6e6c205f2595245 100644 (file)
@@ -50,6 +50,10 @@ class UnifiedPaintPanel():
         row.prop(ups, "use_unified_strength", text="Strength")
         if context.weight_paint_object:
             parent.prop(ups, "use_unified_weight", text="Weight")
+        elif context.vertex_paint_object or context.image_paint_object:
+            parent.prop(ups, "use_unified_color", text="Color")
+        else:
+            parent.prop(ups, "use_unified_color", text="Color")
 
     @staticmethod
     def prop_unified_size(parent, context, brush, prop_name, icon='NONE', text="", slider=False):
@@ -69,6 +73,105 @@ class UnifiedPaintPanel():
         ptr = ups if ups.use_unified_weight else brush
         parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider)
 
+    @staticmethod
+    def prop_unified_color(parent, context, brush, prop_name, text=""):
+        ups = context.tool_settings.unified_paint_settings
+        ptr = ups if ups.use_unified_color else brush
+        parent.prop(ptr, prop_name, text=text)
+
+    @staticmethod
+    def prop_unified_color_picker(parent, context, brush, prop_name, value_slider=True):
+        ups = context.tool_settings.unified_paint_settings
+        ptr = ups if ups.use_unified_color else brush
+        parent.template_color_picker(ptr, prop_name, value_slider=value_slider)
+
+
+def brush_texpaint_common(panel, context, layout, brush, settings):
+    capabilities = brush.image_paint_capabilities
+
+    col = layout.column()
+
+    if brush.image_tool in {'DRAW', 'FILL'}:
+        if brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}:
+            if not brush.use_gradient:
+                panel.prop_unified_color_picker(col, context, brush, "color", value_slider=True)
+
+            if settings.palette:
+                col.template_palette(settings, "palette", color=True)
+
+            if brush.use_gradient:
+                col.label("Gradient Colors")
+                col.template_color_ramp(brush, "gradient", expand=True)
+
+                if brush.image_tool != 'FILL':
+                    col.label("Background Color")
+                    row = col.row(align=True)
+                    panel.prop_unified_color(row, context, brush, "secondary_color", text="")
+
+                if brush.image_tool == 'DRAW':
+                    col.prop(brush, "gradient_stroke_mode", text="Mode")
+                    if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}:
+                        col.prop(brush, "grad_spacing")
+                elif brush.image_tool == 'FILL':
+                    col.prop(brush, "gradient_fill_mode")
+            else:
+                row = col.row(align=True)
+                panel.prop_unified_color(row, context, brush, "color", text="")
+                if brush.image_tool == 'FILL':
+                    col.prop(brush, "fill_threshold")
+                else:
+                    panel.prop_unified_color(row, context, brush, "secondary_color", text="")
+                    row.separator()
+                    row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="")
+
+    elif brush.image_tool == 'SOFTEN':
+        col = layout.column(align=True)
+        col.row().prop(brush, "direction", expand=True)
+        col.separator()
+        col.prop(brush, "sharp_threshold")
+        col.prop(brush, "blur_kernel_radius")
+        col.separator()
+        col.prop(brush, "blur_mode")
+    elif brush.image_tool == 'MASK':
+        col.prop(brush, "weight", text="Mask Value", slider=True)
+
+    elif brush.image_tool == 'CLONE':
+        col.separator()
+        col.prop(brush, "clone_image", text="Image")
+        col.prop(brush, "clone_alpha", text="Alpha")
+
+    col.separator()
+
+    if capabilities.has_radius:
+        row = col.row(align=True)
+        panel.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
+        panel.prop_unified_size(row, context, brush, "use_pressure_size")
+
+        row = col.row(align=True)
+
+    if capabilities.has_space_attenuation:
+        row.prop(brush, "use_space_attenuation", toggle=True, icon_only=True)
+
+    panel.prop_unified_strength(row, context, brush, "strength", text="Strength")
+    panel.prop_unified_strength(row, context, brush, "use_pressure_strength")
+
+    if brush.image_tool in {'DRAW', 'FILL'}:
+        col.separator()
+        col.prop(brush, "blend", text="Blend")
+
+    col = layout.column()
+
+    # use_accumulate
+    if capabilities.has_accumulate:
+        col = layout.column(align=True)
+        col.prop(brush, "use_accumulate")
+
+    col.prop(brush, "use_alpha")
+    col.prop(brush, "use_gradient")
+
+    col.separator()
+    col.template_ID(settings, "palette", new="palette.new")
+
 
 # Used in both the View3D toolbar and texture properties
 def brush_texture_settings(layout, brush, sculpt):
@@ -136,6 +239,7 @@ def brush_mask_texture_settings(layout, brush):
         layout.operator("brush.stencil_reset_transform").mask = True
 
     col = layout.column()
+    col.prop(brush, "use_pressure_masking", text="")
     col.label(text="Angle:")
     col.active = brush.brush_capabilities.has_texture_angle
     col.prop(mask_tex_slot, "angle", text="")
index 97c89df06938886d9af8eec900233186948bc3ec..b3ba3b6305f6c1145db626a7f55e00fec8793d69 100644 (file)
@@ -22,6 +22,7 @@ from bpy.types import Header, Menu, Panel
 from bl_ui.properties_paint_common import (
         UnifiedPaintPanel,
         brush_texture_settings,
+        brush_texpaint_common,
         brush_mask_texture_settings,
         )
 from bl_ui.properties_grease_pencil_common import GreasePencilPanel
@@ -31,13 +32,11 @@ from bpy.app.translations import pgettext_iface as iface_
 class ImagePaintPanel(UnifiedPaintPanel):
     bl_space_type = 'IMAGE_EDITOR'
     bl_region_type = 'TOOLS'
-    bl_category = "Tools"
 
 
-class BrushButtonsPanel:
+class BrushButtonsPanel(UnifiedPaintPanel):
     bl_space_type = 'IMAGE_EDITOR'
     bl_region_type = 'TOOLS'
-    bl_category = "Tools"
 
     @classmethod
     def poll(cls, context):
@@ -66,6 +65,7 @@ class IMAGE_MT_view(Menu):
         sima = context.space_data
         uv = sima.uv_editor
         toolsettings = context.tool_settings
+        paint = toolsettings.image_paint
 
         show_uvedit = sima.show_uvedit
         show_render = sima.show_render
@@ -80,6 +80,8 @@ class IMAGE_MT_view(Menu):
             layout.prop(toolsettings, "show_uv_local_view")
 
         layout.prop(uv, "show_other_objects")
+        if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'):
+            layout.prop(uv, "show_texpaint")
 
         layout.separator()
 
@@ -140,6 +142,24 @@ class IMAGE_MT_select(Menu):
         layout.operator("uv.select_split")
 
 
+class IMAGE_MT_brush(Menu):
+    bl_label = "Brush"
+
+    def draw(self, context):
+        layout = self.layout
+        toolsettings = context.tool_settings
+        settings = toolsettings.image_paint
+        brush = settings.brush
+
+        ups = context.tool_settings.unified_paint_settings
+        layout.prop(ups, "use_unified_size", text="Unified Size")
+        layout.prop(ups, "use_unified_strength", text="Unified Strength")
+        layout.separator()
+
+        # brush tool
+        layout.prop_menu_enum(brush, "image_tool")
+
+
 class IMAGE_MT_image(Menu):
     bl_label = "Image"
 
@@ -382,7 +402,6 @@ class IMAGE_HT_header(Header):
         mode = sima.mode
 
         show_render = sima.show_render
-        # show_paint = sima.show_paint
         show_uvedit = sima.show_uvedit
         show_maskedit = sima.show_maskedit
 
@@ -401,8 +420,7 @@ class IMAGE_HT_header(Header):
             row = layout.row()
             row.template_ID(sima, "mask", new="mask.new")
 
-        if show_uvedit or show_maskedit:
-            layout.prop(sima, "pivot_point", icon_only=True)
+        layout.prop(sima, "pivot_point", icon_only=True)
 
         # uv editing
         if show_uvedit:
@@ -462,6 +480,7 @@ class MASK_MT_editor_menus(Menu):
 
         show_uvedit = sima.show_uvedit
         show_maskedit = sima.show_maskedit
+        show_paint = sima.show_paint
 
         layout.menu("IMAGE_MT_view")
 
@@ -469,6 +488,8 @@ class MASK_MT_editor_menus(Menu):
             layout.menu("IMAGE_MT_select")
         if show_maskedit:
             layout.menu("MASK_MT_select")
+        if show_paint:
+            layout.menu("IMAGE_MT_brush")
 
         if ima and ima.is_dirty:
             layout.menu("IMAGE_MT_image", text="Image*")
@@ -658,49 +679,27 @@ class IMAGE_PT_tools_transform_uvs(Panel, UVToolsPanel):
         col.operator("transform.shear")
 
 
-class IMAGE_PT_paint(Panel, ImagePaintPanel):
+class IMAGE_PT_paint(Panel, BrushButtonsPanel):
     bl_label = "Paint"
-
-    @classmethod
-    def poll(cls, context):
-        sima = context.space_data
-        return sima.show_paint
+    bl_category = "Tools"
 
     def draw(self, context):
         layout = self.layout
 
-        toolsettings = context.tool_settings.image_paint
-        brush = toolsettings.brush
+        settings = context.tool_settings.image_paint
+        brush = settings.brush
 
         col = layout.column()
-        col.template_ID_preview(toolsettings, "brush", new="brush.add", rows=2, cols=6)
+        col.template_ID_preview(settings, "brush", new="brush.add", rows=2, cols=6)
 
         if brush:
-            col = layout.column()
-
-            if brush.image_tool == 'DRAW' and brush.blend not in ('ERASE_ALPHA', 'ADD_ALPHA'):
-                col.template_color_picker(brush, "color", value_slider=True)
-                col.prop(brush, "color", text="")
-
-            row = col.row(align=True)
-            self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
-            self.prop_unified_size(row, context, brush, "use_pressure_size")
-
-            row = col.row(align=True)
-            self.prop_unified_strength(row, context, brush, "strength", slider=True, text="Strength")
-            self.prop_unified_strength(row, context, brush, "use_pressure_strength")
-
-            col.prop(brush, "blend", text="Blend")
-
-            if brush.image_tool == 'CLONE':
-                col.separator()
-                col.prop(brush, "clone_image", text="Image")
-                col.prop(brush, "clone_alpha", text="Alpha")
+            brush_texpaint_common(self, context, layout, brush, settings)
 
 
 class IMAGE_PT_tools_brush_overlay(BrushButtonsPanel, Panel):
     bl_label = "Overlay"
     bl_options = {'DEFAULT_CLOSED'}
+    bl_category = "Options"
 
     def draw(self, context):
         layout = self.layout
@@ -754,6 +753,7 @@ class IMAGE_PT_tools_brush_overlay(BrushButtonsPanel, Panel):
 class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
     bl_label = "Texture"
     bl_options = {'DEFAULT_CLOSED'}
+    bl_category = "Tools"
 
     def draw(self, context):
         layout = self.layout
@@ -770,6 +770,7 @@ class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
 class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
     bl_label = "Texture Mask"
     bl_options = {'DEFAULT_CLOSED'}
+    bl_category = "Tools"
 
     def draw(self, context):
         layout = self.layout
@@ -786,6 +787,7 @@ class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
 class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, Panel):
     bl_label = "Tool"
     bl_options = {'DEFAULT_CLOSED'}
+    bl_category = "Options"
 
     def draw(self, context):
         layout = self.layout
@@ -804,6 +806,7 @@ class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, Panel):
 class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel):
     bl_label = "Paint Stroke"
     bl_options = {'DEFAULT_CLOSED'}
+    bl_category = "Tools"
 
     def draw(self, context):
         layout = self.layout
@@ -828,10 +831,19 @@ class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel):
         if brush.use_space:
             col.separator()
             row = col.row(align=True)
-            row.active = brush.use_space
             row.prop(brush, "spacing", text="Spacing")
             row.prop(brush, "use_pressure_spacing", toggle=True, text="")
 
+        if brush.use_line or brush.use_curve:
+            col.separator()
+            row = col.row(align=True)
+            row.prop(brush, "spacing", text="Spacing")
+
+        if brush.use_curve:
+            col.separator()
+            col.template_ID(brush, "paint_curve", new="paintcurve.new")
+            col.operator("paintcurve.draw")
+
         col = layout.column()
         col.separator()
 
@@ -846,25 +858,23 @@ class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel):
         col = layout.column()
         col.separator()
 
-        col.prop(brush, "use_smooth_stroke")
+        if brush.brush_capabilities.has_smooth_stroke:
+            col.prop(brush, "use_smooth_stroke")
 
-        sub = col.column()
-        sub.active = brush.use_smooth_stroke
-        sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
-        sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
+            sub = col.column()
+            sub.active = brush.use_smooth_stroke
+            sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
+            sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
 
-        col.separator()
+            col.separator()
 
         col.prop(toolsettings, "input_samples")
 
-        col.separator()
-
-        col.prop(brush, "use_wrap")
-
 
 class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
     bl_label = "Paint Curve"
     bl_options = {'DEFAULT_CLOSED'}
+    bl_category = "Tools"
 
     def draw(self, context):
         layout = self.layout
@@ -874,7 +884,8 @@ class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
 
         layout.template_curve_mapping(brush, "curve")
 
-        row = layout.row(align=True)
+        col = layout.column(align=True)
+        row = col.row(align=True)
         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
         row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
         row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
@@ -886,6 +897,7 @@ class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
 class IMAGE_PT_tools_brush_appearance(BrushButtonsPanel, Panel):
     bl_label = "Appearance"
     bl_options = {'DEFAULT_CLOSED'}
+    bl_category = "Options"
 
     def draw(self, context):
         layout = self.layout
@@ -912,6 +924,30 @@ class IMAGE_PT_tools_brush_appearance(BrushButtonsPanel, Panel):
         sub.prop(brush, "icon_filepath", text="")
 
 
+class IMAGE_PT_tools_paint_options(BrushButtonsPanel, Panel):
+    bl_label = "Image Paint"
+    bl_category = "Options"
+
+    def draw(self, context):
+        layout = self.layout
+
+        toolsettings = context.tool_settings
+        brush = toolsettings.image_paint.brush
+
+        ups = toolsettings.unified_paint_settings
+
+        col = layout.column(align=True)
+
+        col.prop(brush, "use_wrap")
+        col.separator()
+
+        col.label(text="Unified Settings:")
+        row = col.row()
+        row.prop(ups, "use_unified_size", text="Size")
+        row.prop(ups, "use_unified_strength", text="Strength")
+        col.prop(ups, "use_unified_color", text="Color")
+
+
 class IMAGE_UV_sculpt_curve(Panel):
     bl_space_type = 'IMAGE_EDITOR'
     bl_region_type = 'TOOLS'
index 4cb3e8e116c90c0a41ec0fd2871e20caf1d95df3..1079c5016a9d7d7124be56f35653d0d356f19f94 100644 (file)
@@ -1454,7 +1454,7 @@ class VIEW3D_MT_brush(Menu):
             layout.separator()
 
             if sculpt_tool != 'GRAB':
-                layout.prop_menu_enum(brush, "stroke_method")
+                layout.prop_menu_enum(brush, "sculpt_stroke_method")
 
                 if sculpt_tool in {'DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'}:
                     layout.prop_menu_enum(brush, "direction")
index 0f2c04d1cdc953dd4d497edd728d618a6fef1862..99b2b8529361cf24b41787f5e831755b4d9052a3 100644 (file)
 
 # <pep8 compliant>
 import bpy
-from bpy.types import Menu, Panel
+from bpy.types import Menu, Panel, UIList
 from bl_ui.properties_grease_pencil_common import GreasePencilPanel
 from bl_ui.properties_paint_common import (
         UnifiedPaintPanel,
         brush_texture_settings,
+        brush_texpaint_common,
         brush_mask_texture_settings,
         )
 
@@ -363,6 +364,7 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, Panel):
 
         draw_repeat_tools(context, layout)
 
+
 class VIEW3D_PT_tools_meshweight(View3DPanel, Panel):
     bl_category = "Tools"
     bl_context = "mesh_edit"
@@ -388,6 +390,7 @@ class VIEW3D_PT_tools_meshweight(View3DPanel, Panel):
         layout = self.layout
         self.draw_generic(layout)
 
+
 class VIEW3D_PT_tools_add_mesh_edit(View3DPanel, Panel):
     bl_category = "Create"
     bl_context = "mesh_edit"
@@ -979,25 +982,7 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
         # Texture Paint Mode #
 
         elif context.image_paint_object and brush:
-            col = layout.column()
-
-            if brush.image_tool == 'DRAW' and brush.blend not in ('ERASE_ALPHA', 'ADD_ALPHA'):
-                col.template_color_picker(brush, "color", value_slider=True)
-                col.prop(brush, "color", text="")
-
-            row = col.row(align=True)
-            self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
-            self.prop_unified_size(row, context, brush, "use_pressure_size")
-
-            row = col.row(align=True)
-            self.prop_unified_strength(row, context, brush, "strength", text="Strength")
-            self.prop_unified_strength(row, context, brush, "use_pressure_strength")
-
-            col.prop(brush, "blend", text="Blend")
-
-            col = layout.column()
-            col.active = (brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'})
-            col.prop(brush, "use_alpha")
+            brush_texpaint_common(self, context, layout, brush, settings)
 
         # Weight Paint Mode #
         elif context.weight_paint_object and brush:
@@ -1024,9 +1009,12 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
         # Vertex Paint Mode #
         elif context.vertex_paint_object and brush:
             col = layout.column()
-            col.template_color_picker(brush, "color", value_slider=True)
-            col.prop(brush, "color", text="")
+            self.prop_unified_color_picker(col, context, brush, "color", value_slider=True)
+            if settings.palette:
+                col.template_palette(settings, "palette", color=True)
+            self.prop_unified_color(col, context, brush, "color", text="")
 
+            col.separator()
             row = col.row(align=True)
             self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
             self.prop_unified_size(row, context, brush, "use_pressure_size")
@@ -1036,12 +1024,75 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
             self.prop_unified_strength(row, context, brush, "use_pressure_strength")
 
             # XXX - TODO
-            #row = col.row(align=True)
-            #row.prop(brush, "jitter", slider=True)
-            #row.prop(brush, "use_pressure_jitter", toggle=True, text="")
-
+            # row = col.row(align=True)
+            # row.prop(brush, "jitter", slider=True)
+            # row.prop(brush, "use_pressure_jitter", toggle=True, text="")
+            col.separator()
             col.prop(brush, "vertex_tool", text="Blend")
 
+            col.separator()
+            col.template_ID(settings, "palette", new="palette.new")
+
+
+class TEXTURE_UL_texpaintslots(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        ma = data
+        ima = item
+
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            layout.label(text=ima.name, translate=False, icon_value=icon)
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label(text="")
+
+
+class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
+    bl_context = "imagepaint"
+    bl_label = "Slots"
+    bl_category = "Layers"
+
+    @classmethod
+    def poll(cls, context):
+        brush = context.tool_settings.image_paint.brush
+        ob = context.active_object
+        return (brush is not None and ob is not None)
+
+    def draw(self, context):
+        layout = self.layout
+
+        settings = context.tool_settings.image_paint
+        brush = settings.brush
+
+        ob = context.active_object
+        col = layout.column()
+
+        if len(ob.material_slots) > 1:
+            col.label("Materials")
+            col.template_list("MATERIAL_UL_matslots", "",
+                              ob, "material_slots",
+                              ob, "active_material_index", rows=2)
+
+        mat = ob.active_material
+        if mat:
+            col.label("Available Paint Slots")
+            col.template_list("TEXTURE_UL_texpaintslots", "",
+                              mat, "texture_paint_slots",
+                              mat, "paint_active_slot", rows=2)
+
+            if not mat.use_nodes:
+                col.operator_menu_enum("paint.add_texture_paint_slot", "type")
+
+                row = col.row(align=True)
+                row.prop(settings, "slot_xresolution_default")
+                row.prop(settings, "slot_yresolution_default")
+                col.prop(settings, "slot_color_default")
+
+            if brush.image_tool == 'CLONE' and settings.use_clone_layer:
+                col.label("Clone Slot")
+                col.template_list("TEXTURE_UL_texpaintslots", "",
+                                  mat, "texture_paint_slots",
+                                  mat, "paint_clone_slot", rows=2)
+
 
 class VIEW3D_PT_tools_brush_overlay(Panel, View3DPaintPanel):
     bl_category = "Options"
@@ -1194,10 +1245,19 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
         if brush.use_space:
             col.separator()
             row = col.row(align=True)
-            row.active = brush.use_space
             row.prop(brush, "spacing", text="Spacing")
             row.prop(brush, "use_pressure_spacing", toggle=True, text="")
 
+        if brush.use_line or brush.use_curve:
+            col.separator()
+            row = col.row(align=True)
+            row.prop(brush, "spacing", text="Spacing")
+
+        if brush.use_curve:
+            col.separator()
+            col.template_ID(brush, "paint_curve", new="paintcurve.new")
+            col.operator("paintcurve.draw")
+
         if context.sculpt_object:
             if brush.sculpt_capabilities.has_jitter:
                 col.separator()
@@ -1234,12 +1294,13 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
             col = layout.column()
             col.separator()
 
-            col.prop(brush, "use_smooth_stroke")
+            if brush.brush_capabilities.has_smooth_stroke:
+                col.prop(brush, "use_smooth_stroke")
 
-            sub = col.column()
-            sub.active = brush.use_smooth_stroke
-            sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
-            sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
+                sub = col.column()
+                sub.active = brush.use_smooth_stroke
+                sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
+                sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
 
         layout.prop(settings, "input_samples")
 
@@ -1263,7 +1324,8 @@ class VIEW3D_PT_tools_brush_curve(Panel, View3DPaintPanel):
 
         layout.template_curve_mapping(brush, "curve", brush=True)
 
-        row = layout.row(align=True)
+        col = layout.column(align=True)
+        row = col.row(align=True)
         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
         row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
         row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
@@ -1493,7 +1555,7 @@ class VIEW3D_PT_tools_vertexpaint(Panel, View3DPaintPanel):
 
         col = layout.column()
         row = col.row()
-        #col.prop(vpaint, "mode", text="")
+        # col.prop(vpaint, "mode", text="")
         row.prop(vpaint, "use_normal")
         col.prop(vpaint, "use_spray")
 
@@ -1531,7 +1593,7 @@ class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel):
         col.operator("image.save_dirty", text="Save All Edited")
 
 
-class VIEW3D_PT_tools_projectpaint(View3DPanel, Panel):
+class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel):
     bl_category = "Options"
     bl_context = "imagepaint"
     bl_label = "Project Paint"
@@ -1551,6 +1613,7 @@ class VIEW3D_PT_tools_projectpaint(View3DPanel, Panel):
         settings = toolsettings.image_paint
 
         col = layout.column()
+
         col.prop(ipaint, "use_occlude")
         col.prop(ipaint, "use_backface_culling")
 
@@ -1565,19 +1628,21 @@ class VIEW3D_PT_tools_projectpaint(View3DPanel, Panel):
 
         split.prop(ipaint, "use_stencil_layer", text="Stencil")
 
-        row = split.row()
-        row.active = (ipaint.use_stencil_layer)
+        col = split.column()
+        col.active = (ipaint.use_stencil_layer)
+        row = col.row()
         stencil_text = mesh.uv_texture_stencil.name if mesh.uv_texture_stencil else ""
         row.menu("VIEW3D_MT_tools_projectpaint_stencil", text=stencil_text, translate=False)
         row.prop(ipaint, "invert_stencil", text="", icon='IMAGE_ALPHA')
+        col.template_ID(ipaint, "stencil_image", new="image.new")
+        col.prop(ipaint, "stencil_color")
 
         col = layout.column()
         col.active = (settings.brush.image_tool == 'CLONE')
-        col.prop(ipaint, "use_clone_layer", text="Clone from UV map")
-        clone_text = mesh.uv_texture_clone.name if mesh.uv_texture_clone else ""
-        col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False)
+        col.prop(ipaint, "use_clone_layer", text="Clone from paint slot")
 
         layout.prop(ipaint, "seam_bleed")
+        self.unified_paint_settings(layout, context)
 
 
 class VIEW3D_PT_imagepaint_options(View3DPaintPanel):
index 1ab5ec51de8eb5d082c523ddc637a25e4190ecb7..868d97681727797ca03a7bea9e3236dd80131d70 100644 (file)
@@ -150,8 +150,10 @@ typedef DMDrawOption (*DMSetDrawOptions)(void *userData, int index);
 typedef DMDrawOption (*DMSetDrawOptionsTex)(struct MTFace *tface, const bool has_vcol, int matnr);
 
 typedef enum DMDrawFlag {
-       DM_DRAW_USE_COLORS = 1,
-       DM_DRAW_ALWAYS_SMOOTH = 2
+       DM_DRAW_USE_COLORS          = (1 << 0),
+       DM_DRAW_ALWAYS_SMOOTH       = (1 << 1),
+       DM_DRAW_USE_ACTIVE_UV       = (1 << 2),
+       DM_DRAW_USE_TEXPAINT_UV     = (1 << 3),
 } DMDrawFlag;
 
 typedef enum DMForeachFlag {
@@ -389,7 +391,7 @@ struct DerivedMesh {
        void (*drawFacesTex)(DerivedMesh *dm,
                             DMSetDrawOptionsTex setDrawOptions,
                             DMCompareDrawOptions compareDrawOptions,
-                            void *userData);
+                            void *userData, DMDrawFlag uvflag);
 
        /** Draw all faces with GLSL materials
         *  o setMaterial is called for every different material nr
@@ -423,7 +425,7 @@ struct DerivedMesh {
        void (*drawMappedFacesTex)(DerivedMesh *dm,
                                   DMSetDrawOptions setDrawOptions,
                                   DMCompareDrawOptions compareDrawOptions,
-                                  void *userData);
+                                  void *userData, DMDrawFlag uvflag);
 
        /** Draw mapped faces with GLSL materials
         * - setMaterial is called for every different material nr
@@ -593,6 +595,8 @@ void DM_ensure_tessface(DerivedMesh *dm);
 void DM_update_tessface_data(DerivedMesh *dm);
 
 void DM_update_materials(DerivedMesh *dm, struct Object *ob);
+struct MTFace *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr);
+
 /** interpolates vertex data from the vertices indexed by src_indices in the
  * source mesh using the given weights and stores the result in the vertex
  * indexed by dest_index in the dest mesh
index 19fa60f5827c7db6a390c70783a3a5664e31d589..5a53b19b34555293cf05e7e0343695395b3daa21 100644 (file)
@@ -42,7 +42,7 @@ extern "C" {
  * and keep comment above the defines.
  * Use STRINGIFY() rather than defining with quotes */
 #define BLENDER_VERSION         271
-#define BLENDER_SUBVERSION      2
+#define BLENDER_SUBVERSION      3
 /* 262 was the last editmesh release but it has compatibility code for bmesh data */
 #define BLENDER_MINVERSION      270
 #define BLENDER_MINSUBVERSION   5
index 104e80e815ce70f9f9cb5714743370a7e9e074a0..d48753590bbd43056b96494f8284605fc3884ce6 100644 (file)
@@ -81,7 +81,11 @@ unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool
 /* radial control */
 struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondary);
 
-/* unified strength and size */
+/* unified strength size and color */
+
+float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush);
+float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush);
+void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3]);
 
 int  BKE_brush_size_get(const struct Scene *scene, struct Brush *brush);
 void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int value);
index 0372931dc496d903ea4a0d6bbb63ac78a226a5fa..0c7af12edc84021fda4dfd265e97ff8230ece8f6 100644 (file)
@@ -71,7 +71,7 @@ void id_clear_lib_data(struct Main *bmain, struct ID *id);
 
 struct ListBase *which_libbase(struct Main *mainlib, short type);
 
-#define MAX_LIBARRAY    41
+#define MAX_LIBARRAY    43
 int set_listbasepointers(struct Main *main, struct ListBase **lb);
 
 void BKE_libblock_free(struct Main *bmain, void *idv);
index 82b03127237d1aa40c44a1e3ce893125e5b3df08..ec654ea4b710b3d74651ef11a702b643fdf0a89b 100644 (file)
@@ -87,6 +87,8 @@ typedef struct Main {
        ListBase nodetree;
        ListBase brush;
        ListBase particle;
+       ListBase palettes;
+       ListBase paintcurves;
        ListBase wm;
        ListBase gpencil;
        ListBase movieclip;
index 89d310753fc9f2fbea8f569975c0f35fe82ac407..e69299a36bf6a6660162b433228825d46eb7bb7d 100644 (file)
@@ -86,6 +86,10 @@ short find_material_index(struct Object *ob, struct Material *ma);
 bool object_add_material_slot(struct Object *ob);
 bool object_remove_material_slot(struct Object *ob);
 
+void BKE_texpaint_slot_refresh_cache(struct Material *ma, bool use_nodes);
+void BKE_texpaint_slots_refresh_object(struct Object *ob, bool use_nodes);
+void BKE_texpaint_slots_clear(struct Material *ma);
+
 /* rna api */
 void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user);
 void BKE_material_append_id(struct ID *id, struct Material *ma);
index 4381330085031bc8b3aa2178831c2f3496f2c11f..0bdac6822f12855cf2efe149e6e6fb6be0a7b740 100644 (file)
@@ -40,11 +40,15 @@ struct CurveMapping;
 struct MDisps;
 struct MeshElemMap;
 struct GridPaintMask;
+struct Main;
 struct MFace;
 struct MultireModifierData;
 struct MVert;
 struct Object;
 struct Paint;
+struct PaintCurve;
+struct Palette;
+struct PaletteColor;
 struct PBVH;
 struct Scene;
 struct Sculpt;
@@ -52,6 +56,7 @@ struct StrokeCache;
 struct Tex;
 struct ImagePool;
 struct UnifiedPaintSettings;
+struct wmOperator;
 
 enum OverlayFlags;
 
@@ -91,6 +96,19 @@ OverlayControlFlags BKE_paint_get_overlay_flags(void);
 void BKE_paint_reset_overlay_invalid(OverlayControlFlags flag);
 void BKE_paint_set_overlay_override(enum OverlayFlags flag);
 
+/* palettes */
+void                 BKE_palette_free(struct Palette *palette);
+struct Palette      *BKE_palette_add(struct Main *bmain, const char *name);
+struct PaletteColor *BKE_palette_color_add(struct Palette *palette);
+void                 BKE_palette_color_delete(struct Palette *palette);
+bool                 BKE_palette_is_empty(const struct Palette *palette);
+void                 BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
+void                 BKE_palette_cleanup(struct Palette *palette);
+
+/* paint curves */
+struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
+void BKE_paint_curve_free(struct PaintCurve *pc);
+
 void BKE_paint_init(struct Paint *p, const char col[3]);
 void BKE_paint_free(struct Paint *p);
 void BKE_paint_copy(struct Paint *src, struct Paint *tar);
@@ -100,6 +118,9 @@ struct Paint *BKE_paint_get_active_from_context(const struct bContext *C);
 PaintMode BKE_paintmode_get_active_from_context(const struct bContext *C);
 struct Brush *BKE_paint_brush(struct Paint *paint);
 void BKE_paint_brush_set(struct Paint *paint, struct Brush *br);
+struct Palette *BKE_paint_palette(struct Paint *paint);
+void BKE_paint_palette_set(struct Paint *p, struct Palette *palette);
+void BKE_paint_curve_set(struct Brush *br, struct PaintCurve *pc);
 
 /* testing face select mode
  * Texture paint could be removed since selected faces are not used
@@ -117,7 +138,10 @@ bool paint_is_bmesh_face_hidden(struct BMFace *f);
 /* paint masks */
 float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level,
                             unsigned x, unsigned y);
+
+/* stroke related */
 void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, const float mouse_pos[2]);
+
 /* Session data (mode-specific) */
 
 typedef struct SculptSession {
index d9af6ac3454d889e602e5749e9a3deedf2b7de81..bdfaf9a1be9695cf21c71330b32935178756c097 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "DNA_cloth_types.h"
 #include "DNA_key_types.h"
+#include "DNA_material_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
@@ -501,11 +502,36 @@ void DM_update_materials(DerivedMesh *dm, Object *ob)
 
        dm->mat = MEM_callocN(totmat * sizeof(*dm->mat), "DerivedMesh.mat");
 
-       for (i = 1; i < totmat; i++) {
-               dm->mat[i] = give_current_material(ob, i);
+       /* we leave last material as empty - rationale here is being able to index
+        * the materials by using the mf->mat_nr directly and leaving the last
+        * material as NULL in case no materials exist on mesh, so indexing will not fail */
+       for (i = 0; i < totmat - 1; i++) {
+               dm->mat[i] = give_current_material(ob, i + 1);
        }
 }
 
+MTFace *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr)
+{
+       MTFace *tf_base;
+
+       BLI_assert(mat_nr < dm->totmat);
+
+       if (dm->mat[mat_nr] && dm->mat[mat_nr]->texpaintslot &&
+           dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname[0])
+       {
+               tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE,
+                                                    dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname);
+               /* This can fail if we have changed the name in the UV layer list and have assigned the old name in the material
+                        * texture slot.*/
+               if (!tf_base)
+                       tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+       }
+       else {
+               tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+       }
+
+       return tf_base;
+}
 
 void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask)
 {
@@ -3091,7 +3117,7 @@ static void navmesh_drawColored(DerivedMesh *dm)
 static void navmesh_DM_drawFacesTex(DerivedMesh *dm,
                                     DMSetDrawOptionsTex setDrawOptions,
                                     DMCompareDrawOptions compareDrawOptions,
-                                    void *userData)
+                                    void *userData, DMDrawFlag UNUSED(flag))
 {
        (void) setDrawOptions;
        (void) compareDrawOptions;
index 967e89e0dd10fdb03d5f26be64f3b01acfee7ab6..cfdb1aa7a9619d1e0de21cb4184ff17f308eddb5 100644 (file)
@@ -83,6 +83,7 @@ static void brush_defaults(Brush *brush)
        brush->plane_trim = 0.5f;
        brush->clone.alpha = 0.5f;
        brush->normal_weight = 0.0f;
+       brush->fill_threshold = 0.2f;
        brush->flag |= BRUSH_ALPHA_PRESSURE;
 
        /* BRUSH PAINT TOOL SETTINGS */
@@ -90,6 +91,8 @@ static void brush_defaults(Brush *brush)
        brush->rgb[1] = 1.0f;
        brush->rgb[2] = 1.0f;
 
+       zero_v3(brush->secondary_rgb);
+
        /* BRUSH STROKE SETTINGS */
        brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN);
        brush->spacing = 10; /* how far each brush dot should be spaced as a percentage of brush diameter */
@@ -161,6 +164,9 @@ Brush *BKE_brush_copy(Brush *brush)
        if (brush->mask_mtex.tex)
                id_us_plus((ID *)brush->mask_mtex.tex);
 
+       if (brush->paint_curve)
+               id_us_plus((ID *)brush->paint_curve);
+
        if (brush->icon_imbuf)
                brushn->icon_imbuf = IMB_dupImBuf(brush->icon_imbuf);
 
@@ -180,11 +186,9 @@ Brush *BKE_brush_copy(Brush *brush)
 /* not brush itself */
 void BKE_brush_free(Brush *brush)
 {
-       if (brush->mtex.tex)
-               brush->mtex.tex->id.us--;
-
-       if (brush->mask_mtex.tex)
-               brush->mask_mtex.tex->id.us--;
+       id_us_min((ID *)brush->mtex.tex);
+       id_us_min((ID *)brush->mask_mtex.tex);
+       id_us_min((ID *)brush->paint_curve);
 
        if (brush->icon_imbuf)
                IMB_freeImBuf(brush->icon_imbuf);
@@ -192,6 +196,9 @@ void BKE_brush_free(Brush *brush)
        BKE_previewimg_free(&(brush->preview));
 
        curvemapping_free(brush->curve);
+
+       if (brush->gradient)
+               MEM_freeN(brush->gradient);
 }
 
 static void extern_local_brush(Brush *brush)
@@ -199,6 +206,7 @@ static void extern_local_brush(Brush *brush)
        id_lib_extern((ID *)brush->mtex.tex);
        id_lib_extern((ID *)brush->mask_mtex.tex);
        id_lib_extern((ID *)brush->clone.image);
+       id_lib_extern((ID *)brush->paint_curve);
 }
 
 void BKE_brush_make_local(Brush *brush)
@@ -742,10 +750,23 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
                          rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
        }
 
+       CLAMP(intensity, 0.0f, 1.0f);
+
+       switch (br->mask_pressure) {
+               case BRUSH_MASK_PRESSURE_CUTOFF:
+                       intensity  = ((1.0f - intensity) < ups->size_pressure_value) ? 1.0f : 0.0f;
+                       break;
+               case BRUSH_MASK_PRESSURE_RAMP:
+                       intensity = ups->size_pressure_value + intensity * (1.0f - ups->size_pressure_value);
+                       break;
+               default:
+                       break;
+       }
+
        return intensity;
 }
 
-/* Unified Size and Strength */
+/* Unified Size / Strength / Color */
 
 /* XXX: be careful about setting size and unprojected radius
  * because they depend on one another
@@ -760,6 +781,29 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
  * In any case, a better solution is needed to prevent
  * inconsistency. */
 
+
+float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush)
+{
+       UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+       return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->rgb : brush->rgb;
+}
+
+float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush)
+{
+       UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+       return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->secondary_rgb : brush->secondary_rgb;
+}
+
+void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3])
+{
+       UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+
+       if (ups->flag & UNIFIED_PAINT_COLOR)
+               copy_v3_v3(ups->rgb, color);
+       else
+               copy_v3_v3(brush->rgb, color);
+}
+
 void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
 {
        UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
index 3f8edbcf1bed75a55e35f550c1d620c31da6c09e..ca4a4b3196c323e3d8560981eae7daf1870bc6c6 100644 (file)
@@ -51,6 +51,7 @@
 #include "BKE_editmesh.h"
 #include "BKE_curve.h"
 
+#include "DNA_material_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
@@ -669,7 +670,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                                      DMSetDrawOptionsTex drawParams,
                                      DMSetDrawOptions drawParamsMapped,
                                      DMCompareDrawOptions compareDrawOptions,
-                                     void *userData)
+                                     void *userData, DMDrawFlag uvflag)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
        MVert *mv = cddm->mvert;
@@ -680,6 +681,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
        MCol *mcol;
        int i, orig;
        int colType, startFace = 0;
+       bool use_tface = (uvflag & DM_DRAW_USE_ACTIVE_UV) != 0;
 
        /* double lookup */
        const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
@@ -718,14 +720,35 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
        cdDM_update_normals_from_pbvh(dm);
 
        if (GPU_buffer_legacy(dm)) {
+               int mat_nr_cache = -1;
+               MTFace *tf_base = DM_get_tessface_data_layer(dm, CD_MTFACE);
+               MTFace *tf_stencil_base = NULL;
+               MTFace *tf_stencil = NULL;
+
+               if (uvflag & DM_DRAW_USE_TEXPAINT_UV) {
+                       int stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE);
+                       tf_stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil);
+               }
+
                DEBUG_VBO("Using legacy code. cdDM_drawFacesTex_common\n");
                for (i = 0; i < dm->numTessFaceData; i++, mf++) {
                        MVert *mvert;
                        DMDrawOption draw_option;
                        unsigned char *cp = NULL;
 
+                       if (uvflag & DM_DRAW_USE_TEXPAINT_UV) {
+                               if (mf->mat_nr != mat_nr_cache) {
+                                       tf_base = DM_paint_uvlayer_active_get(dm, mf->mat_nr);
+
+                                       mat_nr_cache = mf->mat_nr;
+                               }
+                       }
+
+                       tf = tf_base ? tf_base + i : NULL;
+                       tf_stencil = tf_stencil_base ? tf_stencil_base + i : NULL;
+
                        if (drawParams) {
-                               draw_option = drawParams(tf ? &tf[i] : NULL, (mcol != NULL), mf->mat_nr);
+                               draw_option = drawParams(use_tface ? tf : NULL, (mcol != NULL), mf->mat_nr);
                        }
                        else {
                                if (index_mf_to_mpoly) {
@@ -778,21 +801,24 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                                }
 
                                glBegin(mf->v4 ? GL_QUADS : GL_TRIANGLES);
-                               if (tf) glTexCoord2fv(tf[i].uv[0]);
+                               if (tf) glTexCoord2fv(tf->uv[0]);
+                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf->uv[0]);
                                if (cp) glColor3ub(cp[3], cp[2], cp[1]);
                                mvert = &mv[mf->v1];
                                if (lnors) glNormal3sv((const GLshort *)lnors[0][0]);
                                else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no);
                                glVertex3fv(mvert->co);
 
-                               if (tf) glTexCoord2fv(tf[i].uv[1]);
+                               if (tf) glTexCoord2fv(tf->uv[1]);
+                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf->uv[1]);
                                if (cp) glColor3ub(cp[7], cp[6], cp[5]);
                                mvert = &mv[mf->v2];
                                if (lnors) glNormal3sv((const GLshort *)lnors[0][1]);
                                else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no);
                                glVertex3fv(mvert->co);
 
-                               if (tf) glTexCoord2fv(tf[i].uv[2]);
+                               if (tf) glTexCoord2fv(tf->uv[2]);
+                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf->uv[2]);
                                if (cp) glColor3ub(cp[11], cp[10], cp[9]);
                                mvert = &mv[mf->v3];
                                if (lnors) glNormal3sv((const GLshort *)lnors[0][2]);
@@ -800,7 +826,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                                glVertex3fv(mvert->co);
 
                                if (mf->v4) {
-                                       if (tf) glTexCoord2fv(tf[i].uv[3]);
+                                       if (tf) glTexCoord2fv(tf->uv[3]);
+                                       if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf->uv[3]);
                                        if (cp) glColor3ub(cp[15], cp[14], cp[13]);
                                        mvert = &mv[mf->v4];
                                        if (lnors) glNormal3sv((const GLshort *)lnors[0][3]);
@@ -819,7 +846,10 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
        else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
                GPU_vertex_setup(dm);
                GPU_normal_setup(dm);
-               GPU_uv_setup(dm);
+               if (uvflag & DM_DRAW_USE_TEXPAINT_UV)
+                       GPU_texpaint_uv_setup(dm);
+               else
+                       GPU_uv_setup(dm);
                if (mcol) {
                        GPU_color_setup(dm, colType);
                }
@@ -839,7 +869,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                                        next_actualFace = dm->drawObject->triangle_to_mface[i + 1];
 
                                if (drawParams) {
-                                       draw_option = drawParams(tf ? &tf[actualFace] : NULL, (mcol != NULL), mf[actualFace].mat_nr);
+                                       draw_option = drawParams(use_tface && tf ? &tf[actualFace] : NULL, (mcol != NULL), mf[actualFace].mat_nr);
                                }
                                else {
                                        if (index_mf_to_mpoly) {
@@ -895,9 +925,9 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
 static void cdDM_drawFacesTex(DerivedMesh *dm,
                               DMSetDrawOptionsTex setDrawOptions,
                               DMCompareDrawOptions compareDrawOptions,
-                              void *userData)
+                              void *userData, DMDrawFlag uvflag)
 {
-       cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
+       cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, uvflag);
 }
 
 static void cdDM_drawMappedFaces(DerivedMesh *dm,
@@ -1123,9 +1153,9 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm,
 static void cdDM_drawMappedFacesTex(DerivedMesh *dm,
                                     DMSetDrawOptions setDrawOptions,
                                     DMCompareDrawOptions compareDrawOptions,
-                                    void *userData)
+                                    void *userData, DMDrawFlag flag)
 {
-       cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
+       cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
 }
 
 static void cddm_draw_attrib_vertex(DMVertexAttribs *attribs, MVert *mvert, int a, int index, int vert,
index 136ca0098cb3bb1e7038ac255c570254293f7254..4fa4031382b65aadf1537d17b9e75a6f3b8bad8a 100644 (file)
@@ -2472,6 +2472,17 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
                                                BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
                }
 
+               if (ELEM(idtype, ID_MA, ID_TE)) {
+                       const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(sce);
+                       for (obt = bmain->object.first; obt; obt = obt->id.next) {
+                               if (obt->mode & OB_MODE_TEXTURE_PAINT) {
+                                       obt->recalc |= OB_RECALC_DATA;
+                                       BKE_texpaint_slots_refresh_object(obt, new_shading_nodes);
+                                       lib_id_recalc_data_tag(bmain, &obt->id);
+                               }
+                       }
+               }
+
                if (idtype == ID_MC) {
                        MovieClip *clip = (MovieClip *) id;
 
index 3a11b3431aefd284a8482024df4ce0292b0d6311..40a4bc22ce9ba02177eaa1819589a5e4d6a7ad47 100644 (file)
@@ -911,7 +911,7 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm,
 static void emDM_drawFacesTex(DerivedMesh *dm,
                               DMSetDrawOptionsTex setDrawOptions,
                               DMCompareDrawOptions compareDrawOptions,
-                              void *userData)
+                              void *userData, DMDrawFlag UNUSED(flag))
 {
        emDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
 }
@@ -919,7 +919,7 @@ static void emDM_drawFacesTex(DerivedMesh *dm,
 static void emDM_drawMappedFacesTex(DerivedMesh *dm,
                                     DMSetDrawOptions setDrawOptions,
                                     DMCompareDrawOptions compareDrawOptions,
-                                    void *userData)
+                                    void *userData, DMDrawFlag UNUSED(flag))
 {
        emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
 }
index 2e201a0b8e8c8395132a0b225bbe19dfceefbd4d..1b7a03ec80ed1fde9bdac6d17011f87a5ccc4e16 100644 (file)
@@ -73,6 +73,8 @@ static IDType idtypes[] = {
        { ID_NT,     "NodeTree",         "node_groups",     IDTYPE_FLAGS_ISLINKABLE },
        { ID_OB,     "Object",           "objects",         IDTYPE_FLAGS_ISLINKABLE },
        { ID_PA,     "ParticleSettings", "particles",       0                       },
+       { ID_PAL,    "Palettes",         "palettes",        IDTYPE_FLAGS_ISLINKABLE },
+       { ID_PC,     "PaintCurve",       "paint_curves",    IDTYPE_FLAGS_ISLINKABLE },
        { ID_SCE,    "Scene",            "scenes",          IDTYPE_FLAGS_ISLINKABLE },
        { ID_SCR,    "Screen",           "screens",         0                       },
        { ID_SEQ,    "Sequence",         "sequences",       0                       }, /* not actually ID data */
index df343459d2f6a4939283a53d6a3194838890c010..8e07564dec490c17046cd97ac38c29ba52e75892 100644 (file)
 #include "BKE_mask.h"
 #include "BKE_node.h"
 #include "BKE_object.h"
+#include "BKE_paint.h"
 #include "BKE_particle.h"
 #include "BKE_packedFile.h"
 #include "BKE_speaker.h"
@@ -515,6 +516,10 @@ ListBase *which_libbase(Main *mainlib, short type)
                        return &(mainlib->mask);
                case ID_LS:
                        return &(mainlib->linestyle);
+               case ID_PAL:
+                       return &(mainlib->palettes);
+               case ID_PC:
+                       return &(mainlib->paintcurves);
        }
        return NULL;
 }
@@ -596,6 +601,8 @@ int set_listbasepointers(Main *main, ListBase **lb)
        lb[a++] = &(main->text);
        lb[a++] = &(main->sound);
        lb[a++] = &(main->group);
+       lb[a++] = &(main->palettes);
+       lb[a++] = &(main->paintcurves);
        lb[a++] = &(main->brush);
        lb[a++] = &(main->script);
        lb[a++] = &(main->particle);
@@ -731,6 +738,12 @@ static ID *alloc_libblock_notest(short type)
                case ID_LS:
                        id = MEM_callocN(sizeof(FreestyleLineStyle), "Freestyle Line Style");
                        break;
+               case ID_PAL:
+                       id = MEM_callocN(sizeof(Palette), "Palette");
+                       break;
+               case ID_PC:
+                       id = MEM_callocN(sizeof(PaintCurve), "Paint Curve");
+                       break;
        }
        return id;
 }
@@ -1007,6 +1020,12 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
                case ID_LS:
                        BKE_linestyle_free((FreestyleLineStyle *)id);
                        break;
+               case ID_PAL:
+                       BKE_palette_free((Palette *)id);
+                       break;
+               case ID_PC:
+                       BKE_paint_curve_free((PaintCurve *)id);
+                       break;
        }
 
        /* avoid notifying on removed data */
index b8788a2bffb58fa83d4ab4c69f67bb3f78332f94..b3e0f16f6042abd6e58d02990c55bec5e7474778 100644 (file)
@@ -111,6 +111,9 @@ void BKE_material_free_ex(Material *ma, bool do_id_user)
                MEM_freeN(ma->nodetree);
        }
 
+       if (ma->texpaintslot)
+               MEM_freeN(ma->texpaintslot);
+
        if (ma->gpumaterial.first)
                GPU_material_free(ma);
 }
@@ -269,7 +272,9 @@ Material *localize_material(Material *ma)
        
        if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col);
        if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec);
-       
+
+       if (ma->texpaintslot) man->texpaintslot = MEM_dupallocN(man->texpaintslot);
+
        man->preview = NULL;
        
        if (ma->nodetree)
@@ -1301,6 +1306,114 @@ bool object_remove_material_slot(Object *ob)
        return true;
 }
 
+void BKE_texpaint_slots_clear(struct Material *ma)
+{
+
+       if (ma->texpaintslot) {
+               MEM_freeN(ma->texpaintslot);
+               ma->texpaintslot = NULL;
+       }
+       ma->tot_slots = 0;
+       ma->paint_active_slot = 0;
+       ma->paint_clone_slot = 0;
+}
+
+
+static bool get_mtex_slot_valid_texpaint(struct MTex *mtex)
+{
+       return (mtex && (mtex->texco == TEXCO_UV) &&
+               mtex->tex && (mtex->tex->type == TEX_IMAGE) &&
+               mtex->tex->ima);
+}
+
+void BKE_texpaint_slot_refresh_cache(Material *ma, bool use_nodes)
+{
+       MTex **mtex;
+       short count = 0;
+       short index = 0, i;
+
+       if (!ma)
+               return;
+
+       if (ma->texpaintslot) {
+               MEM_freeN(ma->texpaintslot);
+               ma->texpaintslot = NULL;
+       }
+
+       if (use_nodes) {
+               bNode *node, *active_node;
+
+               if (!(ma->use_nodes && ma->nodetree))
+                       return;
+
+               for (node = ma->nodetree->nodes.first; node; node = node->next) {
+                       if (node->typeinfo->nclass == NODE_CLASS_TEXTURE)
+                               count++;
+               }
+
+               ma->tot_slots = count;
+
+               if (count == 0) {
+                       ma->paint_active_slot = 0;
+                       return;
+               }
+               ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
+
+               active_node = nodeGetActiveTexture(ma->nodetree);
+
+               for (node = ma->nodetree->nodes.first; node; node = node->next) {
+                       if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
+                               if (active_node == node)
+                                       ma->paint_active_slot = index;
+                               ma->texpaintslot[index++].ima = (Image *)node->id;
+                       }
+               }
+       }
+       else {
+               for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
+                       if (get_mtex_slot_valid_texpaint(*mtex)) {
+                               count++;
+                       }
+               }
+
+               ma->tot_slots = count;
+
+               if (count == 0) {
+                       ma->paint_active_slot = 0;
+                       return;
+               }
+
+               ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
+
+               for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
+                       if (get_mtex_slot_valid_texpaint(*mtex)) {
+                               ma->texpaintslot[index].ima = (*mtex)->tex->ima;
+                               BLI_strncpy(ma->texpaintslot[index++].uvname, (*mtex)->uvname, 64);
+                       }
+               }
+       }
+
+       if (ma->paint_active_slot >= count) {
+               ma->paint_active_slot = count - 1;
+       }
+
+       if (ma->paint_clone_slot >= count) {
+               ma->paint_clone_slot = count - 1;
+       }
+
+       return;
+}
+
+void BKE_texpaint_slots_refresh_object(struct Object *ob, bool use_nodes)
+{
+       int i;
+
+       for (i = 1; i < ob->totcol + 1; i++) {
+               Material *ma = give_current_material(ob, i);
+               BKE_texpaint_slot_refresh_cache(ma, use_nodes);
+       }
+}
+
 
 /* r_col = current value, col = new value, (fac == 0) is no change */
 void ramp_blend(int type, float r_col[3], const float fac, const float col[3])
index 9a144b5461a48eaea382cd62c5baf544bdf77476..48211f2f627e7b32206c5babd151f2e70351c9f0 100644 (file)
 #include "BLI_bitmap.h"
 #include "BLI_utildefines.h"
 #include "BLI_math_vector.h"
+#include "BLI_listbase.h"
 
 #include "BKE_brush.h"
+#include "BKE_main.h"
 #include "BKE_context.h"
 #include "BKE_crazyspace.h"
 #include "BKE_depsgraph.h"
@@ -269,6 +271,105 @@ void BKE_paint_brush_set(Paint *p, Brush *br)
        }
 }
 
+void BKE_paint_curve_free(PaintCurve *pc)
+{
+       if (pc->points) {
+               MEM_freeN(pc->points);
+               pc->points = NULL;
+               pc->tot_points = 0;
+       }
+}
+
+PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
+{
+       PaintCurve *pc;
+
+       pc = BKE_libblock_alloc(bmain, ID_PC, name);
+
+       return pc;
+}
+
+Palette *BKE_paint_palette(Paint *p)
+{
+       return p ? p->palette : NULL;
+}
+
+void BKE_paint_palette_set(Paint *p, Palette *palette)
+{
+       if (p) {
+               id_us_min((ID *)p->palette);
+               id_us_plus((ID *)palette);
+               p->palette = palette;
+       }
+}
+
+void BKE_paint_curve_set(Brush *br, PaintCurve *pc)
+{
+       if (br) {
+               id_us_min((ID *)br->paint_curve);
+               id_us_plus((ID *)pc);
+               br->paint_curve = pc;
+       }
+}
+
+/* remove colour from palette. Must be certain color is inside the palette! */
+void BKE_palette_color_remove(Palette *palette, PaletteColor *color)
+{
+       BLI_remlink(&palette->colors, color);
+       BLI_addhead(&palette->deleted, color);
+}
+
+void BKE_palette_cleanup(Palette *palette)
+{
+       BLI_freelistN(&palette->deleted);
+}
+
+
+Palette *BKE_palette_add(Main *bmain, const char *name)
+{
+       Palette *palette;
+
+       palette = BKE_libblock_alloc(bmain, ID_PAL, name);
+
+       /* enable fake user by default */
+       palette->id.flag |= LIB_FAKEUSER;
+
+       return palette;
+}
+
+void BKE_palette_free(Palette *palette)
+{
+       BLI_freelistN(&palette->colors);
+}
+
+PaletteColor *BKE_palette_color_add(Palette *palette)
+{
+       PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color");
+       BLI_addtail(&palette->colors, color);
+       palette->active_color = BLI_countlist(&palette->colors) - 1;
+       return color;
+}
+
+void BKE_palette_color_delete(struct Palette *palette)
+{
+       PaletteColor *color = BLI_findlink(&palette->colors, palette->active_color);
+
+       if(color) {
+               if ((color == palette->colors.last) && (palette->colors.last != palette->colors.first))
+                       palette->active_color--;
+
+               BLI_remlink(&palette->colors, color);
+               BLI_addhead(&palette->deleted, color);
+       }
+}
+
+
+bool BKE_palette_is_empty(const struct Palette *palette)
+{
+       return BLI_listbase_is_empty(&palette->colors);
+}
+
+
 /* are we in vertex paint or weight pain face select mode? */
 bool BKE_paint_select_face_test(Object *ob)
 {
@@ -318,6 +419,7 @@ void BKE_paint_init(Paint *p, const char col[3])
 void BKE_paint_free(Paint *paint)
 {
        id_us_min((ID *)paint->brush);
+       id_us_min((ID *)paint->palette);
 }
 
 /* called when copying scene settings, so even if 'src' and 'tar' are the same
@@ -328,6 +430,7 @@ void BKE_paint_copy(Paint *src, Paint *tar)
 {
        tar->brush = src->brush;
        id_us_plus((ID *)tar->brush);
+       id_us_plus((ID *)tar->palette);
 }
 
 /* returns non-zero if any of the face's vertices
index 11dc9150d8f322bf83b6c92f1d97981d9bb1f363..79c348ac1817cc674be54c1f40ee295563254497 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "DNA_material_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 #include "DNA_modifier_types.h"
@@ -2291,18 +2292,23 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
                                       DMSetDrawOptionsTex drawParams,
                                       DMSetDrawOptions drawParamsMapped,
                                       DMCompareDrawOptions compareDrawOptions,
-                                      void *userData)
+                                      void *userData, DMDrawFlag flag)
 {
        CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
        CCGSubSurf *ss = ccgdm->ss;
        CCGKey key;
        MCol *mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL);
        MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
+       MTFace *tf_stencil_base = NULL;
+       MTFace *tf_stencil = NULL;
+       MTFace *tf_base;
        short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
        DMFlagMat *faceFlags = ccgdm->faceFlags;
        DMDrawOption draw_option;
        int i, totface, gridSize = ccgSubSurf_getGridSize(ss);
        int gridFaces = gridSize - 1;
+       int gridOffset = 0;
+       int mat_nr_cache = -1;
 
        (void) compareDrawOptions;
 
@@ -2316,6 +2322,12 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
                mcol = dm->getTessFaceDataArray(dm, CD_TEXTURE_MCOL);
 
        totface = ccgSubSurf_getNumFaces(ss);
+
+       if (flag & DM_DRAW_USE_TEXPAINT_UV) {
+               int stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE);
+               tf_stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil);
+       }
+
        for (i = 0; i < totface; i++) {
                CCGFace *f = ccgdm->faceMap[i].face;
                int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
@@ -2334,6 +2346,18 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
                        mat_nr = 0;
                }
 
+               /* texture painting, handle the correct uv layer here */
+               if (flag & DM_DRAW_USE_TEXPAINT_UV) {
+                       if (mat_nr != mat_nr_cache) {
+                               tf_base = DM_paint_uvlayer_active_get(dm, mat_nr);
+
+                               mat_nr_cache = mat_nr;
+                       }
+                       tf = tf_base + gridOffset;
+                       tf_stencil = tf_stencil_base + gridOffset;
+                       gridOffset += gridFaces * gridFaces * numVerts;
+               }
+
                if (drawParams)
                        draw_option = drawParams(tf, (mcol != NULL), mat_nr);
                else if (index != ORIGINDEX_NONE)
@@ -2374,26 +2398,31 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
                                                float *d_co = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
 
                                                if (tf) glTexCoord2fv(tf->uv[1]);
+                                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[1]);
                                                if (cp) glColor3ub(cp[7], cp[6], cp[5]);
                                                glNormal3sv(ln[0][1]);
                                                glVertex3fv(d_co);
 
                                                if (tf) glTexCoord2fv(tf->uv[2]);
+                                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[2]);
                                                if (cp) glColor3ub(cp[11], cp[10], cp[9]);
                                                glNormal3sv(ln[0][2]);
                                                glVertex3fv(c_co);
 
                                                if (tf) glTexCoord2fv(tf->uv[3]);
+                                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[3]);
                                                if (cp) glColor3ub(cp[15], cp[14], cp[13]);
                                                glNormal3sv(ln[0][3]);
                                                glVertex3fv(b_co);
 
                                                if (tf) glTexCoord2fv(tf->uv[0]);
+                                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[0]);
                                                if (cp) glColor3ub(cp[3], cp[2], cp[1]);
                                                glNormal3sv(ln[0][0]);
                                                glVertex3fv(a_co);
 
                                                if (tf) tf++;
+                                               if (tf_stencil) tf_stencil++;
                                                if (cp) cp += 16;
                                                ln++;
                                        }
@@ -2409,17 +2438,20 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
                                                b = CCG_grid_elem(&key, faceGridData, x, y + 1);
 
                                                if (tf) glTexCoord2fv(tf->uv[0]);
+                                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[0]);
                                                if (cp) glColor3ub(cp[3], cp[2], cp[1]);
                                                glNormal3fv(CCG_elem_no(&key, a));
                                                glVertex3fv(CCG_elem_co(&key, a));
 
                                                if (tf) glTexCoord2fv(tf->uv[1]);
+                                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[1]);
                                                if (cp) glColor3ub(cp[7], cp[6], cp[5]);
                                                glNormal3fv(CCG_elem_no(&key, b));
                                                glVertex3fv(CCG_elem_co(&key, b));
                                                
                                                if (x != gridFaces - 1) {
                                                        if (tf) tf++;
+                                                       if (tf_stencil) tf_stencil++;
                                                        if (cp) cp += 16;
                                                }
                                        }
@@ -2428,16 +2460,19 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
                                        b = CCG_grid_elem(&key, faceGridData, x, y + 1);
 
                                        if (tf) glTexCoord2fv(tf->uv[3]);
+                                       if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[3]);
                                        if (cp) glColor3ub(cp[15], cp[14], cp[13]);
                                        glNormal3fv(CCG_elem_no(&key, a));
                                        glVertex3fv(CCG_elem_co(&key, a));
 
                                        if (tf) glTexCoord2fv(tf->uv[2]);
+                                       if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[2]);
                                        if (cp) glColor3ub(cp[11], cp[10], cp[9]);
                                        glNormal3fv(CCG_elem_no(&key, b));
                                        glVertex3fv(CCG_elem_co(&key, b));
 
                                        if (tf) tf++;
+                                       if (tf_stencil) tf_stencil++;
                                        if (cp) cp += 16;
 
                                        glEnd();
@@ -2456,22 +2491,27 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
                                                ccgDM_glNormalFast(a_co, b_co, c_co, d_co);
 
                                                if (tf) glTexCoord2fv(tf->uv[1]);
+                                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[1]);
                                                if (cp) glColor3ub(cp[7], cp[6], cp[5]);
                                                glVertex3fv(d_co);
 
                                                if (tf) glTexCoord2fv(tf->uv[2]);
+                                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[2]);
                                                if (cp) glColor3ub(cp[11], cp[10], cp[9]);
                                                glVertex3fv(c_co);
 
                                                if (tf) glTexCoord2fv(tf->uv[3]);
+                                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[3]);
                                                if (cp) glColor3ub(cp[15], cp[14], cp[13]);
                                                glVertex3fv(b_co);
 
                                                if (tf) glTexCoord2fv(tf->uv[0]);
+                                               if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[0]);
                                                if (cp) glColor3ub(cp[3], cp[2], cp[1]);
                                                glVertex3fv(a_co);
 
                                                if (tf) tf++;
+                                               if (tf_stencil) tf_stencil++;
                                                if (cp) cp += 16;
                                        }
                                }
@@ -2484,17 +2524,17 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
 static void ccgDM_drawFacesTex(DerivedMesh *dm,
                                DMSetDrawOptionsTex setDrawOptions,
                                DMCompareDrawOptions compareDrawOptions,
-                               void *userData)
+                               void *userData, DMDrawFlag flag)
 {
-       ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
+       ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
 }
 
 static void ccgDM_drawMappedFacesTex(DerivedMesh *dm,
                                      DMSetDrawOptions setDrawOptions,
                                      DMCompareDrawOptions compareDrawOptions,
-                                     void *userData)
+                                     void *userData, DMDrawFlag flag)
 {
-       ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
+       ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
 }
 
 static void ccgDM_drawUVEdges(DerivedMesh *dm)
index 105065e85cf2a106a3468faed04d1313f9da9dd4..77f62771360f4b87475124316c7d5dd00f669113 100644 (file)
@@ -474,7 +474,8 @@ void BKE_texture_free(Tex *tex)
 
 void default_tex(Tex *tex)
 {
-       tex->type = TEX_CLOUDS;
+       tex->type = TEX_IMAGE;
+       tex->ima = NULL;
        tex->stype = 0;
        tex->flag = TEX_CHECKER_ODD;
        tex->imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA;
@@ -592,7 +593,7 @@ Tex *add_texture(Main *bmain, const char *name)
 
 void default_mtex(MTex *mtex)
 {
-       mtex->texco = TEXCO_ORCO;
+       mtex->texco = TEXCO_UV;
        mtex->mapto = MAP_COL;
        mtex->object = NULL;
        mtex->projx = PROJ_X;
index d7e9bf50eae690acca22e649630f49708a73c67b..2535a31ccc416ac775e891caa6cbb04e3128763f 100644 (file)
@@ -49,6 +49,24 @@ MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char
 MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
 MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
 MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
+
+MINLINE void blend_color_overlay_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_hardlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_burn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_linearburn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_dodge_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_screen_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_softlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_pinlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_linearlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_difference_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_exclusion_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_color_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_hue_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_saturation_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_luminosity_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+
 MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float t);
 
 MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4]);
@@ -59,6 +77,24 @@ MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const
 MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4]);
 MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], const float src2[4]);
 MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], const float src2[4]);
+
+MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_difference_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_color_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], const float src2[2]);
+MINLINE void blend_color_luminosity_float(float dst[4], const float src1[4], const float src2[2]);
+
 MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t);
 
 #if BLI_MATH_DO_INLINE
index 942097e1ed6c241564805827c39bea69f46e8919..6885a5aa35142e486c218076df89eb2b2b1e9823 100644 (file)
@@ -65,6 +65,7 @@ MINLINE void swap_v4_v4(float a[4], float b[4]);
 MINLINE void copy_v2_v2_char(char r[2], const char a[2]);
 MINLINE void copy_v3_v3_char(char r[3], const char a[3]);
 MINLINE void copy_v4_v4_char(char r[4], const char a[4]);
+
 /* short */
 MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
 MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
@@ -231,6 +232,7 @@ MINLINE bool equals_v3v3(const float a[3], const float b[3])  ATTR_WARN_UNUSED_R
 MINLINE bool compare_v2v2(const float a[2], const float b[2], const float limit)  ATTR_WARN_UNUSED_RESULT;
 MINLINE bool compare_v3v3(const float a[3], const float b[3], const float limit)  ATTR_WARN_UNUSED_RESULT;
 MINLINE bool compare_len_v3v3(const float a[3], const float b[3], const float limit)  ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_len_squared_v3v3(const float a[3], const float b[3], const float limit)  ATTR_WARN_UNUSED_RESULT;
 
 MINLINE bool compare_v4v4(const float a[4], const float b[4], const float limit)  ATTR_WARN_UNUSED_RESULT;
 MINLINE bool equals_v4v4(const float a[4], const float b[4])  ATTR_WARN_UNUSED_RESULT;
index 4810fe757faf7cd3f3b4f925917fd77c4c5311dc..1985e0611724586742c00d8230356ed57b9f6a3a 100644 (file)
 #include "BLI_math_base.h"
 #include "BLI_math_color.h"
 #include "BLI_math_color_blend.h"
+#include "BLI_math_vector.h"
 #include "BLI_utildefines.h"
 
 #ifndef __MATH_COLOR_BLEND_INLINE_C__
 #define __MATH_COLOR_BLEND_INLINE_C__
 
+/* don't add any saturation to a completly black and white image */
+#define EPS_SATURATION 0.0005f
+#define EPS_ALPHA 0.0005f
+
 /***************************** Color Blending ********************************
  *
  * - byte colors are assumed to be straight alpha
@@ -67,10 +72,7 @@ MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4_char((char *)dst, (char *)src1);
        }
 }
 
@@ -92,10 +94,7 @@ MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4_char((char *)dst, (char *)src1);
        }
 }
 
@@ -117,10 +116,7 @@ MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4_char((char *)dst, (char *)src1);
        }
 }
 
@@ -143,10 +139,7 @@ MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4_char((char *)dst, (char *)src1);
        }
 }
 
@@ -169,10 +162,7 @@ MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4_char((char *)dst, (char *)src1);
        }
 }
 
@@ -195,10 +185,7 @@ MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char s
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4_char((char *)dst, (char *)src1);
        }
 }
 
@@ -215,10 +202,7 @@ MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned c
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4_char((char *)dst, (char *)src1);
        }
 }
 
@@ -235,11 +219,547 @@ MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned cha
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+MINLINE void blend_color_overlay_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+               if (src1[0] > 127)
+                       temp = 255 - ((255 - 2 * (src1[0] - 127)) * (255 - src2[0]) / 255);
+               else
+                       temp = (2 * src1[0] * src2[0]) >> 8;
+               temp = (temp * fac + src1[0] * mfac) / 255;
+               if (temp < 255)
+                       dst[0] = temp;
+               else
+                       dst[0] = 255;
+               if (src1[1] > 127)
+                       temp = 255 - ((255 - 2 * (src1[1] - 127)) * (255 - src2[1]) / 255);
+               else
+                       temp = (2 * src1[1] * src2[1]) / 255;
+
+               temp = (temp * fac + src1[1] * mfac) / 255;
+               if (temp < 255)
+                       dst[1] = temp;
+               else
+                       dst[1] = 255;
+
+               if (src1[2] > 127)
+                       temp = 255 - ((255 - 2 * (src1[2] - 127)) * (255 - src2[2]) / 255);
+               else
+                       temp = (2 * src1[2] * src2[2]) / 255;
+
+               temp = (temp * fac + src1[2] * mfac) / 255;
+               if (temp < 255)
+                       dst[2] = temp;
+               else
+                       dst[2] = 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+
+MINLINE void blend_color_hardlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+               if (src2[0] > 127)
+                       temp = 255 - ((255 - 2 * (src2[0] - 127)) * (255 - src1[0]) / 255);
+               else
+                       temp = (2 * src2[0] * src1[0]) >> 8;
+               temp = (temp * fac + src1[0] * mfac) / 255;
+               if (temp < 255) dst[0] = temp; else dst[0] = 255;
+
+
+               if (src2[1] > 127)
+                       temp = 255 - ((255 - 2 * (src2[1] - 127)) * (255 - src1[1]) / 255);
+               else
+                       temp = (2 * src2[1] * src1[1]) / 255;
+               temp = (temp * fac + src1[1] * mfac) / 255;
+               if (temp < 255) dst[1] = temp; else dst[1] = 255;
+
+
+               if (src2[2] > 127)
+                       temp = 255 - ((255 - 2 * (src2[2] - 127)) * (255 - src1[2]) / 255);
+               else
+                       temp = (2 * src2[2] * src1[2]) / 255;
+
+               temp = (temp * fac + src1[2] * mfac) / 255;
+               if (temp < 255) dst[2] = temp; else dst[2] = 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+
+MINLINE void blend_color_burn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+
+
+               if (src2[0] == 0)
+                       temp = 0;
+               else
+                       temp = 255 - ((255 - src1[0]) * 255) / src2[0];
+               if (temp < 0)
+                       temp = 0;
+               dst[0] = (temp * fac + src1[0] * mfac) / 255;
+
+
+               if (src2[1] == 0)
+                       temp = 0;
+               else
+                       temp = 255 - ((255 - src1[1]) * 255) / src2[1];
+               if (temp < 0)
+                       temp = 0;
+               dst[1] = (temp * fac + src1[1] * mfac) / 255;
+
+
+               if (src2[2] == 0)
+                       temp = 0;
+               else
+                       temp = 255 - ((255 - src1[2]) * 255) / src2[2];
+               if (temp < 0)
+                       temp = 0;
+               dst[2] = (temp * fac + src1[2] * mfac) / 255;
+
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+
+MINLINE void blend_color_linearburn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+
+               temp = src1[0] + src2[0] - 255;
+               if (temp < 0) temp = 0;
+               dst[0] = (temp * fac + src1[0] * mfac) / 255;
+
+               temp = src1[1] + src2[1] - 255;
+               if (temp < 0) temp = 0;
+               dst[1] = (temp * fac + src1[1] * mfac) / 255;
+
+               temp = src1[2] + src2[2] - 255;
+               if (temp < 0) temp = 0;
+               dst[2] = (temp * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+
+MINLINE void blend_color_dodge_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+
+               if (src2[0] == 255) temp = 255;
+               else temp = (src1[0] * 255) / (255 - src2[0]);
+               if (temp > 255) temp = 255;
+               dst[0] = (temp * fac + src1[0] * mfac) / 255;
+
+               if (src2[1] == 255) temp = 255;
+               else temp = (src1[1] * 255) / (255 - src2[1]);
+               if (temp > 255) temp = 255;
+               dst[1] = (temp * fac + src1[1] * mfac) / 255;
+
+               if (src2[2] == 255) temp = 255;
+               else temp = (src1[2] * 255) / (255 - src2[2]);
+               if (temp > 255) temp = 255;
+               dst[2] = (temp * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+MINLINE void blend_color_screen_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+
+               temp = 255 - (((255 - src1[0]) * (255 - src2[0])) / 255);
+               if (temp < 0) temp = 0;
+               dst[0] = (temp * fac + src1[0] * mfac) / 255;
+
+               temp = 255 - (((255 - src1[1]) * (255 - src2[1])) / 255);
+               if (temp < 0) temp = 0;
+               dst[1] = (temp * fac + src1[1] * mfac) / 255;
+
+               temp = 255 - (((255 - src1[2]) * (255 - src2[2])) / 255);
+               if (temp < 0) temp = 0;
+               dst[2] = (temp * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+
+MINLINE void blend_color_softlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+
+               temp = ((unsigned char)((src1[0] < 127) ? ((2 * ((src2[0] / 2) + 64)) * (src1[0])) / 255 : (255 - (2 * (255 - ((src2[0] / 2) + 64)) * (255 - src1[0]) / 255))));
+               dst[0] = (temp * fac + src1[0] * mfac) / 255;
+
+               temp = ((unsigned char)((src1[1] < 127) ? ((2 * ((src2[1] / 2) + 64)) * (src1[1])) / 255 : (255 - (2 * (255 - ((src2[1] / 2) + 64)) * (255 - src1[1]) / 255))));
+               dst[1] = (temp * fac + src1[1] * mfac) / 255;
+
+               temp = ((unsigned char)((src1[2] < 127) ? ((2 * ((src2[2] / 2) + 64)) * (src1[2])) / 255 : (255 - (2 * (255 - ((src2[2] / 2) + 64)) * (255 - src1[2]) / 255))));
+               dst[2] = (temp * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+
+MINLINE void blend_color_pinlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+
+               if (src2[0] > 127) {
+                       temp = 2 * (src2[0] - 127);
+                       if (src1[0] > temp)
+                               temp = src1[0];
+               }
+               else {
+                       temp = 2 * src2[0];
+                       if (src1[0] < temp)
+                               temp = src1[0];
+               }
+
+               dst[0] = (temp * fac + src1[0] * mfac) / 255;
+
+
+               if (src2[1] > 127) {
+                       temp = 2 * (src2[1] - 127);
+                       if (src1[1] > temp) temp = src1[1];
+               }
+               else {
+                       temp = 2 * src2[1];
+                       if (src1[1] < temp) temp = src1[1];
+               }
+
+               dst[1] = (temp * fac + src1[1] * mfac) / 255;
+
+
+               if (src2[2] > 127) {
+                       temp = 2 * (src2[2] - 127);
+                       if (src1[2] > temp) temp = src1[2];
+               }
+               else {
+                       temp = 2 * src2[2];
+                       if (src1[2] < temp) temp = src1[2];
+               }
+               dst[2] = (temp * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+
+MINLINE void blend_color_linearlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+
+               if (src2[0] > 127) {
+                       temp = src1[0] + 2 * (src2[0] - 127);
+                       if (temp > 255)
+                               temp = 255;
+               }
+               else {
+                       temp = src1[0] + 2 * src2[0] - 255;
+                       if (temp < 0) temp = 0;
+               }
+               dst[0] = (temp * fac + src1[0] * mfac) / 255;
+
+               if (src2[1] > 127) {
+                       temp = src1[1] + 2 * (src2[1] - 127);
+                       if (temp > 255)
+                               temp = 255;
+               }
+               else {
+                       temp = src1[1] + 2 * src2[1] - 255;
+                       if (temp < 0) temp = 0;
+               }
+               dst[1] = (temp * fac + src1[1] * mfac) / 255;
+
+               if (src2[2] > 127) {
+                       temp = src1[2] + 2 * (src2[2] - 127);
+                       if (temp > 255)
+                               temp = 255;
+               }
+               else {
+                       temp = src1[2] + 2 * src2[2] - 255;
+                       if (temp < 0) temp = 0;
+               }
+               dst[2] = (temp * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+
+MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+
+               if (src2[0] == 255)
+                       temp = 255;
+               else if (src2[0] == 0)
+                       temp = 0;
+               else if (src2[0] > 127)  {
+                       temp = ((src1[0]) * 255) / (2 * (255 - src2[0]));
+                       if (temp > 255) temp = 255;
+               }
+               else {
+                       temp = 255 - ((255 - src1[0]) * 255 / (2 * src2[0]));
+                       if (temp < 0) temp = 0;
+               }
+
+               dst[0] = (temp * fac + src1[0] * mfac) / 255;
+
+               if (src2[1] == 255)
+                       temp = 255;
+               else if (src2[1] == 0)
+                       temp = 0;
+               else if (src2[1] > 127)  {
+                       temp = ((src1[1]) * 255) / (2 * (255 - src2[1]));
+                       if (temp > 255) temp = 255;
+               }
+               else {
+                       temp = 255 - ((255 - src1[1]) * 255 / (2 * src2[1]));
+                       if (temp < 0) temp = 0;
+               }
+
+               dst[1] = (temp * fac + src1[1] * mfac) / 255;
+
+               if (src2[2] == 255)
+                       temp = 255;
+               else if (src2[2] == 0)
+                       temp = 0;
+               else if (src2[2] > 127)  {
+                       temp = ((src1[2]) * 255) / (2 * (255 - src2[2]));
+                       if (temp > 255) temp = 255;
+               }
+               else {
+                       temp = 255 - ((255 - src1[2]) * 255 / (2 * src2[2]));
+                       if (temp < 0) temp = 0;
+               }
+
+               dst[2] = (temp * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+
+
+MINLINE void blend_color_difference_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+               temp = src1[0] - src2[0];
+               if (temp < 0) temp = -temp;
+               dst[0] = (temp * fac + src1[0] * mfac) / 255;
+
+               temp = src1[1] - src2[1];
+               if (temp < 0) temp = -temp;
+               dst[1] = (temp * fac + src1[1] * mfac) / 255;
+
+               temp = src1[2] - src2[2];
+               if (temp < 0) temp = -temp;
+               dst[2] = (temp * fac + src1[2] * mfac) / 255;
+
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+
+MINLINE void blend_color_exclusion_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int temp;
+               int mfac = 255 - fac;
+               temp = 127 - ((2 * (src1[0] - 127) * (src2[0] - 127)) / 255);
+               dst[0] = (temp * fac + src1[0] * mfac) / 255;
+
+               temp = 127 - ((2 * (src1[1] - 127) * (src2[1] - 127)) / 255);
+               dst[1] = (temp * fac + src1[1] * mfac) / 255;
+
+               temp = 127 - ((2 * (src1[2] - 127) * (src2[2] - 127)) / 255);
+               dst[2] = (temp * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+MINLINE void blend_color_color_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int mfac = 255 - fac;
+               float h1, s1, v1;
+               float h2, s2, v2;
+               float r, g, b;
+               rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
+               rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
+
+
+               h1 = h2;
+               s1 = s2;
+
+               hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+               dst[0] = ((int)(r * 255.0f) * fac + src1[0] * mfac) / 255;
+               dst[1] = ((int)(g * 255.0f) * fac + src1[1] * mfac) / 255;
+               dst[2] = ((int)(b * 255.0f) * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+MINLINE void blend_color_hue_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int mfac = 255 - fac;
+               float h1, s1, v1;
+               float h2, s2, v2;
+               float r, g, b;
+               rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
+               rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
+
+
+               h1 = h2;
+
+               hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+               dst[0] = ((int)(r * 255.0f) * fac + src1[0] * mfac) / 255;
+               dst[1] = ((int)(g * 255.0f) * fac + src1[1] * mfac) / 255;
+               dst[2] = ((int)(b * 255.0f) * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+
+}
+
+MINLINE void blend_color_saturation_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int mfac = 255 - fac;
+               float h1, s1, v1;
+               float h2, s2, v2;
+               float r, g, b;
+               rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
+               rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
+
+               if (s1 > EPS_SATURATION) {
+                       s1 = s2;
+               }
+
+               hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+               dst[0] = ((int)(r * 255.0f) * fac + src1[0] * mfac) / 255;
+               dst[1] = ((int)(g * 255.0f) * fac + src1[1] * mfac) / 255;
+               dst[2] = ((int)(b * 255.0f) * fac + src1[2] * mfac) / 255;
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
+       }
+}
+
+MINLINE void blend_color_luminosity_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+       const unsigned char fac = src2[3];
+       if (fac != 0) {
+               int mfac = 255 - fac;
+               float h1, s1, v1;
+               float h2, s2, v2;
+               float r, g, b;
+               rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
+               rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
+
+
+               v1 = v2;
+
+               hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+               dst[0] = ((int)(r * 255.0f) * fac + src1[0] * mfac) / 255;
+               dst[1] = ((int)(g * 255.0f) * fac + src1[1] * mfac) / 255;
+               dst[2] = ((int)(b * 255.0f) * fac + src1[2] * mfac) / 255;
+
+       }
+       else {
+               /* no op */
+               copy_v4_v4_char((char *)dst, (char *)src1);
        }
+
 }
 
 MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float ft)
@@ -257,10 +777,7 @@ MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned c
                dst[3] = (unsigned char)divide_round_i(tmp, 255);
        }
        else {
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4_char((char *)dst, (char *)src1);
        }
 }
 
@@ -280,10 +797,7 @@ MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const floa
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4(dst, src1);
        }
 }
 
@@ -298,10 +812,7 @@ MINLINE void blend_color_add_float(float dst[4], const float src1[4], const floa
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4(dst, src1);
        }
 }
 
@@ -316,10 +827,7 @@ MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const floa
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4(dst, src1);
        }
 }
 
@@ -337,10 +845,7 @@ MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const floa
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4(dst, src1);
        }
 }
 
@@ -360,10 +865,7 @@ MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4(dst, src1);
        }
 }
 
@@ -383,10 +885,7 @@ MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const f
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4(dst, src1);
        }
 }
 
@@ -397,8 +896,9 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co
                float alpha = max_ff(src1[3] - src2[3], 0.0f);
                float map_alpha;
 
-               if (alpha <= 0.0005f)
+               if (alpha <= EPS_ALPHA) {
                        alpha = 0.0f;
+               }
 
                map_alpha = alpha / src1[3];
 
@@ -409,10 +909,7 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4(dst, src1);
        }
 }
 
@@ -423,8 +920,9 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons
                float alpha = min_ff(src1[3] + src2[3], 1.0f);
                float map_alpha;
 
-               if (alpha >= 1.0f - 0.0005f)
+               if (alpha >= 1.0f - EPS_ALPHA) {
                        alpha = 1.0f;
+               }
 
                map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f;
 
@@ -435,13 +933,543 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons
        }
        else {
                /* no op */
-               dst[0] = src1[0];
-               dst[1] = src1[1];
-               dst[2] = src1[2];
-               dst[3] = src1[3];
+               copy_v4_v4(dst, src1);
+       }
+}
+
+MINLINE void blend_color_overlay_float(float dst[3], const float src1[3], const float src2[3])
+{
+       float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+
+               float temp;
+               float fac = src2[3];
+               float mfac = 1.0f - fac;
+
+               if (src1[0] > 0.5f)
+                       temp = 1 - (1 - 2 * (src1[0] - 0.5f)) * (1 - src2[0]);
+               else
+                       temp = 2 * src1[0] * src2[0];
+               temp = temp * fac + src1[0] * mfac;
+               if (temp < 1.0f)
+                       dst[0] = temp;
+               else
+                       dst[0] = 1.0f;
+
+
+               if (src1[1] > 0.5f)
+                       temp = 1.0f - (1.0f - 2.0f * (src1[1] - 0.5f)) * (1.0f - src2[1]);
+               else
+                       temp = 2.0f * src1[1] * src2[1];
+               temp = temp * fac + src1[1] * mfac;
+               if (temp < 1.0f)
+                       dst[1] = temp;
+               else
+                       dst[1] = 1.0f;
+
+               if (src1[2] > 0.5f)
+                       temp = 1 - (1.0f - 2.0f * (src1[2] - 0.5f)) * (1.0f - src2[2]);
+               else
+                       temp = 2.0f * src1[2] * src2[2];
+               temp = temp * fac + src1[2] * mfac;
+               if (temp < 1.0f)
+                       dst[2] = temp;
+               else
+                       dst[2] = 1.0f;
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+
+MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[2])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+               if (src2[0] > 0.5f)
+                       temp = 1 - ((1.0f - 2.0f * (src2[0] - 0.5f)) * (1.0f - src1[0]));
+               else
+                       temp = 2.0f * src2[0] * src1[0];
+               temp = (temp * fac + src1[0] * mfac) / 1.0f;
+               if (temp < 1.0f) dst[0] = temp; else dst[0] = 1.0f;
+
+               if (src2[1] > 0.5f)
+                       temp = 1 - ((1.0f - 2.0f * (src2[1] - 0.5f)) * (1.0f - src1[1]));
+               else
+                       temp = 2.0f * src2[1] * src1[1];
+               temp = (temp * fac + src1[1] * mfac) / 1.0f;
+               if (temp < 1.0f) dst[1] = temp; else dst[1] = 1.0f;
+
+               if (src2[2] > 0.5f)
+                       temp = 1 - ((1.0f - 2.0f * (src2[2] - 0.5f)) * (1.0f - src1[2]));
+               else
+                       temp = 2.0f * src2[2] * src1[2];
+               temp = (temp * fac + src1[2] * mfac) / 1.0f;
+
+               if (temp < 1.0f)
+                       dst[2] = temp;
+               else
+                       dst[2] = 1.0f;
+
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+MINLINE void blend_color_burn_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+
+               if (src2[0] == 0.0f)
+                       temp = 0.0f;
+               else
+                       temp = 1.0f - ((1.0f - src1[0]) / src2[0]);
+               if (temp < 0.0f)
+                       temp = 0.0f;
+               dst[0] = (temp * fac + src1[0] * mfac);
+
+               if (src2[1] == 0.0f)
+                       temp = 0.0f;
+               else
+                       temp = 1.0f - ((1.0f - src1[1]) / src2[1]);
+               if (temp < 0.0f)
+                       temp = 0.0f;
+               dst[1] = (temp * fac + src1[1] * mfac);
+
+               if (src2[2] == 0.0f)
+                       temp = 0.0f;
+               else
+                       temp = 1.0f - ((1.0f - src1[2]) / src2[2]);
+               if (temp < 0.0f)
+                       temp = 0.0f;
+               dst[2] = (temp * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
        }
 }
 
+MINLINE void blend_color_linearburn_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+
+               temp = src1[0] + src2[0] - 1.0f;
+               if (temp < 0) temp = 0;
+               dst[0] = (temp * fac + src1[0] * mfac);
+
+               temp = src1[1] + src2[1] - 1.0f;
+               if (temp < 0) temp = 0;
+               dst[1] = (temp * fac + src1[1] * mfac);
+
+               temp = src1[2] + src2[2] - 1.0f;
+               if (temp < 0) temp = 0;
+               dst[2] = (temp * fac + src1[2] * mfac);
+
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+
+MINLINE void blend_color_dodge_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+
+               if (src2[0] >= 1.0f) temp = 1.0f;
+               else temp = (src1[0]) / (1.0f - src2[0]);
+               if (temp > 1.0f) temp = 1.0f;
+               dst[0] = (temp * fac + src1[0] * mfac);
+
+               if (src2[1] >= 1.0f) temp = 1.0f;
+               else temp = (src1[1]) / (1.0f - src2[1]);
+               if (temp > 1.0f) temp = 1.0f;
+               dst[1] = (temp * fac + src1[1] * mfac);
+
+               if (src2[2] >= 1.0f) temp = 1.0f;
+               else temp = (src1[2]) / (1.0f - src2[2]);
+               if (temp > 1.0f) temp = 1.0f;
+               dst[2] = (temp * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+MINLINE void blend_color_screen_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+
+               temp = 1.0f - ((1.0f - src1[0]) * (1.0f - src2[0]));
+               if (temp < 0) temp = 0;
+               dst[0] = (temp * fac + src1[0] * mfac);
+
+               temp = 1.0f - ((1.0f - src1[1]) * (1.0f - src2[1]));
+               if (temp < 0) temp = 0;
+               dst[1] = (temp * fac + src1[1] * mfac);
+
+               temp = 1.0f - ((1.0f - src1[2]) * (1.0f - src2[2]));
+               if (temp < 0) temp = 0;
+               dst[2] = (temp * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+MINLINE void blend_color_softlight_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+
+               temp = (((src1[0] < 0.5f) ? ((src2[0] + 0.5f) * (src1[0])) : (1.0f - ((1.0f - ((src2[0]) + 0.5f)) * (1.0f - src1[0])))));
+               dst[0] = (temp * fac + src1[0] * mfac);
+
+               temp = (((src1[1] < 0.5f) ? ((src2[1] + 0.5f) * (src1[1])) : (1.0f - ((1.0f - ((src2[1]) + 0.5f)) * (1.0f - src1[1])))));
+               dst[1] = (temp * fac + src1[1] * mfac);
+
+               temp = (((src1[2] < 0.5f) ? ((src2[2] + 0.5f) * (src1[2])) : (1.0f - ((1.0f - ((src2[2]) + 0.5f)) * (1.0f - src1[2])))));
+               dst[2] = (temp * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+MINLINE void blend_color_pinlight_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+
+               if (src2[0] > 0.5f) {
+                       temp = 2 * (src2[0] - 0.5f);
+                       if (src1[0] > temp)
+                               temp = src1[0];
+               }
+               else {
+                       temp = 2 * src2[0];
+                       if (src1[0] < temp)
+                               temp = src1[0];
+               }
+
+               dst[0] = (temp * fac + src1[0] * mfac);
+
+
+               if (src2[1] > 0.5f) {
+                       temp = 2 * (src2[1] - 0.5f);
+                       if (src1[1] > temp) temp = src1[1];
+               }
+               else {
+                       temp = 2 * src2[1];
+                       if (src1[1] < temp) temp = src1[1];
+               }
+
+               dst[1] = (temp * fac + src1[1] * mfac);
+
+
+               if (src2[2] > 0.5f) {
+                       temp = 2 * (src2[2] - 0.5f);
+                       if (src1[2] > temp) temp = src1[2];
+               }
+               else {
+                       temp = 2 * src2[2];
+                       if (src1[2] < temp) temp = src1[2];
+               }
+               dst[2] = (temp * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+
+MINLINE void blend_color_linearlight_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+
+               if (src2[0] > 0.5f) {
+                       temp = src1[0] + 2 * (src2[0] - 0.5f);
+                       if (temp > 1.0f)
+                               temp = 1.0f;
+               }
+               else {
+                       temp = src1[0] + 2 * src2[0] - 1.0f;
+                       if (temp < 0) temp = 0;
+               }
+               dst[0] = (temp * fac + src1[0] * mfac);
+
+               if (src2[1] > 0.5f) {
+                       temp = src1[1] + 2 * (src2[1] - 0.5f);
+                       if (temp > 1.0f)
+                               temp = 1.0f;
+               }
+               else {
+                       temp = src1[1] + 2 * src2[1] - 1.0f;
+                       if (temp < 0) temp = 0;
+               }
+               dst[1] = (temp * fac + src1[1] * mfac);
+
+               if (src2[2] > 0.5f) {
+                       temp = src1[2] + 2 * (src2[2] - 0.5f);
+                       if (temp > 1.0f)
+                               temp = 1.0f;
+               }
+               else {
+                       temp = src1[2] + 2 * src2[2] - 1.0f;
+                       if (temp < 0) temp = 0;
+               }
+               dst[2] = (temp * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+
+MINLINE void blend_color_vividlight_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+
+               if (src2[0] == 1.0f)
+                       temp = 1.0f;
+               else if (src2[0] == 0)
+                       temp = 0;
+               else if (src2[0] > 0.5f) {
+                       temp = ((src1[0]) * 1.0f) / (2 * (1.0f - src2[0]));
+                       if (temp > 1.0f) temp = 1.0f;
+               }
+               else {
+                       temp = 1.0f - ((1.0f - src1[0]) * 1.0f / (2 * src2[0]));
+                       if (temp < 0) temp = 0;
+               }
+
+               dst[0] = (temp * fac + src1[0] * mfac);
+
+               if (src2[1] == 1.0f)
+                       temp = 1.0f;
+               else if (src2[1] == 0)
+                       temp = 0;
+               else if (src2[1] > 0.5f) {
+                       temp = ((src1[1]) * 1.0f) / (2 * (1.0f - src2[1]));
+                       if (temp > 1.0f) temp = 1.0f;
+               }
+               else {
+                       temp = 1.0f - ((1.0f - src1[1]) * 1.0f / (2 * src2[1]));
+                       if (temp < 0) temp = 0;
+               }
+
+               dst[1] = (temp * fac + src1[1] * mfac);
+
+               if (src2[2] == 1.0f)
+                       temp = 1.0f;
+               else if (src2[2] == 0)
+                       temp = 0;
+               else if (src2[2] > 0.5f) {
+                       temp = ((src1[2]) * 1.0f) / (2 * (1.0f - src2[2]));
+                       if (temp > 1.0f) temp = 1.0f;
+               }
+               else {
+                       temp = 1.0f - ((1.0f - src1[2]) * 1.0f / (2 * src2[2]));
+                       if (temp < 0) temp = 0;
+               }
+
+               dst[2] = (temp * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+MINLINE void blend_color_difference_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+               temp = src1[0] - src2[0];
+               if (temp < 0) temp = -temp;
+               dst[0] = (temp * fac + src1[0] * mfac);
+
+               temp = src1[1] - src2[1];
+               if (temp < 0) temp = -temp;
+               dst[1] = (temp * fac + src1[1] * mfac);
+
+               temp = src1[2] - src2[2];
+               if (temp < 0) temp = -temp;
+               dst[2] = (temp * fac + src1[2] * mfac);
+
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+
+MINLINE void blend_color_exclusion_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float temp;
+               float mfac = 1.0f - fac;
+               temp = 0.5f - ((2 * (src1[0] - 0.5f) * (src2[0] - 0.5f)));
+               dst[0] = (temp * fac + src1[0] * mfac);
+
+               temp = 0.5f - ((2 * (src1[1] - 0.5f) * (src2[1] - 0.5f)));
+               dst[1] = (temp * fac + src1[1] * mfac);
+
+               temp = 0.5f - ((2 * (src1[2] - 0.5f) * (src2[2] - 0.5f)));
+               dst[2] = (temp * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+
+}
+
+MINLINE void blend_color_color_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float mfac = 1.0f - fac;
+               float h1, s1, v1;
+               float h2, s2, v2;
+               float r, g, b;
+               rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
+               rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
+
+
+               h1 = h2;
+               s1 = s2;
+
+               hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+               dst[0] = (r * fac + src1[0] * mfac);
+               dst[1] = (g * fac + src1[1] * mfac);
+               dst[2] = (b * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+
+MINLINE void blend_color_hue_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float mfac = 1.0f - fac;
+               float h1, s1, v1;
+               float h2, s2, v2;
+               float r, g, b;
+               rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
+               rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
+
+
+               h1 = h2;
+
+               hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+               dst[0] = (r * fac + src1[0] * mfac);
+               dst[1] = (g * fac + src1[1] * mfac);
+               dst[2] = (b * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+MINLINE void blend_color_saturation_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float mfac = 1.0f - fac;
+               float h1, s1, v1;
+               float h2, s2, v2;
+               float r, g, b;
+               rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
+               rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
+
+               if (s1 > EPS_SATURATION) {
+                       s1 = s2;
+               }
+               hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+               dst[0] = (r * fac + src1[0] * mfac);
+               dst[1] = (g * fac + src1[1] * mfac);
+               dst[2] = (b * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+MINLINE void blend_color_luminosity_float(float dst[3], const float src1[3], const float src2[3])
+{
+       const float fac = src2[3];
+       if (fac != 0.0f && fac < 1.0f) {
+               float mfac = 1.0f - fac;
+               float h1, s1, v1;
+               float h2, s2, v2;
+               float r, g, b;
+               rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
+               rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
+
+
+               v1 = v2;
+               hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+               dst[0] = (r * fac + src1[0] * mfac);
+               dst[1] = (g * fac + src1[1] * mfac);
+               dst[2] = (b * fac + src1[2] * mfac);
+       }
+       else {
+               /* no op */
+               copy_v4_v4(dst, src1);
+       }
+}
+
+
 MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t)
 {
        /* interpolation, colors are premultiplied so it goes fine */
@@ -453,4 +1481,7 @@ MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], co
        dst[3] = mt * src1[3] + t * src2[3];
 }
 
+#undef EPS_SATURATION
+#undef EPS_ALPHA
+
 #endif /* __MATH_COLOR_BLEND_INLINE_C__ */
index 419f72b5fd6762ea91e680d6c57d60fc575dc82b..d5eebdb12d29be6533fc0d15151819f2c681a09b 100644 (file)
@@ -1824,6 +1824,7 @@ static void lib_link_brush(FileData *fd, Main *main)
                        brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
                        brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex);
                        brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image);
+                       brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve);
                }
        }
 }
@@ -1834,6 +1835,8 @@ static void direct_link_brush(FileData *fd, Brush *brush)
 
        /* fallof curve */
        brush->curve = newdataadr(fd, brush->curve);
+       brush->gradient = newdataadr(fd, brush->gradient);
+
        if (brush->curve)
                direct_link_curvemapping(fd, brush->curve);
        else
@@ -1843,6 +1846,43 @@ static void direct_link_brush(FileData *fd, Brush *brush)
        brush->icon_imbuf = NULL;
 }
 
+/* ************ READ Palette *************** */
+static void lib_link_palette(FileData *UNUSED(fd), Main *main)
+{
+       Palette *palette;
+
+       /* only link ID pointers */
+       for (palette = main->palettes.first; palette; palette = palette->id.next) {
+               if (palette->id.flag & LIB_NEED_LINK) {
+                       palette->id.flag -= LIB_NEED_LINK;
+               }
+       }
+}
+
+static void direct_link_palette(FileData *fd, Palette *palette)
+{
+       /* palette itself has been read */
+       link_list(fd, &palette->colors);
+}
+
+static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main)
+{
+       PaintCurve *pc;
+
+       /* only link ID pointers */
+       for (pc = main->paintcurves.first; pc; pc = pc->id.next) {
+               if (pc->id.flag & LIB_NEED_LINK) {
+                       pc->id.flag -= LIB_NEED_LINK;
+               }
+       }
+}
+
+static void direct_link_paint_curve(FileData *fd, PaintCurve *pc)
+{
+       pc->points = newdataadr(fd, pc->points);
+}
+
+
 static void direct_link_script(FileData *UNUSED(fd), Script *script)
 {
        script->id.us = 1;
@@ -3516,7 +3556,8 @@ static void direct_link_material(FileData *fd, Material *ma)
        for (a = 0; a < MAX_MTEX; a++) {
                ma->mtex[a] = newdataadr(fd, ma->mtex[a]);
        }
-       
+       ma->texpaintslot = NULL;
+
        ma->ramp_col = newdataadr(fd, ma->ramp_col);
        ma->ramp_spec = newdataadr(fd, ma->ramp_spec);
        
@@ -5059,6 +5100,7 @@ static void link_paint(FileData *fd, Scene *sce, Paint *p)
 {
        if (p) {
                p->brush = newlibadr_us(fd, sce->id.lib, p->brush);
+               p->palette = newlibadr_us(fd, sce->id.lib, p->palette);
                p->paint_cursor = NULL;
        }
 }
@@ -5107,6 +5149,10 @@ static void lib_link_scene(FileData *fd, Main *main)
                                sce->toolsettings->sculpt->gravity_object =
                                                newlibadr_us(fd, sce->id.lib, sce->toolsettings->sculpt->gravity_object);
 
+                       if (sce->toolsettings->imapaint.stencil)
+                               sce->toolsettings->imapaint.stencil =
+                                       newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.stencil);
+
                        sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
                        
                        for (base = sce->base.first; base; base = next) {
@@ -7138,6 +7184,8 @@ static const char *dataname(short id_code)
                case ID_NT: return "Data from NT";
                case ID_BR: return "Data from BR";
                case ID_PA: return "Data from PA";
+               case ID_PAL: return "Data from PAL";
+               case ID_PC: return "Data from PCRV";
                case ID_GD: return "Data from GD";
                case ID_WM: return "Data from WM";
                case ID_MC: return "Data from MC";
@@ -7323,6 +7371,12 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
                case ID_LS:
                        direct_link_linestyle(fd, (FreestyleLineStyle *)id);
                        break;
+               case ID_PAL:
+                       direct_link_palette(fd, (Palette *)id);
+                       break;
+               case ID_PC:
+                       direct_link_paint_curve(fd, (PaintCurve *)id);
+                       break;
        }
        
        oldnewmap_free_unused(fd->datamap);
@@ -7511,6 +7565,8 @@ static void lib_link_all(FileData *fd, Main *main)
        lib_link_vfont(fd, main);
        lib_link_nodetree(fd, main);    /* has to be done after scene/materials, this will verify group nodes */
        lib_link_brush(fd, main);
+       lib_link_palette(fd, main);
+       lib_link_paint_curve(fd, main);
        lib_link_particlesettings(fd, main);
        lib_link_movieclip(fd, main);
        lib_link_mask(fd, main);
@@ -8050,6 +8106,7 @@ static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
        expand_doit(fd, mainvar, brush->mtex.tex);
        expand_doit(fd, mainvar, brush->mask_mtex.tex);
        expand_doit(fd, mainvar, brush->clone.image);
+       expand_doit(fd, mainvar, brush->paint_curve);
 }
 
 static void expand_material(FileData *fd, Main *mainvar, Material *ma)
index dde16c8d44f711e866e849f4a2f20445b67d446c..be6f985d7012fe2cfa492fe64412da18c5ac83b5 100644 (file)
@@ -34,6 +34,7 @@
 /* allow readfile to use deprecated functionality */
 #define DNA_DEPRECATED_ALLOW
 
+#include "DNA_brush_types.h"
 #include "DNA_constraint_types.h"
 #include "DNA_sdna_types.h"
 #include "DNA_space_types.h"
@@ -309,6 +310,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
                                mat->line_col[3] = mat->alpha;
                        }
                }
+
+               if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) {
+                       Scene *scene;
+                       for (scene = main->scene.first; scene; scene = scene->id.next) {
+                               scene->r.preview_start_resolution = 64;
+                       }
+               }
        }
 
        if (!MAIN_VERSION_ATLEAST(main, 271, 2)) {
@@ -334,6 +342,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
                }
        }
 
+       if (!MAIN_VERSION_ATLEAST(main, 271, 3)) {
+               Scene *sce;
+               Brush *br;
+
+               for (sce = main->scene.first; sce; sce = sce->id.next) {
+                       sce->toolsettings->imapaint.slot_xresolution_default = 1024;
+                       sce->toolsettings->imapaint.slot_yresolution_default = 1024;
+               }
+
+               for (br = main->brush.first; br; br = br->id.next) {
+                       br->fill_threshold = 0.2f;
+               }
+       }
+
        if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) {
                Scene *scene;
                for (scene = main->scene.first; scene; scene = scene->id.next) {
index 759e17295bc259c0c151787daeb57912888a8851..13fa6f65d0cff64acab5b402cd06cf739b9087f0 100644 (file)
@@ -2924,6 +2924,38 @@ static void write_brushes(WriteData *wd, ListBase *idbase)
                        
                        if (brush->curve)
                                write_curvemapping(wd, brush->curve);
+                       if (brush->curve)
+                               writestruct(wd, DATA, "ColorBand", 1, brush->gradient);
+               }
+       }
+}
+
+static void write_palettes(WriteData *wd, ListBase *idbase)
+{
+       Palette *palette;
+
+       for (palette = idbase->first; palette; palette = palette->id.next) {
+               if (palette->id.us > 0 || wd->current) {
+                       PaletteColor *color;
+                       writestruct(wd, ID_PAL, "Palette", 1, palette);
+                       if (palette->id.properties) IDP_WriteProperty(palette->id.properties, wd);
+
+                       for (color = palette->colors.first; color; color= color->next)
+                               writestruct(wd, DATA, "PaletteColor", 1, color);
+               }
+       }
+}
+
+static void write_paintcurves(WriteData *wd, ListBase *idbase)
+{
+       PaintCurve *pc;
+
+       for (pc = idbase->first; pc; pc = pc->id.next) {
+               if (pc->id.us > 0 || wd->current) {
+                       writestruct(wd, ID_PC, "PaintCurve", 1, pc);
+
+                       writestruct(wd, DATA, "PaintCurvePoint", pc->tot_points, pc->points);
+                       if (pc->id.properties) IDP_WriteProperty(pc->id.properties, wd);
                }
        }
 }
@@ -3399,6 +3431,8 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil
        write_particlesettings(wd, &mainvar->particle);
        write_nodetrees(wd, &mainvar->nodetree);
        write_brushes  (wd, &mainvar->brush);
+       write_palettes (wd, &mainvar->palettes);
+       write_paintcurves (wd, &mainvar->paintcurves);
        write_scripts  (wd, &mainvar->script);
        write_gpencils (wd, &mainvar->gpencil);
        write_linestyles(wd, &mainvar->linestyle);
index 3fc6e2e6f0d49c4d331f96b18e997c36451e494e..2a84ca7f2973aa59c3bac0602f599469fbbdb216 100644 (file)
@@ -93,6 +93,8 @@ if(WITH_BLENDER)
                data_to_c_simple(../../../../release/datafiles/brushicons/soften.png SRC)
                data_to_c_simple(../../../../release/datafiles/brushicons/subtract.png SRC)
                data_to_c_simple(../../../../release/datafiles/brushicons/texdraw.png SRC)
+               data_to_c_simple(../../../../release/datafiles/brushicons/texfill.png SRC)
+               data_to_c_simple(../../../../release/datafiles/brushicons/texmask.png SRC)
                data_to_c_simple(../../../../release/datafiles/brushicons/thumb.png SRC)
                data_to_c_simple(../../../../release/datafiles/brushicons/twist.png SRC)
                data_to_c_simple(../../../../release/datafiles/brushicons/vertexdraw.png SRC)
index 47819d0e33c5b808d7aa41d9d132fb6c4712dc67..6bc8f21e384fc42cb0d7512e8dcf8afa92253ab4 100644 (file)
@@ -77,6 +77,8 @@ sources.extend((
     os.path.join(env['DATA_SOURCES'], "soften.png.c"),
     os.path.join(env['DATA_SOURCES'], "subtract.png.c"),
     os.path.join(env['DATA_SOURCES'], "texdraw.png.c"),
+    os.path.join(env['DATA_SOURCES'], "texfill.png.c"),
+    os.path.join(env['DATA_SOURCES'], "texmask.png.c"),
     os.path.join(env['DATA_SOURCES'], "thumb.png.c"),
     os.path.join(env['DATA_SOURCES'], "twist.png.c"),
     os.path.join(env['DATA_SOURCES'], "vertexdraw.png.c"),
index 9022a1481aa789ea8daee8d5e20112d6ff69034c..661ab58b98cd6e82d3884a8c5dc540346ef416af 100644 (file)
@@ -150,6 +150,12 @@ extern char datatoc_subtract_png[];
 extern int datatoc_texdraw_png_size;
 extern char datatoc_texdraw_png[];
 
+extern int datatoc_texfill_png_size;
+extern char datatoc_texfill_png[];
+
+extern int datatoc_texmask_png_size;
+extern char datatoc_texmask_png[];
+
 extern int datatoc_thumb_png_size;
 extern char datatoc_thumb_png[];
 
index b15a83809f55e798ac138900717bb9ecd532ca6d..db13c628ade9b121319365b978d239b842837681 100644 (file)
@@ -69,8 +69,11 @@ void ED_image_point_pos__reverse(struct SpaceImage *sima, struct ARegion *ar, co
 bool ED_space_image_show_render(struct SpaceImage *sima);
 bool ED_space_image_show_paint(struct SpaceImage *sima);
 bool ED_space_image_show_uvedit(struct SpaceImage *sima, struct Object *obedit);
+bool ED_space_image_show_texpaint(struct SpaceImage *sima, struct Object *ob);
 bool ED_space_image_show_uvshadow(struct SpaceImage *sima, struct Object *obedit);
 
+bool ED_space_image_paint_curve(const struct bContext *C);
+
 bool ED_space_image_check_show_maskedit(struct Scene *scene, struct SpaceImage *sima);
 int ED_space_image_maskedit_poll(struct bContext *C);
 int ED_space_image_maskedit_mask_poll(struct bContext *C);
index d7e84d8f50d86a310cced87dcf798061f3a79ebc..decd79fcc7b6e72e90c5cf6b65478dae752c31d6 100644 (file)
 struct bContext;
 struct RegionView3D;
 struct wmKeyConfig;
+struct wmOperator;
 
 /* paint_ops.c */
 void ED_operatortypes_paint(void);
+void ED_operatormacros_paint(void);
 void ED_keymap_paint(struct wmKeyConfig *keyconf);
 
 /* paint_undo.c */
@@ -41,6 +43,7 @@ enum {
 
 typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb);
 typedef void (*UndoFreeCb)(struct ListBase *lb);
+typedef bool (*UndoCleanupCb)(struct bContext *C, struct ListBase *lb);
 
 int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name);
 void ED_undo_paint_step_num(struct bContext *C, int type, int num);
@@ -48,7 +51,7 @@ const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, int *ac
 void ED_undo_paint_free(void);
 int ED_undo_paint_valid(int type, const char *name);
 bool ED_undo_paint_empty(int type);
-void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free);
+void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup);
 void ED_undo_paint_push_end(int type);
 
 /* paint_image.c */
@@ -57,5 +60,6 @@ void ED_image_undo_restore(struct bContext *C, struct ListBase *lb);
 void ED_image_undo_free(struct ListBase *lb);
 void ED_imapaint_clear_partial_redraw(void);
 void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
 
 #endif /* __ED_PAINT_H__ */
index 41ff9b88da98361694f98ce82edacf93b2dfe7d3..daa6864b5aace3db7339bc4cf7d90fc8811ab3df 100644 (file)
@@ -98,6 +98,7 @@ enum TfmMode {
 #define CTX_NDOF            (1 << 5)
 #define CTX_MOVIECLIP       (1 << 6)
 #define CTX_MASK            (1 << 7)
+#define CTX_PAINT_CURVE     (1 << 8)
 
 /* Standalone call to get the transformation center corresponding to the current situation
  * returns 1 if successful, 0 otherwise (usually means there's no selection)
index 768397470763395a0c200877a56a436817fefcc9..ed68dd72c6494eeec996a56b384bcd6f37c1873d 100644 (file)
@@ -84,6 +84,7 @@ typedef struct ViewDepths {
 
 float *ED_view3d_cursor3d_get(struct Scene *scene, struct View3D *v3d);
 void   ED_view3d_cursor3d_position(struct bContext *C, float fp[3], const int mval[2]);
+void   ED_view3d_cursor3d_update(struct bContext *C, const int mval[2]);
 
 struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
 
index c776026a811f05a46184f0b4485f5d17878d840c..e06b8e62f277448665ab3a5102a3008e51670627 100644 (file)
@@ -976,6 +976,8 @@ DEF_ICON(BRUSH_SNAKE_HOOK)
 DEF_ICON(BRUSH_SOFTEN)
 DEF_ICON(BRUSH_SUBTRACT)
 DEF_ICON(BRUSH_TEXDRAW)
+DEF_ICON(BRUSH_TEXFILL)
+DEF_ICON(BRUSH_TEXMASK)
 DEF_ICON(BRUSH_THUMB)
 DEF_ICON(BRUSH_ROTATE)
 DEF_ICON(BRUSH_VERTEXDRAW)
index 1565583b5742c1af792278945a8fdd2e632a9496..c73efa13f29586ae7beb7b87ef5b3f6abc450f64 100644 (file)
@@ -75,6 +75,9 @@ struct ImBuf;
 struct bNodeTree;
 struct bNode;
 struct bNodeSocket;
+struct wmDropBox;
+struct wmDrag;
+struct wmEvent;
 
 typedef struct uiBut uiBut;
 typedef struct uiBlock uiBlock;
@@ -288,6 +291,9 @@ typedef enum {
 #define UI_GRAD_V_ALT   9
 #define UI_GRAD_L_ALT   10
 
+#define UI_PALETTE_COLOR 20
+#define UI_PALETTE_COLOR_ACTIVE 1
+
 /* Drawing
  *
  * Functions to draw various shapes, taking theme settings into account.
@@ -437,6 +443,7 @@ void    uiButSetDragValue(uiBut *but);
 void    uiButSetDragImage(uiBut *but, const char *path, int icon, struct ImBuf *ima, float scale);
 
 bool    UI_but_active_drop_name(struct bContext *C);
+bool    UI_but_active_drop_color(struct bContext *C);
 
 void    uiButSetFlag(uiBut *but, int flag);
 void    uiButClearFlag(uiBut *but, int flag);
@@ -847,6 +854,7 @@ void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char
 void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type,
                             int levels, int brush, int neg_slope);
 void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic);
+void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color);
 void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
                       PointerRNA *used_ptr, const char *used_propname, int active_layer);
 void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
@@ -916,7 +924,14 @@ void uiItemMenuEnumO(uiLayout *layout, struct bContext *C, const char *opname, c
 void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon);
 
 /* UI Operators */
+typedef struct uiDragColorHandle {
+       float color[3];
+       bool gamma_corrected;
+} uiDragColorHandle;
+
 void UI_buttons_operatortypes(void);
+void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
+int UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event);
 
 /* Helpers for Operators */
 uiBut *uiContextActiveButton(const struct bContext *C);
index 2e78940a813d7a32ec7ce405660da64e5f6e0cc4..da365355e9581c712585ff720ced6ba916f89c39 100644 (file)
@@ -237,6 +237,9 @@ enum {
        TH_STITCH_PREVIEW_UNSTITCHABLE,
        TH_STITCH_PREVIEW_ACTIVE,
 
+       TH_PAINT_CURVE_HANDLE,
+       TH_PAINT_CURVE_PIVOT,
+
        TH_UV_SHADOW,
        TH_UV_OTHERS,
 
index 7dfb17b3111393a4dfc50e6a1d53160e8c34fb02..76c5861ce0c08c4a1c275fa73c37991aa4719c15 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "DNA_brush_types.h"
 #include "DNA_sensor_types.h"
 #include "DNA_controller_types.h"
 #include "DNA_actuator_types.h"
@@ -60,6 +61,7 @@
 #include "PIL_time.h"
 
 #include "BKE_blender.h"
+#include "BKE_brush.h"
 #include "BKE_colortools.h"
 #include "BKE_context.h"
 #include "BKE_idprop.h"
@@ -1189,7 +1191,7 @@ static bool ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *eve
        
        BLI_rcti_rctf_copy(&rect, &but->rect);
        
-       if (but->imb) {
+       if (but->imb || but->type == COLOR) {
                /* use button size itself */
        }
        else if (but->drawflag & UI_BUT_ICON_LEFT) {
@@ -1242,10 +1244,42 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
                }
                else
 #endif
-               {
+               if (but->type == COLOR) {
+                       bool valid = false;
+                       uiDragColorHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
+
+                       /* TODO support more button pointer types */
+                       if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+                               RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color);
+                               drag_info->gamma_corrected = true;
+                               valid = true;
+                       }
+                       else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+                               RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color);
+                               drag_info->gamma_corrected = false;
+                               valid = true;
+                       }
+                       else if (but->pointype == UI_BUT_POIN_FLOAT) {
+                               copy_v3_v3(drag_info->color, (float *)but->poin);
+                               valid = true;
+                       }
+                       else if (but->pointype == UI_BUT_POIN_CHAR) {
+                               rgba_uchar_to_float(drag_info->color, (unsigned char *)but->poin);
+                               valid = true;
+                       }
+
+                       if (valid) {
+                               WM_event_start_drag(C, ICON_COLOR, WM_DRAG_COLOR, drag_info, 0.0, WM_DRAG_FREE_DATA);
+                       }
+                       else {
+                               MEM_freeN(drag_info);
+                               return false;
+                       }
+               }
+               else {
                        wmDrag *drag;
 
-                       drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but));
+                       drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but), WM_DRAG_NOP);
                        if (but->imb)
                                WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect));
                }
@@ -4053,7 +4087,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
                        }
                }
 #ifdef USE_DRAG_TOGGLE
-               if (event->type == LEFTMOUSE && ui_is_but_drag_toggle(but)) {
+               if (event->type == LEFTMOUSE && event->val == KM_PRESS && (ui_is_but_drag_toggle(but))) {
                        button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
                        data->dragstartx = event->x;
                        data->dragstarty = event->y;
@@ -4206,6 +4240,24 @@ static bool ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data,
 static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
 {
        if (data->state == BUTTON_STATE_HIGHLIGHT) {
+               /* first handle click on icondrag type button */
+               if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
+                       if (ui_but_mouse_inside_icon(but, data->region, event)) {
+                               button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+                               data->dragstartx = event->x;
+                               data->dragstarty = event->y;
+                               return WM_UI_HANDLER_BREAK;
+                       }
+               }
+#ifdef USE_DRAG_TOGGLE
+               if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
+                       button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+                       data->dragstartx = event->x;
+                       data->dragstarty = event->y;
+                       return WM_UI_HANDLER_BREAK;
+               }
+#endif
+               /* regular open menu */
                if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
                        button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
                        return WM_UI_HANDLER_BREAK;
@@ -4233,6 +4285,81 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
                        ui_apply_button(C, but->block, but, data, true);
                        return WM_UI_HANDLER_BREAK;
                }
+               else if ((int)(but->a1) == UI_PALETTE_COLOR &&
+                        event->type == DELKEY && event->val == KM_PRESS)
+               {
+                       Scene *scene = CTX_data_scene(C);
+                       Paint *paint = BKE_paint_get_active(scene);
+                       Palette *palette = BKE_paint_palette(paint);
+                       PaletteColor *color = but->rnapoin.data;
+
+                       BKE_palette_color_remove(palette, color);
+
+                       button_activate_state(C, but, BUTTON_STATE_EXIT);
+                       return WM_UI_HANDLER_BREAK;
+               }
+       }
+       else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+
+               /* this function also ends state */
+               if (ui_but_start_drag(C, but, data, event)) {
+                       return WM_UI_HANDLER_BREAK;
+               }
+
+               /* outside icon quit, not needed if drag activated */
+               if (0 == ui_but_mouse_inside_icon(but, data->region, event)) {
+                       button_activate_state(C, but, BUTTON_STATE_EXIT);
+                       data->cancel = true;
+                       return WM_UI_HANDLER_BREAK;
+               }
+
+               if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+                       if ((int)(but->a1) == UI_PALETTE_COLOR) {
+                               Palette *palette = but->rnapoin.id.data;
+                               PaletteColor *color = but->rnapoin.data;
+                               palette->active_color = BLI_findindex(&palette->colors, color);
+
+                               if( !event->ctrl) {
+                                       float color[3];
+                                       Scene *scene = CTX_data_scene(C);
+                                       Paint *paint = BKE_paint_get_active(scene);
+                                       Brush *brush = BKE_paint_brush(paint);
+
+                                       if (brush->flag & BRUSH_USE_GRADIENT) {
+                                               float *target = &brush->gradient->data[brush->gradient->cur].r;
+
+                                               if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+                                                       RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
+                                                       ui_block_to_scene_linear_v3(but->block, target);
+                                               }
+                                               else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+                                                       RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
+                                               }
+                                       }
+                                       else {
+                                               if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+                                                       RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
+                                                       BKE_brush_color_set(scene, brush, color);
+                                               }
+                                               else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+                                                       RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
+                                                       ui_block_to_display_space_v3(but->block, color);
+                                                       BKE_brush_color_set(scene, brush, color);
+                                               }
+                                       }
+
+                                       button_activate_state(C, but, BUTTON_STATE_EXIT);
+                               }
+                               else {
+                                       button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
+                               }
+                       }
+                       else {
+                               button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
+                       }
+                       return WM_UI_HANDLER_BREAK;
+               }
+
        }
 
        return WM_UI_HANDLER_CONTINUE;
@@ -6250,7 +6377,7 @@ static bool ui_but_contains_pt(uiBut *but, float mx, float my)
        return BLI_rctf_isect_pt(&but->rect, mx, my);
 }
 
-static uiBut *ui_but_find_activated(ARegion *ar)
+uiBut *ui_but_find_activated(ARegion *ar)
 {
        uiBlock *block;
        uiBut *but;
@@ -6305,6 +6432,17 @@ bool UI_but_active_drop_name(bContext *C)
        return 0;
 }
 
+bool UI_but_active_drop_color(bContext *C)
+{
+       ARegion *ar = CTX_wm_region(C);
+       uiBut *but = ui_but_find_activated(ar);
+
+       if (but && but->type == COLOR)
+               return true;
+
+       return false;
+}
+
 static void ui_blocks_set_tooltips(ARegion *ar, const bool enable)
 {
        uiBlock *block;
index 546b2b85af56c724e5aa916e53132faac4140005..51dd9166e4695da7ed4b0f0c51d62c6add5ee67b 100644 (file)
@@ -508,6 +508,8 @@ static void init_brush_icons(void)
        INIT_BRUSH_ICON(ICON_BRUSH_SOFTEN, soften);
        INIT_BRUSH_ICON(ICON_BRUSH_SUBTRACT, subtract);
        INIT_BRUSH_ICON(ICON_BRUSH_TEXDRAW, texdraw);
+       INIT_BRUSH_ICON(ICON_BRUSH_TEXFILL, texfill);
+       INIT_BRUSH_ICON(ICON_BRUSH_TEXMASK, texmask);
        INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb);
        INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist);
        INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw);
index cd3b63901843d5f436c0b045d155cc2ee072c334..830bca393c4d7869012303ffb29f03280f22c48d 100644 (file)
@@ -186,6 +186,7 @@ struct uiBut {
         * (type == LABEL),      Use (a1 == 1.0f) to use a2 as a blending factor (wow, this is imaginative!).
         * (type == SCROLL)      Use as scroll size.
         * (type == SEARCH_MENU) Use as number or rows.
+        * (type == COLOR)       Use as indication of color palette
         */
        float a1;
 
@@ -193,6 +194,7 @@ struct uiBut {
         * (type == NUM),        Use to store RNA 'precision' value, for dragging and click-step.
         * (type == LABEL),      If (a1 == 1.0f) use a2 as a blending factor.
         * (type == SEARCH_MENU) Use as number or columns.
+        * (type == COLOR)       Use as indication of active palette color
         */
        float a2;
 
@@ -556,6 +558,8 @@ extern void ui_button_active_free(const struct bContext *C, uiBut *but);
 extern bool ui_button_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT;
 extern int ui_button_open_menu_direction(uiBut *but);
 extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
+extern uiBut *ui_but_find_activated(struct ARegion *ar);
+
 void ui_button_clipboard_free(void);
 void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa);
 uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
index 877a993e0ac69749a7b828bc0695f6cf34ea36a1..32b073ba2693456af74a8edc27c5663ccfdefb32 100644 (file)
@@ -35,6 +35,7 @@
 #include "DNA_text_types.h" /* for UI_OT_reports_to_text */
 
 #include "BLI_blenlib.h"
+#include "BLI_math_color.h"
 
 #include "BLF_api.h"
 #include "BLF_translation.h"
@@ -44,6 +45,7 @@
 #include "BKE_global.h"
 #include "BKE_text.h" /* for UI_OT_reports_to_text */
 #include "BKE_report.h"
+#include "BKE_paint.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
@@ -55,6 +57,8 @@
 #include "WM_api.h"
 #include "WM_types.h"
 
+#include "ED_paint.h"
+
 /* only for UI_OT_editsource */
 #include "ED_screen.h"
 #include "BKE_main.h"
@@ -810,6 +814,91 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot)
        ot->exec = reloadtranslation_exec;
 }
 
+int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
+{
+       /* should only return true for regions that include buttons, for now
+        * return true always */
+       if (drag->type == WM_DRAG_COLOR) {
+               SpaceImage *sima = CTX_wm_space_image(C);
+               ARegion *ar = CTX_wm_region(C);
+
+               if (UI_but_active_drop_color(C))
+                       return 1;
+
+               if (sima && (sima->mode == SI_MODE_PAINT) &&
+                   sima->image && (ar && ar->regiontype == RGN_TYPE_WINDOW))
+               {
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
+{
+       uiDragColorHandle *drag_info = (uiDragColorHandle *)drag->poin;
+
+       RNA_float_set_array(drop->ptr, "color", drag_info->color);
+       RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
+}
+
+static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+       ARegion *ar = CTX_wm_region(C);
+       uiBut *but = NULL;
+       float color[3];
+       bool gamma;
+
+       RNA_float_get_array(op->ptr, "color", color);
+       gamma = RNA_boolean_get(op->ptr, "gamma");
+
+       /* find button under mouse, check if it has RNA color property and
+        * if it does copy the data */
+       but = ui_but_find_activated(ar);
+
+       if (but && but->type == COLOR && but->rnaprop) {
+               if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+                       if (!gamma)
+                               ui_block_to_display_space_v3(but->block, color);
+                       RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
+                       RNA_property_update(C, &but->rnapoin, but->rnaprop);
+               }
+               else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+                       if (gamma)
+                               ui_block_to_scene_linear_v3(but->block, color);
+                       RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
+                       RNA_property_update(C, &but->rnapoin, but->rnaprop);
+               }
+       }
+       else {
+               if (gamma) {
+                       srgb_to_linearrgb_v3_v3(color, color);
+               }
+
+               ED_imapaint_bucket_fill(C, color, op);
+       }
+
+       ED_region_tag_redraw(ar);
+
+       return OPERATOR_FINISHED;
+}
+
+
+static void UI_OT_drop_color(wmOperatorType *ot)
+{
+       ot->name = "Drop Color";
+       ot->idname = "UI_OT_drop_color";
+       ot->description = "Drop colors to buttons";
+
+       ot->invoke = drop_color_invoke;
+
+       RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
+       RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected ");
+}
+
+
+
 /* ********************************************************* */
 /* Registration */
 
@@ -821,7 +910,7 @@ void UI_buttons_operatortypes(void)
        WM_operatortype_append(UI_OT_unset_property_button);
        WM_operatortype_append(UI_OT_copy_to_selected_button);
        WM_operatortype_append(UI_OT_reports_to_textblock);  /* XXX: temp? */
-
+       WM_operatortype_append(UI_OT_drop_color);
 #ifdef WITH_PYTHON
        WM_operatortype_append(UI_OT_editsource);
        WM_operatortype_append(UI_OT_edittranslation_init);
index 33412b4df784fad56b1d5f5cd1d0cb2d93dfcf11..b2b3493d4fc18f0df748ca8a898ea431885ca208 100644 (file)
@@ -36,6 +36,7 @@
 #include "DNA_scene_types.h"
 #include "DNA_object_types.h"
 #include "DNA_object_force.h"
+#include "DNA_brush_types.h"
 
 #include "BLI_utildefines.h"
 #include "BLI_string.h"
@@ -60,6 +61,7 @@
 #include "BKE_object.h"
 #include "BKE_packedFile.h"
 #include "BKE_particle.h"
+#include "BKE_paint.h"
 #include "BKE_report.h"
 #include "BKE_sca.h"
 #include "BKE_screen.h"
@@ -349,6 +351,8 @@ static const char *template_id_browse_tip(StructRNA *type)
                        case ID_BR:  return N_("Browse Brush to be linked");
                        case ID_PA:  return N_("Browse Particle Settings to be linked");
                        case ID_GD:  return N_("Browse Grease Pencil Data to be linked");
+                       case ID_PAL: return N_("Browse Palette Data to be linked");
+                       case ID_PC:  return N_("Browse Paint Curve Data to be linked");
                }
        }
        return N_("Browse ID data to be linked");
@@ -2363,6 +2367,61 @@ void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propna
        }
 }
 
+void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname, int UNUSED(colors))
+{
+       PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+       PointerRNA cptr;
+       Palette *palette;
+       PaletteColor *color;
+       uiBlock *block;
+       uiLayout *col;
+       int row_cols = 0, col_id = 0;
+       int cols_per_row = MAX2(uiLayoutGetWidth(layout) / UI_UNIT_X, 1);
+
+       if (!prop) {
+               RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+               return;
+       }
+
+       cptr = RNA_property_pointer_get(ptr, prop);
+       if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Palette))
+               return;
+
+       block = uiLayoutGetBlock(layout);
+
+       palette = cptr.data;
+
+       /* first delete any pending colors */
+       BKE_palette_cleanup(palette);
+
+       color = palette->colors.first;
+
+       col = uiLayoutColumn(layout, true);
+       uiLayoutRow(col, true);
+       uiDefIconButO(block, BUT, "PALETTE_OT_color_add", WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+       uiDefIconButO(block, BUT, "PALETTE_OT_color_delete", WM_OP_INVOKE_DEFAULT, ICON_ZOOMOUT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+
+       col = uiLayoutColumn(layout, true);
+       uiLayoutRow(col, true);
+
+       for (; color; color = color->next) {
+               PointerRNA ptr;
+
+               if (row_cols >= cols_per_row) {
+                       uiLayoutRow(col, true);
+                       row_cols = 0;
+               }
+
+               RNA_pointer_create(&palette->id, &RNA_PaletteColor, color, &ptr);
+               uiDefButR(block, COLOR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, &ptr, "color", -1, 0.0, 1.0,
+                         UI_PALETTE_COLOR, (col_id == palette->active_color) ? UI_PALETTE_COLOR_ACTIVE : 0.0, "");
+
+               row_cols++;
+               col_id++;
+       }
+}
+
+
 /********************* Layer Buttons Template ************************/
 
 static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
index e8f8f1541b74d65281e74252f73a9a61c2b80591..23f185befb90e0fb387da8e8f78530550c853756 100644 (file)
@@ -33,6 +33,7 @@
 #include <string.h>
 #include <assert.h>
 
+#include "DNA_brush_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_userdef_types.h"
 
@@ -2825,6 +2826,17 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
 
        widgetbase_draw(&wtb, wcol);
        
+       if (but->a1 == UI_PALETTE_COLOR && but->a2 == UI_PALETTE_COLOR_ACTIVE) {
+               float width = rect->xmax - rect->xmin;
+               float height = rect->ymax - rect->ymin;
+
+               glColor4ubv((unsigned char *)wcol->outline);
+               glBegin(GL_TRIANGLES);
+               glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.9f * height);
+               glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.5f * height);
+               glVertex2f(rect->xmin + 0.5f * width, rect->ymin + 0.9f * height);
+               glEnd();
+       }
 }
 
 static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
index 372ced0a6fdb872513cc4ce882f52c0376a4dc77..65c01781d6d01dcac0c3a8ff4ea6867b2082c635 100644 (file)
 
 #include "MEM_guardedalloc.h"
 
+#include "DNA_brush_types.h"
 #include "DNA_curve_types.h"
-#include "DNA_userdef_types.h"
+#include "DNA_mesh_types.h"  /* init_userdef_factory */
+#include "DNA_object_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
 #include "DNA_windowmanager_types.h"
-#include "DNA_mesh_types.h"  /* init_userdef_factory */
 
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
 #include "BLI_math.h"
 
+#include "BKE_brush.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_global.h"
 #include "BKE_main.h"
 #include "BKE_texture.h"
+#include "BKE_library.h"
 
 
 #include "BIF_gl.h"
@@ -537,6 +541,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
                                        cp = ts->preview_stitch_active;
                                        break;
 
+                               case TH_PAINT_CURVE_HANDLE:
+                                       cp = ts->paint_curve_handle;
+                                       break;
+                               case TH_PAINT_CURVE_PIVOT:
+                                       cp = ts->paint_curve_pivot;
+                                       break;
+
                                case TH_UV_OTHERS:
                                        cp = ts->uv_others;
                                        break;
@@ -871,6 +882,8 @@ void ui_theme_init_default(void)
        rgba_char_args_set(btheme->tv3d.title, 0, 0, 0, 255);
        rgba_char_args_set(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255);
        rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
+       rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+       rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
 
        btheme->tv3d.facedot_size = 4;
 
@@ -2427,6 +2440,16 @@ void init_userdef_do_versions(void)
                }
        }
 
+       if (U.versionfile < 272|| (U.versionfile == 272 && U.subversionfile < 2)) {
+               bTheme *btheme;
+               for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+                       rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+                       rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
+                       rgba_char_args_set_fl(btheme->tima.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+                       rgba_char_args_set_fl(btheme->tima.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
+               }
+       }
+
        {
                bTheme *btheme;
                for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -2470,4 +2493,34 @@ void init_userdef_factory(void)
                        me->flag &= ~ME_TWOSIDED;
                }
        }
+
+       {
+               Brush *br;
+               br = BKE_brush_add(G.main, "Fill");
+               br->imagepaint_tool = PAINT_TOOL_FILL;
+               br->ob_mode = OB_MODE_TEXTURE_PAINT;
+
+               br = (Brush *)BKE_libblock_find_name(ID_BR, "Mask");
+               if (br) {
+                       br->imagepaint_tool = PAINT_TOOL_MASK;
+                       br->ob_mode |= OB_MODE_TEXTURE_PAINT;
+               }
+       }
+
+       {
+               Scene *scene;
+
+               for (scene = G.main->scene.first; scene; scene = scene->id.next) {
+                       if (scene->toolsettings) {
+                               ToolSettings *ts = scene->toolsettings;
+
+                               if (ts->sculpt) {
+                                       Sculpt *sculpt = ts->sculpt;
+                                       sculpt->paint.symmetry_flags |= PAINT_SYMM_X;
+                                       sculpt->flags |= SCULPT_DYNTOPO_COLLAPSE;
+                                       sculpt->detail_size = 12;
+                               }
+                       }
+               }
+       }
 }
index 94d8d78de1a402bdddeb7fe79fdc9eb48a1380be..f11af9b4d51209cb87797c10e4745ca398fa8c0a 100644 (file)
@@ -165,6 +165,7 @@ void ED_render_engine_changed(Main *bmain)
        bScreen *sc;
        ScrArea *sa;
        Scene *scene;
+       Material *ma;
 
        for (sc = bmain->screen.first; sc; sc = sc->id.next)
                for (sa = sc->areabase.first; sa; sa = sa->next)
@@ -174,6 +175,11 @@ void ED_render_engine_changed(Main *bmain)
 
        for (scene = bmain->scene.first; scene; scene = scene->id.next)
                ED_render_id_flush_update(bmain, &scene->id);
+
+       /* reset texture painting */
+       for (ma = bmain->mat.first; ma; ma = ma->id.next) {
+               BKE_texpaint_slots_clear(ma);
+       }
 }
 
 /***************************** Updates ***********************************
index 3cdf22229346361748f8467296b998b264fda742..7d2299063fa60762e27e39b308d9570288c6ce0f 100644 (file)
@@ -4154,7 +4154,8 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
        /* dropbox for entire window */
        lb = WM_dropboxmap_find("Window", 0, 0);
        WM_dropbox_add(lb, "WM_OT_open_mainfile", open_file_drop_poll, open_file_drop_copy);
-       
+       WM_dropbox_add(lb, "UI_OT_drop_color", UI_drop_color_poll, UI_drop_color_copy);
+
        keymap_modal_set(keyconf);
 }
 
index 79ce4f879b7676b24bdde128066f8e399ba581eb..18db57c9f21b6c75c578f9ea9d1cd5d7a0e48ecd 100644 (file)
@@ -40,6 +40,7 @@ set(INC_SYS
 
 set(SRC
        paint_cursor.c
+       paint_curve.c
        paint_hide.c
        paint_image.c
        paint_image_2d.c
index b5b0ddd6f701244a3b77c9723328220af47927ee..7b9ede38b391552cb6116dd726424a91b3be442b 100644 (file)
@@ -44,6 +44,7 @@
 
 #include "BKE_brush.h"
 #include "BKE_context.h"
+#include "BKE_curve.h"
 #include "BKE_image.h"
 #include "BKE_node.h"
 #include "BKE_paint.h"
@@ -58,6 +59,8 @@
 
 #include "ED_view3d.h"
 
+#include "UI_resources.h"
+
 #include "paint_intern.h"
 /* still needed for sculpt_stroke_get_location, should be
  * removed eventually (TODO) */
@@ -791,6 +794,138 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
        glPopAttrib();
 }
 
+
+BLI_INLINE void draw_tri_point(float *co, float width, bool selected)
+{
+       float w = width / 2.0f;
+       if (selected)
+               UI_ThemeColor4(TH_VERTEX_SELECT);
+       else
+               UI_ThemeColor4(TH_PAINT_CURVE_PIVOT);
+
+       glLineWidth(3.0);
+
+       glBegin(GL_LINE_LOOP);
+       glVertex2f(co[0], co[1] + w);
+       glVertex2f(co[0] - w, co[1] - w);
+       glVertex2f(co[0] + w, co[1] - w);
+       glEnd();
+
+       glColor4f(1.0, 1.0, 1.0, 0.5);
+       glLineWidth(1.0);
+
+       glBegin(GL_LINE_LOOP);
+       glVertex2f(co[0], co[1] + w);
+       glVertex2f(co[0] - w, co[1] - w);
+       glVertex2f(co[0] + w, co[1] - w);
+       glEnd();
+}
+
+BLI_INLINE void draw_rect_point(float *co, float width, bool selected)
+{
+       float w = width / 2.0f;
+       if (selected)
+               UI_ThemeColor4(TH_VERTEX_SELECT);
+       else
+               UI_ThemeColor4(TH_PAINT_CURVE_HANDLE);
+       glLineWidth(3.0);
+
+       glBegin(GL_LINE_LOOP);
+       glVertex2f(co[0] + w, co[1] + w);
+       glVertex2f(co[0] - w, co[1] + w);
+       glVertex2f(co[0] - w, co[1] - w);
+       glVertex2f(co[0] + w, co[1] - w);
+       glEnd();
+
+       glColor4f(1.0, 1.0, 1.0, 0.5);
+       glLineWidth(1.0);
+
+       glBegin(GL_LINE_LOOP);
+       glVertex2f(co[0] + w, co[1] + w);
+       glVertex2f(co[0] - w, co[1] + w);
+       glVertex2f(co[0] - w, co[1] - w);
+       glVertex2f(co[0] + w, co[1] - w);
+       glEnd();
+}
+
+
+BLI_INLINE void draw_bezier_handle_lines(BezTriple *bez)
+{
+       short line1[] = {0, 1};
+       short line2[] = {1, 2};
+
+       glVertexPointer(2, GL_FLOAT, 3 * sizeof(float), bez->vec);
+       glColor4f(0.0, 0.0, 0.0, 0.5);
+       glLineWidth(3.0);
+       glDrawArrays(GL_LINE_STRIP, 0, 3);
+
+       glLineWidth(1.0);
+       if (bez->f1 || bez->f2)
+               UI_ThemeColor4(TH_VERTEX_SELECT);
+       else
+               glColor4f(1.0, 1.0, 1.0, 0.5);
+       glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line1);
+       if (bez->f3 || bez->f2)
+               UI_ThemeColor4(TH_VERTEX_SELECT);
+       else
+               glColor4f(1.0, 1.0, 1.0, 0.5);
+       glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line2);
+}
+
+static void paint_draw_curve_cursor(Brush *brush)
+{
+       if (brush->paint_curve && brush->paint_curve->points) {
+               int i;
+               PaintCurve *pc = brush->paint_curve;
+               PaintCurvePoint *cp = pc->points;
+
+               glEnable(GL_LINE_SMOOTH);
+               glEnable(GL_BLEND);
+               glEnableClientState(GL_VERTEX_ARRAY);
+
+               /* draw the bezier handles and the curve segment between the current and next point */
+               for (i = 0; i < pc->tot_points - 1; i++, cp++) {
+                       int j;
+                       PaintCurvePoint *cp_next = cp + 1;
+                       float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+                       /* use color coding to distinguish handles vs curve segments  */
+                       draw_bezier_handle_lines(&cp->bez);
+                       draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2);
+                       draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
+                       draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
+
+                       for (j = 0; j < 2; j++)
+                               BKE_curve_forward_diff_bezier(
+                                       cp->bez.vec[1][j],
+                                       cp->bez.vec[2][j],
+                                       cp_next->bez.vec[0][j],
+                                       cp_next->bez.vec[1][j],
+                                       data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
+
+                       glVertexPointer(2, GL_FLOAT, 0, data);
+                       glLineWidth(3.0);
+                       glColor4f(0.0, 0.0, 0.0, 0.5);
+                       glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1);
+
+                       glLineWidth(1.0);
+                       glColor4f(0.9, 0.9, 1.0, 0.5);
+                       glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1);
+               }
+
+               /* draw last line segment */
+               draw_bezier_handle_lines(&cp->bez);
+               draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2);
+               draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
+               draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
+
+               glLineWidth(1.0);
+
+               glDisable(GL_BLEND);
+               glDisable(GL_LINE_SMOOTH);
+               glDisableClientState(GL_VERTEX_ARRAY);
+       }
+}
+
 /* Special actions taken when paint cursor goes over mesh */
 /* TODO: sculpt only for now */
 static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc,
@@ -848,6 +983,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
        zoomx = max_ff(zoomx, zoomy);
        mode = BKE_paintmode_get_active_from_context(C);
 
+       /* skip everything and draw brush here */
+       if (brush->flag & BRUSH_CURVE) {
+               paint_draw_curve_cursor(brush);
+               return;
+       }
+
        /* set various defaults */
        translation[0] = x;
        translation[1] = y;
@@ -857,8 +998,11 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
 
        /* don't calculate rake angles while a stroke is active because the rake variables are global and
         * we may get interference with the stroke itself. For line strokes, such interference is visible */
-       if (!ups->stroke_active && (brush->flag & BRUSH_RAKE))
-               paint_calculate_rake_rotation(ups, translation);
+       if (!ups->stroke_active) {
+               if (brush->flag & BRUSH_RAKE)
+                       /* here, translation contains the mouse coordinates. */
+                       paint_calculate_rake_rotation(ups, translation);
+       }
 
        /* draw overlay */
        paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
@@ -878,7 +1022,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
                /* check if brush is subtracting, use different color then */
                /* TODO: no way currently to know state of pen flip or
                 * invert key modifier without starting a stroke */
-               if ((!(brush->flag & BRUSH_INVERTED) ^
+               if ((!(ups->draw_inverted) ^
                     !(brush->flag & BRUSH_DIR_IN)) &&
                    ELEM(brush->sculpt_tool, SCULPT_TOOL_DRAW,
                          SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
@@ -890,12 +1034,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
                /* only do if brush is over the mesh */
                if (hit)
                        paint_cursor_on_hit(ups, brush, &vc, location);
+       }
 
-               if (ups->draw_anchored) {
-                       final_radius = ups->anchored_size;
-                       translation[0] = ups->anchored_initial_mouse[0];
-                       translation[1] = ups->anchored_initial_mouse[1];
-               }
+       if (ups->draw_anchored) {
+               final_radius = ups->anchored_size;
+               translation[0] = ups->anchored_initial_mouse[0];
+               translation[1] = ups->anchored_initial_mouse[1];
        }
 
        /* make lines pretty */
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
new file mode 100644 (file)
index 0000000..6ca0a04
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/sculpt_paint/paint_curve.c
+ *  \ingroup edsculpt
+ */
+
+#include <string.h>
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_paint.h"
+
+#include "BLI_math_vector.h"
+#include "BLI_string.h"
+
+#include "ED_paint.h"
+#include "ED_view3d.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_view2d.h"
+
+#include "paint_intern.h"
+
+#define PAINT_CURVE_SELECT_THRESHOLD 40.0f
+#define PAINT_CURVE_POINT_SELECT(pcp, i) (*(&pcp->bez.f1 + i) = SELECT)
+
+
+int paint_curve_poll(bContext *C)
+{
+       Object *ob = CTX_data_active_object(C);
+       Paint *p;
+       RegionView3D *rv3d = CTX_wm_region_view3d(C);
+       SpaceImage *sima;
+
+       if (rv3d && !(ob && ((ob->mode & OB_MODE_ALL_PAINT) != 0)))
+               return false;
+
+       sima = CTX_wm_space_image(C);
+
+       if (sima && sima->mode != SI_MODE_PAINT)
+               return false;
+
+       p = BKE_paint_get_active_from_context(C);
+
+       if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
+               return true;
+       }
+
+       return false;
+}
+
+/* Paint Curve Undo*/
+
+typedef struct UndoCurve {
+       struct UndoImageTile *next, *prev;
+
+       PaintCurvePoint *points; /* points of curve */
+       int tot_points;
+       int active_point;
+
+       char idname[MAX_ID_NAME];  /* name instead of pointer*/
+} UndoCurve;
+
+static void paintcurve_undo_restore(bContext *C, ListBase *lb)
+{
+       Paint *p = BKE_paint_get_active_from_context(C);
+       UndoCurve *uc;
+       PaintCurve *pc;
+
+       if (p->brush) {
+               pc = p->brush->paint_curve;
+       }
+
+       if (!pc)
+               return;
+
+       uc = (UndoCurve *)lb->first;
+
+       if (strncmp(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname))) == 0) {
+               SWAP(PaintCurvePoint *, pc->points, uc->points);
+               SWAP(int, pc->tot_points, uc->tot_points);
+               SWAP(int, pc->add_index, uc->active_point);
+       }
+}
+
+static void paintcurve_undo_delete(ListBase *lb)
+{
+       UndoCurve *uc;
+       uc = (UndoCurve *)lb->first;
+
+       if (uc->points)
+               MEM_freeN(uc->points);
+       uc->points = NULL;
+}
+
+
+static void paintcurve_undo_begin(bContext *C, wmOperator *op, PaintCurve *pc)
+{
+       PaintMode mode = BKE_paintmode_get_active_from_context(C);
+       ListBase *lb = NULL;
+       int undo_stack_id;
+       UndoCurve *uc;
+
+       switch (mode) {
+               case PAINT_TEXTURE_2D:
+               case PAINT_TEXTURE_PROJECTIVE:
+                       undo_stack_id = UNDO_PAINT_IMAGE;
+                       break;
+
+               case PAINT_SCULPT:
+                       undo_stack_id = UNDO_PAINT_MESH;
+                       break;
+
+               default:
+                       /* do nothing, undo is handled by global */
+                       return;
+       }
+
+
+       ED_undo_paint_push_begin(undo_stack_id, op->type->name,
+                                paintcurve_undo_restore, paintcurve_undo_delete, NULL);
+       lb = undo_paint_push_get_list(undo_stack_id);
+
+       uc = MEM_callocN(sizeof(*uc), "Undo_curve");
+
+       lb->first = uc;
+
+       BLI_strncpy(uc->idname, pc->id.name, sizeof(uc->idname));
+       uc->tot_points = pc->tot_points;
+       uc->active_point = pc->add_index;
+       uc->points = MEM_dupallocN(pc->points);
+
+       undo_paint_push_count_alloc(undo_stack_id, sizeof(*uc) + sizeof(*pc->points) * pc->tot_points);
+
+       ED_undo_paint_push_end(undo_stack_id);
+}
+#define SEL_F1 (1 << 0)
+#define SEL_F2 (1 << 1)
+#define SEL_F3 (1 << 2)
+
+/* returns 0, 1, or 2 in point according to handle 1, pivot or handle 2 */
+static PaintCurvePoint *paintcurve_point_get_closest(PaintCurve *pc, const float pos[2], bool ignore_pivot, const float threshold, char *point)
+{
+       PaintCurvePoint *pcp, *closest = NULL;
+       int i;
+       float dist, closest_dist = FLT_MAX;
+
+       for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+               dist = len_manhattan_v2v2(pos, pcp->bez.vec[0]);
+               if (dist < threshold) {
+                       if (dist < closest_dist) {
+                               closest = pcp;
+                               closest_dist = dist;
+                               if (point)
+                                       *point = SEL_F1;
+                       }
+               }
+               if (!ignore_pivot) {
+                       dist = len_manhattan_v2v2(pos, pcp->bez.vec[1]);
+                       if (dist < threshold) {
+                               if (dist < closest_dist) {
+                                       closest = pcp;
+                                       closest_dist = dist;
+                                       if (point)
+                                               *point = SEL_F2;
+                               }
+                       }
+               }
+               dist = len_manhattan_v2v2(pos, pcp->bez.vec[2]);
+               if (dist < threshold) {
+                       if (dist < closest_dist) {
+                               closest = pcp;
+                               closest_dist = dist;
+                               if (point)
+                                       *point = SEL_F3;
+                       }
+               }
+       }
+
+       return closest;
+}
+
+static int paintcurve_point_co_index(char sel)
+{
+       char i = 0;
+       while (sel != 1) {
+               sel >>= 1;
+               i++;
+       }
+       return i;
+}
+
+/******************* Operators *********************************/
+
+static int paintcurve_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       Paint *p = BKE_paint_get_active_from_context(C);
+       Main *bmain = CTX_data_main(C);
+
+       if (p && p->brush) {
+               p->brush->paint_curve = BKE_paint_curve_add(bmain, "PaintCurve");
+       }
+
+       return OPERATOR_FINISHED;
+}
+
+void PAINTCURVE_OT_new(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Add New Paint Curve";
+       ot->description = "Add new paint curve";
+       ot->idname = "PAINTCURVE_OT_new";
+
+       /* api callbacks */
+       ot->exec = paintcurve_new_exec;
+       ot->poll = paint_curve_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static void paintcurve_point_add(bContext *C,  wmOperator *op, const int loc[2])
+{
+       Paint *p = BKE_paint_get_active_from_context(C);
+       Brush *br = p->brush;
+       Main *bmain = CTX_data_main(C);
+       PaintCurve *pc;
+       PaintCurvePoint *pcp;
+       wmWindow *window = CTX_wm_window(C);
+       ARegion *ar = CTX_wm_region(C);
+       float vec[3] = {loc[0], loc[1], 0.0};
+       int add_index;
+       int i;
+
+       pc = br->paint_curve;
+       if (!pc) {
+               br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve");
+       }
+
+       paintcurve_undo_begin(C, op, pc);
+
+       pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint");
+       add_index = pc->add_index;
+
+       if (pc->points) {
+               if (add_index > 0)
+                       memcpy(pcp, pc->points, add_index * sizeof(PaintCurvePoint));
+               if (add_index < pc->tot_points)
+                       memcpy(pcp + add_index + 1, pc->points + add_index, (pc->tot_points - add_index) * sizeof(PaintCurvePoint));
+
+               MEM_freeN(pc->points);
+       }
+       pc->points = pcp;
+       pc->tot_points++;
+
+       /* initialize new point */
+       memset(&pcp[add_index], 0, sizeof(PaintCurvePoint));
+       copy_v3_v3(pcp[add_index].bez.vec[0], vec);
+       copy_v3_v3(pcp[add_index].bez.vec[1], vec);
+       copy_v3_v3(pcp[add_index].bez.vec[2], vec);
+
+       /* last step, clear selection from all bezier handles expect the next */
+       for (i = 0; i < pc->tot_points; i++) {
+               pcp[i].bez.f1 = pcp[i].bez.f2 = pcp[i].bez.f3 = 0;
+       }
+       pcp[add_index].bez.f3 = SELECT;
+       pcp[add_index].bez.h2 = HD_ALIGN;
+
+       pc->add_index = add_index + 1;
+
+       WM_paint_cursor_tag_redraw(window, ar);
+}
+
+
+static int paintcurve_add_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       int loc[2] = {event->mval[0], event->mval[1]};
+       paintcurve_point_add(C, op, loc);
+       RNA_int_set_array(op->ptr, "location", loc);
+       return OPERATOR_FINISHED;
+}
+
+static int paintcurve_add_point_exec(bContext *C, wmOperator *op)
+{
+       int loc[2];
+
+       if (RNA_struct_property_is_set(op->ptr, "location")) {
+               RNA_int_get_array(op->ptr, "location", loc);
+               paintcurve_point_add(C, op, loc);
+               return OPERATOR_FINISHED;
+       }
+
+       return OPERATOR_CANCELLED;
+}
+
+void PAINTCURVE_OT_add_point(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Add New Paint Curve Point";
+       ot->description = "Add new paint curve point";
+       ot->idname = "PAINTCURVE_OT_add_point";
+
+       /* api callbacks */
+       ot->invoke = paintcurve_add_point_invoke;
+       ot->exec = paintcurve_add_point_exec;
+       ot->poll = paint_curve_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+       /* properties */
+       RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
+                          "Location", "Location of vertex in area space", 0, SHRT_MAX);
+}
+
+static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
+{
+       Paint *p = BKE_paint_get_active_from_context(C);
+       Brush *br = p->brush;
+       PaintCurve *pc;
+       PaintCurvePoint *pcp;
+       wmWindow *window = CTX_wm_window(C);
+       ARegion *ar = CTX_wm_region(C);
+       int i;
+       int tot_del = 0;
+       pc = br->paint_curve;
+
+       if (!pc || pc->tot_points == 0) {
+               return OPERATOR_CANCELLED;
+       }
+
+       paintcurve_undo_begin(C, op, pc);
+
+#define DELETE_TAG 2
+
+       for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+               if ((pcp->bez.f1 & SELECT) || (pcp->bez.f2 & SELECT) || (pcp->bez.f3 & SELECT)) {
+                       pcp->bez.f2 |= DELETE_TAG;
+                       tot_del++;
+               }
+       }
+
+       if (tot_del > 0) {
+               int j = 0;
+               int new_tot = pc->tot_points - tot_del;
+               PaintCurvePoint *points_new = NULL;
+               if (new_tot > 0)
+                       points_new = MEM_mallocN(new_tot * sizeof(PaintCurvePoint), "PaintCurvePoint");
+
+               for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+                       if (!(pcp->bez.f2 & DELETE_TAG)) {
+                               points_new[j] = pc->points[i];
+
+                               if ((i + 1) == pc->add_index) {
+                                       pc->add_index = j + 1;
+                               }
+                               j++;
+                       }
+                       else if ((i + 1) == pc->add_index) {
+                               /* prefer previous point */
+                               pc->add_index = j;
+                       }
+               }
+               MEM_freeN(pc->points);
+
+               pc->points = points_new;
+               pc->tot_points = new_tot;
+       }
+
+#undef DELETE_TAG
+
+       WM_paint_cursor_tag_redraw(window, ar);
+
+       return OPERATOR_FINISHED;
+}
+
+
+void PAINTCURVE_OT_delete_point(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Add New Paint Curve Point";
+       ot->description = "Add new paint curve point";
+       ot->idname = "PAINTCURVE_OT_delete_point";
+
+       /* api callbacks */
+       ot->exec = paintcurve_delete_point_exec;
+       ot->poll = paint_curve_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_UNDO;
+}
+
+
+static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2], bool toggle, bool extend)
+{
+       wmWindow *window = CTX_wm_window(C);
+       ARegion *ar = CTX_wm_region(C);
+       Paint *p = BKE_paint_get_active_from_context(C);
+       Brush *br = p->brush;
+       PaintCurve *pc;
+       PaintCurvePoint *pcp;
+       int i;
+       const float loc_fl[2] = {UNPACK2(loc)};
+
+       pc = br->paint_curve;
+
+       if (!pc)
+               return false;
+
+       paintcurve_undo_begin(C, op, pc);
+
+       pcp = pc->points;
+
+       if (toggle) {
+               char select = 0;
+               bool selected = false;
+
+               for (i = 0; i < pc->tot_points; i++) {
+                       if (pcp[i].bez.f1 || pcp[i].bez.f2 || pcp[i].bez.f3) {
+                               selected = true;
+                               break;
+                       }
+               }
+
+               if (!selected) {
+                       select = SELECT;
+               }
+
+               for (i = 0; i < pc->tot_points; i++) {
+                       pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = select;
+               }
+       }
+       else {
+               PaintCurvePoint *pcp;
+               char selflag;
+
+               pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag);
+
+               if (pcp) {
+                       pc->add_index = (pcp - pc->points) + 1;
+
+                       if (selflag == SEL_F2) {
+                               if (extend)
+                                       pcp->bez.f2 ^= SELECT;
+                               else
+                                       pcp->bez.f2 |= SELECT;
+                       }
+                       else if (selflag == SEL_F1) {
+                               if (extend)
+                                       pcp->bez.f1 ^= SELECT;
+                               else
+                                       pcp->bez.f1 |= SELECT;
+                       }
+                       else if (selflag == SEL_F3) {
+                               if (extend)
+                                       pcp->bez.f3 ^= SELECT;
+                               else
+                                       pcp->bez.f3 |= SELECT;
+                       }
+               }
+
+               /* clear selection for unselected points if not extending and if a point has been selected */
+               if (!extend && pcp) {
+                       for (i = 0; i < pc->tot_points; i++) {
+                               pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = 0;
+
+                               if ((pc->points + i) == pcp) {
+                                       char index = paintcurve_point_co_index(selflag);
+                                       PAINT_CURVE_POINT_SELECT(pcp, index);
+                               }
+                       }
+               }
+
+               if (!pcp)
+                       return false;
+       }
+
+       WM_paint_cursor_tag_redraw(window, ar);
+
+       return true;
+}
+
+
+static int paintcurve_select_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       int loc[2] = {UNPACK2(event->mval)};
+       bool toggle = RNA_boolean_get(op->ptr, "toggle");
+       bool extend = RNA_boolean_get(op->ptr, "extend");
+       if (paintcurve_point_select(C, op, loc, toggle, extend)) {
+               RNA_int_set_array(op->ptr, "location", loc);
+               return OPERATOR_FINISHED;
+       }
+       else {
+               return OPERATOR_CANCELLED;
+       }
+}
+
+static int paintcurve_select_point_exec(bContext *C, wmOperator *op)
+{
+       int loc[2];
+
+       if (RNA_struct_property_is_set(op->ptr, "location")) {
+               bool toggle = RNA_boolean_get(op->ptr, "toggle");
+               bool extend = RNA_boolean_get(op->ptr, "extend");
+               RNA_int_get_array(op->ptr, "location", loc);
+               if (paintcurve_point_select(C, op, loc, toggle, extend))
+                       return OPERATOR_FINISHED;
+       }
+
+       return OPERATOR_CANCELLED;
+}
+
+void PAINTCURVE_OT_select(wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+
+       /* identifiers */
+       ot->name = "Select Paint Curve Point";
+       ot->description = "Select a paint curve point";
+       ot->idname = "PAINTCURVE_OT_select";
+
+       /* api callbacks */
+       ot->invoke = paintcurve_select_point_invoke;
+       ot->exec = paintcurve_select_point_exec;
+       ot->poll = paint_curve_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+       /* properties */
+       RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
+                          "Location", "Location of vertex in area space", 0, SHRT_MAX);
+       prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle", "Select/Deselect all");
+       RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+       prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
+       RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+typedef struct PointSlideData {
+       PaintCurvePoint *pcp;
+       char select;
+       int initial_loc[2];
+       float point_initial_loc[3][2];
+       int event;
+       bool align;
+} PointSlideData;
+
+static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       Paint *p = BKE_paint_get_active_from_context(C);
+       const float loc_fl[2] = {UNPACK2(event->mval)};
+       char select;
+       int i;
+       bool do_select = RNA_boolean_get(op->ptr, "select");
+       bool align = RNA_boolean_get(op->ptr, "align");
+       Brush *br = p->brush;
+       PaintCurve *pc = br->paint_curve;
+       PaintCurvePoint *pcp;
+
+       if (!pc)
+               return OPERATOR_PASS_THROUGH;
+
+       if (do_select) {
+               pcp = paintcurve_point_get_closest(pc, loc_fl, align, PAINT_CURVE_SELECT_THRESHOLD, &select);
+       }
+       else {
+               /* just find first selected point */
+               for (i = 0; i < pc->tot_points; i++) {
+                       if (pc->points[i].bez.f1 || pc->points[i].bez.f2 || pc->points[i].bez.f3) {
+                               pcp = &pc->points[i];
+                               select = SEL_F3;
+                               break;
+                       }
+               }
+       }
+
+
+       if (pcp) {
+               ARegion *ar = CTX_wm_region(C);
+               wmWindow *window = CTX_wm_window(C);
+               PointSlideData *psd = MEM_mallocN(sizeof(PointSlideData), "PointSlideData");
+               copy_v2_v2_int(psd->initial_loc, event->mval);
+               psd->event = event->type;
+               psd->pcp = pcp;
+               psd->select = paintcurve_point_co_index(select);
+               for (i = 0; i < 3; i++) {
+                       copy_v2_v2(psd->point_initial_loc[i], pcp->bez.vec[i]);
+               }
+               psd->align = align;
+               op->customdata = psd;
+
+               if (do_select)
+                       paintcurve_undo_begin(C, op, pc);
+
+               /* first, clear all selection from points */
+               for (i = 0; i < pc->tot_points; i++)
+                       pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0;
+
+               /* only select the active point */
+               PAINT_CURVE_POINT_SELECT(pcp, psd->select);
+               pc->add_index = (pcp - pc->points) + 1;
+
+               WM_event_add_modal_handler(C, op);
+               WM_paint_cursor_tag_redraw(window, ar);
+               return OPERATOR_RUNNING_MODAL;
+       }
+
+       return OPERATOR_PASS_THROUGH;
+}
+
+static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       PointSlideData *psd = op->customdata;
+
+       if (event->type == psd->event && event->val == KM_RELEASE) {
+               MEM_freeN(psd);
+               return OPERATOR_FINISHED;
+       }
+
+       switch (event->type) {
+               case MOUSEMOVE:
+               {
+                       ARegion *ar = CTX_wm_region(C);
+                       wmWindow *window = CTX_wm_window(C);
+                       float diff[2] = {event->mval[0] - psd->initial_loc[0],
+                                        event->mval[1] - psd->initial_loc[1]};
+                       if (psd->select == 1) {
+                               int i;
+                               for (i = 0; i < 3; i++)
+                                       add_v2_v2v2(psd->pcp->bez.vec[i], diff, psd->point_initial_loc[i]);
+                       }
+                       else {
+                               add_v2_v2(diff, psd->point_initial_loc[psd->select]);
+                               copy_v2_v2(psd->pcp->bez.vec[psd->select], diff);
+
+                               if (psd->align) {
+                                       char opposite = (psd->select == 0) ? 2 : 0;
+                                       sub_v2_v2v2(diff, psd->pcp->bez.vec[1], psd->pcp->bez.vec[psd->select]);
+                                       add_v2_v2v2(psd->pcp->bez.vec[opposite], psd->pcp->bez.vec[1], diff);
+                               }
+                       }
+                       WM_paint_cursor_tag_redraw(window, ar);
+                       break;
+               }
+               default:
+                       break;
+       }
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+
+void PAINTCURVE_OT_slide(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Slide Paint Curve Point";
+       ot->description = "Select and slide paint curve point";
+       ot->idname = "PAINTCURVE_OT_slide";
+
+       /* api callbacks */
+       ot->invoke = paintcurve_slide_invoke;
+       ot->modal = paintcurve_slide_modal;
+       ot->poll = paint_curve_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_boolean(ot->srna, "align", false, "Align Handles", "Aligns opposite point handle during transform");
+       RNA_def_boolean(ot->srna, "select", true, "Select", "Attempt to select a point handle before transform");
+}
+
+static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       PaintMode mode = BKE_paintmode_get_active_from_context(C);
+       const char *name;
+
+       switch (mode) {
+               case PAINT_TEXTURE_2D:
+               case PAINT_TEXTURE_PROJECTIVE:
+                       name = "PAINT_OT_image_paint";
+                       break;
+               case PAINT_WEIGHT:
+                       name = "PAINT_OT_weight_paint";
+                       break;
+               case PAINT_VERTEX:
+                       name = "PAINT_OT_vertex_paint";
+                       break;
+               case PAINT_SCULPT:
+                       name = "SCULPT_OT_brush_stroke";
+                       break;
+               default:
+                       return OPERATOR_PASS_THROUGH;
+       }
+
+       return WM_operator_name_call(C, name, WM_OP_INVOKE_DEFAULT, NULL);
+}
+
+void PAINTCURVE_OT_draw(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Draw Curve";
+       ot->description = "Draw curve";
+       ot->idname = "PAINTCURVE_OT_draw";
+
+       /* api callbacks */
+       ot->exec = paintcurve_draw_exec;
+       ot->poll = paint_curve_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_UNDO;
+}
+
+static int paintcurve_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       op->customdata = SET_INT_IN_POINTER(event->type);
+       WM_event_add_modal_handler(C, op);
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+static int paintcurve_cursor_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       if (event->type == GET_INT_FROM_POINTER(op->customdata) && event->val == KM_RELEASE)
+               return OPERATOR_FINISHED;
+
+       if (event->type == MOUSEMOVE) {
+               PaintMode mode = BKE_paintmode_get_active_from_context(C);
+
+               switch (mode) {
+                       case PAINT_TEXTURE_2D:
+                       {
+                               ARegion *ar = CTX_wm_region(C);
+                               SpaceImage *sima = CTX_wm_space_image(C);
+                               float location[2];
+
+                               if (!sima)
+                                       return OPERATOR_CANCELLED;
+
+                               UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
+                               copy_v2_v2(sima->cursor, location);
+                               WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+                               break;
+                       }
+                       default:
+                               ED_view3d_cursor3d_update(C, event->mval);
+                               break;
+               }
+       }
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+void PAINTCURVE_OT_cursor(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Place Cursor";
+       ot->description = "Place cursor";
+       ot->idname = "PAINTCURVE_OT_cursor";
+
+       /* api callbacks */
+       ot->invoke = paintcurve_cursor_invoke;
+       ot->modal = paintcurve_cursor_modal;
+       ot->poll = paint_curve_poll;
+
+       /* flags */
+       ot->flag = 0;
+}
index 34232c51ff73f320c4e985dc3f14328d9aea2b27..88b9f5bb29615cbce7a8ca2d593f7b3cefbd1a72 100644 (file)
@@ -43,6 +43,7 @@
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
+#include "BLI_threads.h"
 
 #include "PIL_time.h"
 
 #include "BKE_brush.h"
 #include "BKE_image.h"
 #include "BKE_main.h"
+#include "BKE_material.h"
 #include "BKE_mesh.h"
 #include "BKE_node.h"
 #include "BKE_paint.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
+#include "BKE_colortools.h"
 
 #include "BKE_editmesh.h"
 
 #include "UI_view2d.h"
 
 #include "ED_image.h"
+#include "ED_mesh.h"
 #include "ED_object.h"
 #include "ED_paint.h"
 #include "ED_screen.h"
@@ -82,6 +89,9 @@
 
 #include "GPU_draw.h"
 
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
 #include "IMB_colormanagement.h"
 
 #include "paint_intern.h"
@@ -102,14 +112,27 @@ typedef struct UndoImageTile {
 
        int x, y;
 
+       Image *ima;
        short source, use_float;
        char gen_type;
+       bool valid;
 } UndoImageTile;
 
 /* this is a static resource for non-globality,
  * Maybe it should be exposed as part of the
  * paint operation, but for now just give a public interface */
 static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
+static SpinLock undolock;
+
+void image_undo_init_locks(void)
+{
+       BLI_spin_init(&undolock);
+}
+
+void image_undo_end_locks(void)
+{
+       BLI_spin_end(&undolock);
+}
 
 ImagePaintPartialRedraw *get_imapaintpartial(void)
 {
@@ -122,26 +145,53 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
 }
 
 /* UNDO */
+typedef enum {
+       COPY = 0,
+       RESTORE = 1,
+       RESTORE_COPY = 2
+} CopyMode;
 
-static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
+static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
 {
-       /* copy or swap contents of tile->rect and region in ibuf->rect */
-       IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
-                   tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+       if (mode == COPY) {
+               /* copy or swap contents of tile->rect and region in ibuf->rect */
+               IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
+                           tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
 
-       if (ibuf->rect_float) {
-               SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+               if (ibuf->rect_float) {
+                       SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+               }
+               else {
+                       SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+               }
        }
        else {
-               SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
-       }
-       
-       if (restore)
+               if (mode == RESTORE_COPY)
+                       IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
+                               tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+               /* swap to the tmpbuf for easy copying */
+               if (ibuf->rect_float) {
+                       SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+               }
+               else {
+                       SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+               }
+
                IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE,
                            tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+
+               if (mode == RESTORE) {
+                       if (ibuf->rect_float) {
+                               SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+                       }
+                       else {
+                               SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+                       }
+               }
+       }
 }
 
-void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask)
+void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate)
 {
        ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
        UndoImageTile *tile;
@@ -160,6 +210,8 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
 
                                                *mask = tile->mask;
                                        }
+                                       if (validate)
+                                               tile->valid = true;
 
                                        return tile->rect.pt;
                                }
@@ -170,7 +222,7 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
        return NULL;
 }
 
-void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
+void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj)
 {
        ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
        UndoImageTile *tile;
@@ -179,10 +231,14 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
        void *data;
 
        /* check if tile is already pushed */
-       data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, NULL);
-       if (data)
-               return data;
-       
+
+       /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
+       if (!proj) {
+               data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true);
+               if (data)
+                       return data;
+       }
+
        if (*tmpibuf == NULL)
                *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
        
@@ -191,6 +247,11 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
        tile->x = x_tile;
        tile->y = y_tile;
 
+       /* add mask explicitly here */
+       if (mask)
+               *mask = tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
+                                        "UndoImageTile.mask");
+
        allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
        allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
        tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
@@ -200,12 +261,23 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
        tile->gen_type = ima->gen_type;
        tile->source = ima->source;
        tile->use_float = use_float;
+       tile->valid = true;
+       tile->ima = ima;
 
-       undo_copy_tile(tile, *tmpibuf, ibuf, 0);
-       undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
+       if (valid)
+               *valid = &tile->valid;
+
+       undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
 
+       if (proj)
+               BLI_spin_lock(&undolock);
+
+       undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
        BLI_addtail(lb, tile);
-       
+
+       if (proj)
+               BLI_spin_unlock(&undolock);
+
        return tile->rect.pt;
 }
 
@@ -222,6 +294,33 @@ void image_undo_remove_masks(void)
        }
 }
 
+static void image_undo_restore_runtime(ListBase *lb)
+{
+       ImBuf *ibuf, *tmpibuf;
+       UndoImageTile *tile;
+
+       tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
+                                IB_rectfloat | IB_rect);
+
+       for (tile = lb->first; tile; tile = tile->next) {
+               Image *ima = tile->ima;
+               ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+
+               undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
+
+               GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
+               if (ibuf->rect_float)
+                       ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+               if (ibuf->mipmap[0])
+                       ibuf->userflags |= IB_MIPMAP_INVALID;  /* force mipmap recreatiom */
+               ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+               BKE_image_release_ibuf(ima, ibuf, NULL);
+       }
+
+       IMB_freeImBuf(tmpibuf);
+}
+
 void ED_image_undo_restore(bContext *C, ListBase *lb)
 {
        Main *bmain = CTX_data_main(C);
@@ -273,7 +372,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
                        continue;
                }
 
-               undo_copy_tile(tile, tmpibuf, ibuf, 1);
+               undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
 
                GPU_free_image(ima); /* force OpenGL reload */
                if (ibuf->rect_float)
@@ -282,6 +381,8 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
                        ibuf->userflags |= IB_MIPMAP_INVALID;  /* force mipmap recreatiom */
                ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
 
+               DAG_id_tag_update(&ima->id, 0);
+
                BKE_image_release_ibuf(ima, ibuf, NULL);
        }
 
@@ -296,6 +397,42 @@ void ED_image_undo_free(ListBase *lb)
                MEM_freeN(tile->rect.pt);
 }
 
+static void image_undo_end(void)
+{
+       ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+       UndoImageTile *tile;
+       int deallocsize = 0;
+       int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
+
+       /* first dispose of invalid tiles (may happen due to drag dot for instance) */
+       for (tile = lb->first; tile;) {
+               if (!tile->valid) {
+                       UndoImageTile *tmp_tile = tile->next;
+                       deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
+                       MEM_freeN(tile->rect.pt);
+                       BLI_freelinkN (lb, tile);
+                       tile = tmp_tile;
+               }
+               else {
+                       tile = tile->next;
+               }
+       }
+
+       /* don't forget to remove the size of deallocated tiles */
+       undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize);
+
+       ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+}
+
+static void image_undo_invalidate(void)
+{
+       UndoImageTile *tile;
+       ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+
+       for (tile = lb->first; tile; tile = tile->next)
+               tile->valid = false;
+}
+
 /* Imagepaint Partial Redraw & Dirty Region */
 
 void ED_imapaint_clear_partial_redraw(void)
@@ -344,7 +481,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
 
        for (ty = tiley; ty <= tileh; ty++)
                for (tx = tilex; tx <= tilew; tx++)
-                       image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty);
+                       image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false);
 
        ibuf->userflags |= IB_BITMAPDIRTY;
        
@@ -373,6 +510,70 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
        }
 }
 
+/* paint blur kernels */
+BlurKernel *paint_new_blur_kernel(Brush *br)
+{
+       int i, j;
+       BlurKernel *kernel = MEM_mallocN(sizeof(BlurKernel), "blur kernel");
+       int pixel_len = br->blur_kernel_radius;
+       BlurKernelType type = br->blur_mode;
+
+       kernel->side = pixel_len * 2 + 1;
+       kernel->side_squared = kernel->side * kernel->side;
+       kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data");
+       kernel->pixel_len = pixel_len;
+
+       switch (type) {
+               case KERNEL_BOX:
+                       for (i = 0; i < kernel->side_squared; i++)
+                               kernel->wdata[i] = 1.0;
+                       break;
+
+               case KERNEL_GAUSSIAN:
+               {
+                       float standard_dev = pixel_len / 3.0; /* at standard deviation of 3.0 kernel is at about zero */
+                       int i_term = pixel_len + 1;
+
+                       /* make the necessary adjustment to the value for use in the normal distribution formula */
+                       standard_dev = standard_dev * standard_dev * 2;
+
+                       kernel->wdata[pixel_len + pixel_len * kernel->side] = 1.0;
+                       /* fill in all four quadrants at once */
+                       for (i = 0; i < i_term; i++) {
+                               for (j = 0; j < pixel_len; j++) {
+                                       float idist = pixel_len - i;
+                                       float jdist = pixel_len - j;
+
+                                       float value = exp((idist * idist + jdist * jdist) / standard_dev);
+
+                                       kernel->wdata[i + j * kernel->side] =
+                                       kernel->wdata[(kernel->side - j - 1) + i * kernel->side] =
+                                       kernel->wdata[(kernel->side - i - 1) + (kernel->side - j - 1) * kernel->side] =
+                                       kernel->wdata[j + (kernel->side - i - 1) * kernel->side] =
+                                               value;
+                               }
+                       }
+
+                       break;
+               }
+
+               default:
+                       printf("unidentified kernel type, aborting\n");
+                       MEM_freeN(kernel->wdata);
+                       MEM_freeN(kernel);
+                       return NULL;
+                       break;
+       }
+
+       return kernel;
+}
+
+void paint_delete_blur_kernel(BlurKernel *kernel)
+{
+       if (kernel->wdata)
+               MEM_freeN(kernel->wdata);
+}
+
 /************************ image paint poll ************************/
 
 static Brush *image_paint_brush(bContext *C)
@@ -432,11 +633,57 @@ typedef struct PaintOperation {
        void *custom_paint;
 
        float prevmouse[2];
+       float startmouse[2];
        double starttime;
 
+       void *cursor;
        ViewContext vc;
 } PaintOperation;
 
+bool paint_use_opacity_masking(Brush *brush)
+{
+       return (brush->flag & BRUSH_AIRBRUSH) ||
+              (brush->flag & BRUSH_DRAG_DOT) ||
+              (brush->flag & BRUSH_ANCHORED) ||
+              (brush->imagepaint_tool == PAINT_TOOL_SMEAR) ||
+              (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) ||
+              (brush->imagepaint_tool == PAINT_TOOL_FILL) ||
+              (brush->flag & BRUSH_USE_GRADIENT) ||
+                  (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)) ?
+                   false : true;
+}
+
+void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance,
+                           float pressure, float color[3], struct ColorManagedDisplay *display)
+{
+       if (invert)
+               copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br));
+       else {
+               if (br->flag & BRUSH_USE_GRADIENT) {
+                       switch (br->gradient_stroke_mode) {
+                               case BRUSH_GRADIENT_PRESSURE:
+                                       do_colorband(br->gradient, pressure, color);
+                                       break;
+                               case BRUSH_GRADIENT_SPACING_REPEAT:
+                               {
+                                       float coord = fmod(distance / br->gradient_spacing, 1.0);
+                                       do_colorband(br->gradient, coord, color);
+                                       break;
+                               }
+                               case BRUSH_GRADIENT_SPACING_CLAMP:
+                               {
+                                       do_colorband(br->gradient, distance / br->gradient_spacing, color);
+                                       break;
+                               }
+                       }
+               }
+               else
+                       copy_v3_v3(color, BKE_brush_color_get(scene, br));
+       }
+       if (color_correction)
+               IMB_colormanagement_display_to_scene_linear_v3(color, display);
+}
+
 void paint_brush_init_tex(Brush *brush)
 {
        /* init mtex nodes */
@@ -462,26 +709,54 @@ void paint_brush_exit_tex(Brush *brush)
        }
 }
 
+static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customdata)
+{
+       PaintOperation *pop = (PaintOperation *)customdata;
+
+       if (pop) {
+               glEnable(GL_LINE_SMOOTH);
+               glEnable(GL_BLEND);
+
+               glLineWidth(4.0);
+               glColor4ub(0, 0, 0, 255);
+               sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
+               glLineWidth(2.0);
+               glColor4ub(255, 255, 255, 255);
+               sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
+               glLineWidth(1.0);
+
+               glDisable(GL_BLEND);
+               glDisable(GL_LINE_SMOOTH);
+       }
+}
+
 
-static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mouse[2])
+static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2])
 {
        Scene *scene = CTX_data_scene(C);
        ToolSettings *settings = scene->toolsettings;
        PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
+       Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
        int mode = RNA_enum_get(op->ptr, "mode");
        view3d_set_viewcontext(C, &pop->vc);
 
-       pop->prevmouse[0] = mouse[0];
-       pop->prevmouse[1] = mouse[1];
+       copy_v2_v2(pop->prevmouse, mouse);
+       copy_v2_v2(pop->startmouse, mouse);
+
+       if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
+               pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, gradient_draw_line, pop);
+       }
 
        /* initialize from context */
        if (CTX_wm_region_view3d(C)) {
+               Object *ob = OBACT;
+               paint_proj_mesh_data_ensure(C, ob, op);
                pop->mode = PAINT_MODE_3D_PROJECT;
-               pop->custom_paint = paint_proj_new_stroke(C, OBACT, pop->prevmouse, mode);
+               pop->custom_paint = paint_proj_new_stroke(C, ob, mouse, mode);
        }
        else {
                pop->mode = PAINT_MODE_2D;
-               pop->custom_paint = paint_2d_new_stroke(C, op);
+               pop->custom_paint = paint_2d_new_stroke(C, op, mode);
        }
 
        if (!pop->custom_paint) {
@@ -491,52 +766,69 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mou
 
        settings->imapaint.flag |= IMAGEPAINT_DRAWING;
        ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
-                                ED_image_undo_restore, ED_image_undo_free);
-
-       {
-               UnifiedPaintSettings *ups = &settings->unified_paint_settings;
-               ups->stroke_active = true;
-       }
+                                ED_image_undo_restore, ED_image_undo_free, NULL);
 
        return pop;
 }
 
+/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
+static void paint_stroke_restore(void)
+{
+       ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+       image_undo_restore_runtime(lb);
+       image_undo_invalidate();
+}
+
 static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
 {
        PaintOperation *pop = paint_stroke_mode_data(stroke);
        Scene *scene = CTX_data_scene(C);
-       Brush *brush = BKE_paint_brush(&scene->toolsettings->imapaint.paint);
+       ToolSettings *toolsettings = CTX_data_tool_settings(C);
+       UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
+       Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
+
+       float alphafac = (brush->flag & BRUSH_ACCUMULATE) ? ups->overlap_factor : 1.0f;
 
        /* initial brush values. Maybe it should be considered moving these to stroke system */
-       float startsize = (float)BKE_brush_size_get(scene, brush);
        float startalpha = BKE_brush_alpha_get(scene, brush);
 
        float mouse[2];
        float pressure;
+       float size;
+       float distance = paint_stroke_distance_get(stroke);
        int eraser;
 
        RNA_float_get_array(itemptr, "mouse", mouse);
        pressure = RNA_float_get(itemptr, "pressure");
        eraser = RNA_boolean_get(itemptr, "pen_flip");
+       size = max_ff(1.0f, RNA_float_get(itemptr, "size"));
+
+       /* stroking with fill tool only acts on stroke end */
+       if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
+               copy_v2_v2(pop->prevmouse, mouse);
+               return;
+       }
 
        if (BKE_brush_use_alpha_pressure(scene, brush))
-               BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure));
-       if (BKE_brush_use_size_pressure(scene, brush))
-               BKE_brush_size_set(scene, brush, (int)max_ff(1.0f, startsize * pressure));
+               BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure * alphafac));
+       else
+               BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac));
+
+       if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) {
+               paint_stroke_restore();
+       }
 
        if (pop->mode == PAINT_MODE_3D_PROJECT) {
-               paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse);
+               paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse, pressure, distance, size);
        }
        else {
-               paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser);
+               paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size);
        }
 
-       pop->prevmouse[0] = mouse[0];
-       pop->prevmouse[1] = mouse[1];
+       copy_v2_v2(pop->prevmouse, mouse);
 
        /* restore brush values */
        BKE_brush_alpha_set(scene, brush, startalpha);
-       BKE_brush_size_set(scene, brush, startsize);
 }
 
 static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, bool final)
@@ -554,11 +846,39 @@ static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, b
 static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
 {
        Scene *scene = CTX_data_scene(C);
-       ToolSettings *settings = scene->toolsettings;
+       ToolSettings *toolsettings = scene->toolsettings;
        PaintOperation *pop = paint_stroke_mode_data(stroke);
+       Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
 
-       settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+       toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
 
+       if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
+               if (brush->flag & BRUSH_USE_GRADIENT) {
+                       if (pop->mode == PAINT_MODE_2D) {
+                               paint_2d_gradient_fill(C, brush, pop->startmouse, pop->prevmouse, pop->custom_paint);
+                       }
+                       else {
+                               paint_proj_stroke(C, pop->custom_paint, pop->startmouse, pop->prevmouse, 1.0, 0.0, BKE_brush_size_get(scene, brush));
+                               /* two redraws, one for GPU update, one for notification */
+                               paint_proj_redraw(C, pop->custom_paint, false);
+                               paint_proj_redraw(C, pop->custom_paint, true);
+                       }
+               }
+               else {
+                       if (pop->mode == PAINT_MODE_2D) {
+                               float color[3];
+
+                               srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush));
+                               paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint);
+                       }
+                       else {
+                               paint_proj_stroke(C, pop->custom_paint, pop->startmouse, pop->prevmouse, 1.0, 0.0, BKE_brush_size_get(scene, brush));
+                               /* two redraws, one for GPU update, one for notification */
+                               paint_proj_redraw(C, pop->custom_paint, false);
+                               paint_proj_redraw(C, pop->custom_paint, true);
+                       }
+               }
+       }
        if (pop->mode == PAINT_MODE_3D_PROJECT) {
                paint_proj_stroke_done(pop->custom_paint);
        }
@@ -566,7 +886,11 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
                paint_2d_stroke_done(pop->custom_paint);
        }
 
-       ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+       if (pop->cursor) {
+               WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor);
+       }
+
+       image_undo_end();
 
        /* duplicate warning, see texpaint_init */
 #if 0
@@ -576,43 +900,41 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
                BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile);
 #endif
        MEM_freeN(pop);
-
-       {
-               UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
-               ups->stroke_active = false;
-       }
-}
-
-static bool paint_stroke_test_start(bContext *UNUSED(C), wmOperator *UNUSED(op), const float UNUSED(mouse[2]))
-{
-       return true;
 }
 
-
-static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static bool paint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
 {
        PaintOperation *pop;
-       float mouse[2];
-       int retval;
 
        /* TODO Should avoid putting this here. Instead, last position should be requested
         * from stroke system. */
-       mouse[0] = event->mval[0];
-       mouse[1] = event->mval[1];
 
        if (!(pop = texture_paint_init(C, op, mouse))) {
-               return OPERATOR_CANCELLED;
+               return false;
        }
 
-       op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start,
+       paint_stroke_set_mode_data(op->customdata, pop);
+
+       return true;
+}
+
+
+static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       int retval;
+
+       op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start,
                                          paint_stroke_update_step,
                                          paint_stroke_redraw,
                                          paint_stroke_done, event->type);
-       paint_stroke_set_mode_data(op->customdata, pop);
+
+       if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+               paint_stroke_data_free(op);
+               return OPERATOR_FINISHED;
+       }
        /* add modal handler */
        WM_event_add_modal_handler(C, op);
 
-       retval = op->type->modal(C, op, event);
        OPERATOR_RETVAL_CHECK(retval);
        BLI_assert(retval == OPERATOR_RUNNING_MODAL);
 
@@ -637,12 +959,10 @@ static int paint_exec(bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        }
 
-       op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start,
+       op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start,
                                          paint_stroke_update_step,
                                          paint_stroke_redraw,
                                          paint_stroke_done, 0);
-       paint_stroke_set_mode_data(op->customdata, pop);
-
        /* frees op->customdata */
        paint_stroke_exec(C, op);
 
@@ -686,9 +1006,9 @@ int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
 
        if (!rv3d) {
                SpaceImage *sima = CTX_wm_space_image(C);
-               ARegion *ar = CTX_wm_region(C);
 
                if (sima->mode == SI_MODE_PAINT) {
+                       ARegion *ar = CTX_wm_region(C);
                        ED_space_image_get_zoom(sima, ar, zoomx, zoomy);
 
                        return 1;
@@ -847,17 +1167,39 @@ void PAINT_OT_grab_clone(wmOperatorType *ot)
 typedef struct {
        bool show_cursor;
        short event_type;
-} SampleColorData;
+       float initcolor[3];
+       bool sample_palette;
+}      SampleColorData;
+
+
+static void sample_color_update_header(SampleColorData *data, bContext *C)
+{
+#define HEADER_LENGTH 150
+       char msg[HEADER_LENGTH];
+       ScrArea *sa = CTX_wm_area(C);
+
+       if (sa) {
+               BLI_snprintf(msg, HEADER_LENGTH,
+                            "Sample color for %s",
+                            !data->sample_palette ?
+                            "Brush. Use Left Click to sample for palette instead" :
+                            "Palette. Use Left Click to sample more colors");
+               ED_area_headerprint(sa, msg);
+       }
+
+#undef HEADER_LENGTH
+}
 
 static int sample_color_exec(bContext *C, wmOperator *op)
 {
        Paint *paint = BKE_paint_get_active_from_context(C);
        Brush *brush = BKE_paint_brush(paint);
+       PaintMode mode = BKE_paintmode_get_active_from_context(C);
        ARegion *ar = CTX_wm_region(C);
        wmWindow *win = CTX_wm_window(C);
        bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
        int location[2];
-
+       bool use_palette;
        paint->flags &= ~PAINT_SHOW_BRUSH;
 
        /* force redraw without cursor */
@@ -865,7 +1207,9 @@ static int sample_color_exec(bContext *C, wmOperator *op)
        WM_redraw_windows(C);
 
        RNA_int_get_array(op->ptr, "location", location);
-       paint_sample_color(C, ar, location[0], location[1]);
+       use_palette = RNA_boolean_get(op->ptr, "palette");
+
+       paint_sample_color(C, ar, location[0], location[1], mode == PAINT_TEXTURE_PROJECTIVE, use_palette);
 
        if (show_cursor) {
                paint->flags |= PAINT_SHOW_BRUSH;
@@ -878,7 +1222,9 @@ static int sample_color_exec(bContext *C, wmOperator *op)
 
 static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
+       Scene *scene = CTX_data_scene(C);
        Paint *paint = BKE_paint_get_active_from_context(C);
+       PaintMode mode = BKE_paintmode_get_active_from_context(C);
        Brush *brush = BKE_paint_brush(paint);
        SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample color custom data");
        ARegion *ar = CTX_wm_region(C);
@@ -886,18 +1232,24 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
 
        data->event_type = event->type;
        data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
+       copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, brush));
+       data->sample_palette = false;
        op->customdata = data;
        paint->flags &= ~PAINT_SHOW_BRUSH;
 
+       sample_color_update_header(data, C);
+
+       WM_event_add_modal_handler(C, op);
+
        /* force redraw without cursor */
        WM_paint_cursor_tag_redraw(win, ar);
        WM_redraw_windows(C);
 
        RNA_int_set_array(op->ptr, "location", event->mval);
-       paint_sample_color(C, ar, event->mval[0], event->mval[1]);
+
+       paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false);
        WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
 
-       WM_event_add_modal_handler(C, op);
        WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
 
        return OPERATOR_RUNNING_MODAL;
@@ -905,17 +1257,27 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
 
 static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
 {
+       Scene *scene = CTX_data_scene(C);
        SampleColorData *data = op->customdata;
        Paint *paint = BKE_paint_get_active_from_context(C);
        Brush *brush = BKE_paint_brush(paint);
+       PaintMode mode = BKE_paintmode_get_active_from_context(C);
 
        if ((event->type == data->event_type) && (event->val == KM_RELEASE)) {
+               ScrArea *sa = CTX_wm_area(C);
+
                if (data->show_cursor) {
                        paint->flags |= PAINT_SHOW_BRUSH;
                }
 
+               if (data->sample_palette) {
+                       BKE_brush_color_set(scene, brush, data->initcolor);
+                       RNA_boolean_set(op->ptr, "palette", true);
+               }
                WM_cursor_modal_restore(CTX_wm_window(C));
                MEM_freeN(data);
+               ED_area_headerprint(sa, NULL);
+
                return OPERATOR_FINISHED;
        }
 
@@ -924,10 +1286,22 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
                {
                        ARegion *ar = CTX_wm_region(C);
                        RNA_int_set_array(op->ptr, "location", event->mval);
-                       paint_sample_color(C, ar, event->mval[0], event->mval[1]);
+                       paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false);
                        WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
                        break;
                }
+
+               case LEFTMOUSE:
+                       if (event->val == KM_PRESS) {
+                               ARegion *ar = CTX_wm_region(C);
+                               RNA_int_set_array(op->ptr, "location", event->mval);
+                               paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, true);
+                               if (!data->sample_palette) {
+                                       data->sample_palette = true;
+                                       sample_color_update_header(data, C);
+                               }
+                       }
+                       break;
        }
 
        return OPERATOR_RUNNING_MODAL;
@@ -956,6 +1330,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
 
        /* properties */
        RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "Cursor location in region coordinates", 0, 16384);
+       RNA_def_boolean(ot->srna, "palette", 0, "Palette", "Add color to palette");
 }
 
 /******************** texture paint toggle operator ********************/
@@ -973,13 +1348,84 @@ static int texture_paint_toggle_poll(bContext *C)
        return 1;
 }
 
+
+/* Make sure that active object has a material, and assign UVs and image layers if they do not exist */
+void paint_proj_mesh_data_ensure(bContext *C, Object *ob, wmOperator *op)
+{
+       Mesh *me;
+       int layernum;
+       bool add_material = false;
+       ImagePaintSettings *imapaint = &(CTX_data_tool_settings(C)->imapaint);
+       Brush *br = BKE_paint_brush(&imapaint->paint);
+
+       /* no material, add one */
+       if (ob->totcol == 0) {
+               add_material = true;
+       }
+       else {
+               /* there may be material slots but they may be empty, check */
+               bool has_material = false;
+               int i;
+
+               for (i = 1; i < ob->totcol + 1; i++) {
+                       Material *ma = give_current_material(ob, i);
+                       if (ma) {
+                               has_material = true;
+                               if (!ma->texpaintslot) {
+                                       proj_paint_add_slot(C, MAP_COL, ma);
+                               }
+                       }
+               }
+
+               if (!has_material)
+                       add_material = true;
+       }
+
+       if (add_material) {
+               Material *ma = BKE_material_add(CTX_data_main(C), "Material");
+               /* no material found, just assign to first slot */
+               assign_material(ob, ma, 1, BKE_MAT_ASSIGN_USERPREF);
+               proj_paint_add_slot(C, MAP_COL, ma);
+       }
+
+       me = BKE_mesh_from_object(ob);
+       layernum = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+
+       if (layernum == 0) {
+               BKE_reportf(op->reports, RPT_WARNING, "Object did not have UV map. Recommend manual unwrap");
+
+               ED_mesh_uv_texture_add(me, "UVMap", true);
+       }
+
+       /* Make sure we have a stencil to paint on! */
+       if (br->imagepaint_tool == PAINT_TOOL_MASK) {
+               imapaint->flag |= IMAGEPAINT_PROJECT_LAYER_STENCIL;
+
+               if (imapaint->stencil == NULL) {
+                       int width;
+                       int height;
+                       Main *bmain = CTX_data_main(C);
+                       float color[4] = {0.0, 0.0, 0.0, 1.0};
+
+                       /* should not be allowed, but just in case */
+                       if (imapaint->slot_xresolution_default == 0)
+                               imapaint->slot_xresolution_default = 1024;
+                       if (imapaint->slot_yresolution_default == 0)
+                               imapaint->slot_yresolution_default = 1024;
+
+                       width = imapaint->slot_xresolution_default;
+                       height = imapaint->slot_yresolution_default;
+                       imapaint->stencil = BKE_image_add_generated(bmain, width, height, "Stencil", 32, false, IMA_GENTYPE_BLANK, color);
+               }
+       }
+}
+