Alpha mask textures porting part 1: Support for projective texturing.

Also add random mapping to brushes.
This commit is contained in:
2013-03-25 01:00:16 +00:00
parent 48a256c910
commit ceb3225db7
16 changed files with 207 additions and 12 deletions

View File

@@ -112,3 +112,18 @@ def brush_texture_settings(layout, brush, sculpt):
col = layout.column(align=True)
col.label(text="Sample Bias:")
col.prop(brush, "texture_sample_bias", slider=True, text="")
def brush_mask_texture_settings(layout, brush):
mask_tex_slot = brush.mask_texture_slot
if(brush.mask_texture):
layout.label(text="Mask Mapping:")
col = layout.column()
col.active = brush.brush_capabilities.has_texture_angle
col.prop(mask_tex_slot, "angle", text="")
# scale and offset
split = layout.split()
split.prop(mask_tex_slot, "offset")
split.prop(mask_tex_slot, "scale")

View File

@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bl_ui.properties_paint_common import UnifiedPaintPanel, brush_texture_settings
from bl_ui.properties_paint_common import UnifiedPaintPanel, brush_texture_settings, brush_mask_texture_settings
from bpy.app.translations import pgettext_iface as iface_
@@ -729,6 +729,28 @@ class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
brush_texture_settings(col, brush, 0)
class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
bl_label = "Texture Mask"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
brush = context.tool_settings.image_paint.brush
tex_slot_alpha = brush.mask_texture_slot
self.layout.prop(brush, 'use_mask', text="")
def draw(self, context):
layout = self.layout
brush = context.tool_settings.image_paint.brush
tex_slot_alpha = brush.mask_texture_slot
col = layout.column()
col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
brush_mask_texture_settings(col, brush)
class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, Panel):
bl_label = "Tool"
bl_options = {'DEFAULT_CLOSED'}

View File

@@ -21,6 +21,7 @@ import bpy
from bpy.types import Menu, Panel
from bl_ui.properties_paint_common import UnifiedPaintPanel
from bl_ui.properties_paint_common import brush_texture_settings
from bl_ui.properties_paint_common import brush_mask_texture_settings
class View3DPanel():
@@ -782,6 +783,34 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
sub.prop(brush, "texture_overlay_alpha", text="Alpha")
class VIEW3D_PT_tools_mask_texture(View3DPanel, Panel):
bl_context = "imagepaint"
bl_label = "Texture Mask"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
brush = context.tool_settings.image_paint.brush
return (context.image_paint_object and brush and brush.image_tool != 'SOFTEN')
def draw_header(self, context):
brush = context.tool_settings.image_paint.brush
tex_slot_alpha = brush.mask_texture_slot
self.layout.prop(brush, 'use_mask', text="")
def draw(self, context):
layout = self.layout
brush = context.tool_settings.image_paint.brush
tex_slot_alpha = brush.mask_texture_slot
col = layout.column()
col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
brush_mask_texture_settings(col, brush)
class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
bl_label = "Stroke"
bl_options = {'DEFAULT_CLOSED'}

View File

@@ -42,7 +42,7 @@ extern "C" {
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 266
#define BLENDER_SUBVERSION 3
#define BLENDER_SUBVERSION 4
/* 262 was the last editmesh release but it has compatibility code for bmesh data */
#define BLENDER_MINVERSION 262

View File

@@ -78,6 +78,8 @@ float BKE_brush_sample_tex_3D(const Scene *scene, struct Brush *br, const float
float rgba[4], const int thread, struct ImagePool *pool);
float BKE_brush_sample_tex_2D(const struct Scene *scene, struct Brush *brush, const float xy[2],
float rgba[4]);
float BKE_brush_sample_masktex (const Scene *scene, struct Brush *br,const float point[3],
const int thread, struct ImagePool *pool);
void BKE_brush_imbuf_new(const struct Scene *scene, struct Brush *brush, short flt, short texfalloff, int size,
struct ImBuf **imbuf, int use_color_correction);

View File

@@ -107,6 +107,7 @@ static void brush_defaults(Brush *brush)
/* BRUSH TEXTURE SETTINGS */
default_mtex(&brush->mtex);
default_mtex(&brush->mask_mtex);
brush->texture_sample_bias = 0; /* value to added to texture samples */
brush->texture_overlay_alpha = 33;
@@ -152,6 +153,9 @@ Brush *BKE_brush_copy(Brush *brush)
if (brush->mtex.tex)
id_us_plus((ID *)brush->mtex.tex);
if (brush->mask_mtex.tex)
id_us_plus((ID *)brush->mask_mtex.tex);
if (brush->icon_imbuf)
brushn->icon_imbuf = IMB_dupImBuf(brush->icon_imbuf);
@@ -174,6 +178,9 @@ 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--;
if (brush->icon_imbuf)
IMB_freeImBuf(brush->icon_imbuf);
@@ -185,6 +192,7 @@ void BKE_brush_free(Brush *brush)
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);
}
@@ -514,7 +522,9 @@ float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
float radius = 1.0f; /* Quite warnings */
float co[3];
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW ||
mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM)
{
/* keep coordinates relative to mouse */
rotation += ups->brush_rotation;
@@ -575,6 +585,60 @@ float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
return intensity;
}
float BKE_brush_sample_masktex (const Scene *scene, Brush *br,
const float point[3],
const int thread,
struct ImagePool *pool) {
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
MTex *mtex = &br->mask_mtex;
if (mtex && mtex->tex) {
float rotation = -mtex->rot;
float point_2d[2] = {point[0], point[1]};
float x = 0.0f, y = 0.0f; /* Quite warnings */
float radius = 1.0f; /* Quite warnings */
float co[3];
float rgba[4], intensity = 1.0;
point_2d[0] -= ups->tex_mouse[0];
point_2d[1] -= ups->tex_mouse[1];
/* use pressure adjusted size for fixed mode */
radius = ups->pixel_radius;
x = point_2d[0];
y = point_2d[1];
x /= radius;
y /= radius;
/* it is probably worth optimizing for those cases where
* the texture is not rotated by skipping the calls to
* atan2, sqrtf, sin, and cos. */
if (rotation > 0.001f || rotation < -0.001f) {
const float angle = atan2f(y, x) + rotation;
const float flen = sqrtf(x * x + y * y);
x = flen * cosf(angle);
y = flen * sinf(angle);
}
x *= br->mask_mtex.size[0];
y *= br->mask_mtex.size[1];
co[0] = x + br->mask_mtex.ofs[0];
co[1] = y + br->mask_mtex.ofs[1];
co[2] = 0.0f;
externtex(mtex, co, &intensity,
rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
return intensity;
}
else {
return 1.0f;
}
}
/* Brush Sampling for 2D brushes. when we unify the brush systems this will be necessarily a separate function */
float BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2], float rgba[4])

View File

@@ -804,6 +804,10 @@ void BKE_texture_make_local(Tex *tex)
if (br->id.lib) is_lib = TRUE;
else is_local = TRUE;
}
if (br->mask_mtex.tex == tex) {
if (br->id.lib) is_lib = TRUE;
else is_local = TRUE;
}
br = br->id.next;
}
pa = bmain->particle.first;
@@ -877,6 +881,13 @@ void BKE_texture_make_local(Tex *tex)
tex->id.us--;
}
}
if (br->mask_mtex.tex == tex) {
if (br->id.lib == NULL) {
br->mask_mtex.tex = tex_new;
tex_new->id.us++;
tex->id.us--;
}
}
br = br->id.next;
}
pa = bmain->particle.first;

View File

@@ -146,6 +146,7 @@
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_text.h" // for txt_extended_ascii_as_utf8
#include "BKE_texture.h"
#include "BKE_tracking.h"
#include "BKE_sound.h"
@@ -1811,6 +1812,7 @@ static void lib_link_brush(FileData *fd, Main *main)
brush->id.flag -= LIB_NEED_LINK;
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);
}
}
@@ -9065,6 +9067,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
if (!MAIN_VERSION_ATLEAST(main, 266, 4)) {
Brush *brush;
for (brush = main->brush.first; brush; brush = brush->id.next) {
default_mtex(&brush->mask_mtex);
}
}
if (main->versionfile < 267) {
/* TIP: to initialize new variables added, use the new function

View File

@@ -1678,6 +1678,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
/* brush texture changes */
for (brush = main->brush.first; brush; brush = brush->id.next) {
default_mtex(&brush->mtex);
default_mtex(&brush->mask_mtex);
}
for (ma = main->mat.first; ma; ma = ma->id.next) {

View File

@@ -2865,6 +2865,7 @@ static void write_brushes(WriteData *wd, ListBase *idbase)
if (brush->id.properties) IDP_WriteProperty(brush->id.properties, wd);
writestruct(wd, DATA, "MTex", 1, &brush->mtex);
writestruct(wd, DATA, "MTex", 1, &brush->mask_mtex);
if (brush->curve)
write_curvemapping(wd, brush->curve);

View File

@@ -407,6 +407,9 @@ void paint_brush_init_tex(Brush *brush)
MTex *mtex = &brush->mtex;
if (mtex->tex && mtex->tex->nodetree)
ntreeTexBeginExecTree(mtex->tex->nodetree); /* has internal flag to detect it only does it once */
mtex = &brush->mask_mtex;
if (mtex->tex && mtex->tex->nodetree)
ntreeTexBeginExecTree(mtex->tex->nodetree);
}
}
@@ -416,6 +419,9 @@ void paint_brush_exit_tex(Brush *brush)
MTex *mtex = &brush->mtex;
if (mtex->tex && mtex->tex->nodetree)
ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
mtex = &brush->mask_mtex;
if (mtex->tex && mtex->tex->nodetree)
ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
}
}

View File

@@ -264,7 +264,8 @@ typedef struct ProjPaintState {
short is_ortho;
bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */
short is_texbrush; /* only to avoid running */
bool is_texbrush; /* only to avoid running */
bool is_maskbrush;
#ifndef PROJ_DEBUG_NOSEAMBLEED
float seam_bleed_px;
#endif
@@ -3905,6 +3906,10 @@ static void *do_projectpaint_thread(void *ph_v)
alpha = 1.0f;
}
if (ps->is_maskbrush) {
alpha *= BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
}
if (!ps->do_masking) {
/* for an aurbrush there is no real mask, so just multiply the alpha by it */
alpha *= falloff * BKE_brush_alpha_get(ps->scene, brush);
@@ -4153,14 +4158,15 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->blend = brush->blend;
/* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW ||
brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) ? false : true;
ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? 1 : 0;
ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || brush->mtex.brush_map_mode != MTEX_MAP_MODE_TILED) ? false : true;
ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
ps->is_maskbrush = (brush->flag & BRUSH_USE_MASK && brush->mask_mtex.tex) ? true : false;
}
else {
/* brush may be NULL*/
ps->do_masking = false;
ps->is_texbrush = false;
ps->is_maskbrush = false;
}
/* sizeof(ProjPixel), since we alloc this a _lot_ */
@@ -4321,7 +4327,8 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
}
/* override */
ps.is_texbrush = 0;
ps.is_texbrush = false;
ps.is_maskbrush = false;
ps.do_masking = false;
orig_brush_size = BKE_brush_size_get(scene, ps.brush);
BKE_brush_size_set(scene, ps.brush, 32); /* cover the whole image */

View File

@@ -178,14 +178,20 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)))
{
copy_v2_v2(ups->tex_mouse, mouse);
if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) &&
if (((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) ||
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)) &&
(brush->flag & BRUSH_RANDOM_ROTATION) &&
!(brush->flag & BRUSH_RAKE))
{
ups->brush_rotation = 2.0f * (float)M_PI * BLI_frand();
}
if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)) {
ups->tex_mouse[0] = BLI_frand() * stroke->vc.ar->sizex;
ups->tex_mouse[1] = BLI_frand() * stroke->vc.ar->sizey;;
} else {
copy_v2_v2(ups->tex_mouse, mouse);
}
}
if (brush->flag & BRUSH_ANCHORED) {

View File

@@ -56,6 +56,7 @@ typedef struct Brush {
struct BrushClone clone;
struct CurveMapping *curve; /* falloff curve */
struct MTex mtex;
struct MTex mask_mtex;
struct Brush *toggle_brush;
@@ -140,7 +141,8 @@ typedef enum BrushFlags {
/* temporary flag which sets up automatically for correct brush
* drawing when inverted modal operator is running */
BRUSH_INVERTED = (1 << 29),
BRUSH_ABSOLUTE_JITTER = (1 << 30)
BRUSH_ABSOLUTE_JITTER = (1 << 30),
BRUSH_USE_MASK = (1 << 31)
} BrushFlags;
/* Brush.sculpt_tool */

View File

@@ -499,6 +499,7 @@ typedef struct ColorMapping {
#define MTEX_MAP_MODE_TILED 1
#define MTEX_MAP_MODE_3D 2
#define MTEX_MAP_MODE_AREA 3
#define MTEX_MAP_MODE_RANDOM 4
/* **************** EnvMap ********************* */

View File

@@ -432,6 +432,7 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna)
{MTEX_MAP_MODE_AREA, "AREA_PLANE", 0, "Area Plane", ""},
{MTEX_MAP_MODE_TILED, "TILED", 0, "Tiled", ""},
{MTEX_MAP_MODE_3D, "3D", 0, "3D", ""},
{MTEX_MAP_MODE_RANDOM, "RANDOM", 0, "Random", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -439,6 +440,7 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna)
{MTEX_MAP_MODE_VIEW, "VIEW_PLANE", 0, "View Plane", ""},
{MTEX_MAP_MODE_TILED, "TILED", 0, "Tiled", ""},
{MTEX_MAP_MODE_3D, "3D", 0, "3D", ""},
{MTEX_MAP_MODE_RANDOM, "RANDOM", 0, "Random", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -911,6 +913,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RESTORE_MESH);
RNA_def_property_ui_text(prop, "Restore Mesh", "Allow a single dot to be carefully positioned");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_USE_MASK);
RNA_def_property_ui_text(prop, "Mask Texture", "Use a texture as mask for the brush");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* only for projection paint, TODO, other paint modes */
prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE);
@@ -953,6 +960,18 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Texture", "");
RNA_def_property_update(prop, NC_TEXTURE, "rna_Brush_update");
prop = RNA_def_property(srna, "mask_texture_slot", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BrushTextureSlot");
RNA_def_property_pointer_sdna(prop, NULL, "mask_mtex");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Mask Texture Slot", "");
prop = RNA_def_property(srna, "mask_texture", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "mask_mtex.tex");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Mask Texture", "");
RNA_def_property_update(prop, NC_TEXTURE, "rna_Brush_update");
prop = RNA_def_property(srna, "texture_overlay_alpha", PROP_INT, PROP_PERCENTAGE);
RNA_def_property_int_sdna(prop, NULL, "texture_overlay_alpha");
RNA_def_property_range(prop, 1, 100);