From 275c23f81c7b58cebea48926b368c94daf69adb4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 30 Sep 2012 11:15:40 +0000 Subject: [PATCH 001/143] fix for double free. --- .../compositor/operations/COM_GaussianXBlurOperation.cpp | 6 ++++-- .../compositor/operations/COM_GaussianYBlurOperation.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp index 984119b926a..3ab60a1faa9 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp @@ -108,8 +108,10 @@ void GaussianXBlurOperation::executePixel(float output[4], int x, int y, void *d void GaussianXBlurOperation::deinitExecution() { BlurBaseOperation::deinitExecution(); - MEM_freeN(this->m_gausstab); - this->m_gausstab = NULL; + if (this->m_gausstab) { + MEM_freeN(this->m_gausstab); + this->m_gausstab = NULL; + } deinitMutex(); } diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp index 192bc29e1ae..7ab00b202e1 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp @@ -109,8 +109,10 @@ void GaussianYBlurOperation::executePixel(float output[4], int x, int y, void *d void GaussianYBlurOperation::deinitExecution() { BlurBaseOperation::deinitExecution(); - MEM_freeN(this->m_gausstab); - this->m_gausstab = NULL; + if (this->m_gausstab) { + MEM_freeN(this->m_gausstab); + this->m_gausstab = NULL; + } deinitMutex(); } From 029c2156e9d9eb139cfe403a9e854f4895528e93 Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Sun, 30 Sep 2012 12:19:25 +0000 Subject: [PATCH 002/143] Fix #32706, Unnecesary refreshing of compositor. RNA doesn't need to do full update for label changes. --- source/blender/makesrna/intern/rna_nodetree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 3239e8ac596..af3a8691e08 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4315,7 +4315,7 @@ static void rna_def_node(BlenderRNA *brna) prop = RNA_def_property(srna, "label", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "label"); RNA_def_property_ui_text(prop, "Label", "Optional custom node label"); - RNA_def_property_update(prop, NC_NODE, "rna_Node_update"); + RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "inputs", NULL); From 4b6be3c19b22af74b2f5aa2f60f38662e6c4c113 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 30 Sep 2012 12:24:29 +0000 Subject: [PATCH 003/143] fix for using uninitialized blur falloff for dilate/erode node. --- source/blender/compositor/nodes/COM_DilateErodeNode.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.cpp b/source/blender/compositor/nodes/COM_DilateErodeNode.cpp index 5bd2f78d8a6..5cfc29ecce2 100644 --- a/source/blender/compositor/nodes/COM_DilateErodeNode.cpp +++ b/source/blender/compositor/nodes/COM_DilateErodeNode.cpp @@ -95,6 +95,7 @@ void DilateErodeNode::convertToOperations(ExecutionSystem *graph, CompositorCont operationx->setbNode(editorNode); operationx->setData(data); operationx->setQuality(quality); + operationx->setFalloff(PROP_SMOOTH); this->getInputSocket(0)->relinkConnections(operationx->getInputSocket(0), 0, graph); // this->getInputSocket(1)->relinkConnections(operationx->getInputSocket(1), 1, graph); // no size input yet graph->addOperation(operationx); @@ -102,6 +103,7 @@ void DilateErodeNode::convertToOperations(ExecutionSystem *graph, CompositorCont operationy->setbNode(editorNode); operationy->setData(data); operationy->setQuality(quality); + operationy->setFalloff(PROP_SMOOTH); this->getOutputSocket(0)->relinkConnections(operationy->getOutputSocket()); graph->addOperation(operationy); addLink(graph, operationx->getOutputSocket(), operationy->getInputSocket(0)); From 168ffbfb67302c7ee2d2d17941c0b3f8324d00e5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Sun, 30 Sep 2012 15:04:46 +0000 Subject: [PATCH 004/143] Revert changes made to support diffuse color when sculpting This changes are not stable enough and trying fix it could backfire in some other regressions which isn't wanted so much close to the release. This means objects will have gray color as diffuse which becomes darker in masked areas for 2.64. Proper fix is aimed for 2.65. This commit reverts 50827 and 50898. --- source/blender/blenlib/intern/pbvh.c | 4 - source/blender/gpu/GPU_buffers.h | 5 +- source/blender/gpu/GPU_draw.h | 2 - source/blender/gpu/intern/gpu_buffers.c | 109 +++++++----------------- source/blender/gpu/intern/gpu_draw.c | 15 ---- 5 files changed, 33 insertions(+), 102 deletions(-) diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c index 0bd9e68cb71..d3d8d371f60 100644 --- a/source/blender/blenlib/intern/pbvh.c +++ b/source/blender/blenlib/intern/pbvh.c @@ -1169,14 +1169,10 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) break; case PBVH_FACES: GPU_update_mesh_buffers(node->draw_buffers, - bvh->faces, - node->prim_indices, - node->totprim, bvh->verts, node->vert_indices, node->uniq_verts + node->face_verts, - node->face_vert_indices, CustomData_get_layer(bvh->vdata, CD_PAINT_MASK)); break; diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 745ca1ef2ac..1729ac06f5a 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -162,9 +162,8 @@ GPU_Buffers *GPU_build_mesh_buffers(int (*face_vert_indices)[4], struct MFace *mface, struct MVert *mvert, int *face_indices, int totface); -void GPU_update_mesh_buffers(GPU_Buffers *buffers, struct MFace *mface, int *face_indices, int totface, - struct MVert *mvert, int *vert_indices, int totvert, - int (*face_vert_indices)[4], const float *vmask); +void GPU_update_mesh_buffers(GPU_Buffers *buffers, struct MVert *mvert, + int *vert_indices, int totvert, const float *vmask); GPU_Buffers *GPU_build_grid_buffers(int *grid_indices, int totgrid, unsigned int **grid_hidden, int gridsize); diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 7d829bd57bf..285acb6bdde 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -75,8 +75,6 @@ void GPU_end_object_materials(void); int GPU_enable_material(int nr, void *attribs); void GPU_disable_material(void); -void GPU_material_diffuse_get(int nr, float diff[4]); - void GPU_set_material_alpha_blend(int alphablend); int GPU_get_material_alpha_blend(void); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 659cd4e944c..c44a181841e 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -54,7 +54,6 @@ #include "DNA_userdef_types.h" #include "GPU_buffers.h" -#include "GPU_draw.h" typedef enum { GPU_BUFFER_VERTEX_STATE = 1, @@ -1281,8 +1280,6 @@ typedef struct { char pad[2]; unsigned char color[3]; - float accum_color[3]; - int tot_color; } VertexBufferFormat; struct GPU_Buffers { @@ -1330,24 +1327,24 @@ static void gpu_colors_disable(VBO_State vbo_state) static float gpu_color_from_mask(float mask) { - return 1.0f - mask * 0.75f; + return (1.0f - mask) * 0.5f + 0.25f; } -static void gpu_color_from_mask_copy(float mask, const float diffuse_color[4], unsigned char out[3]) +static void gpu_color_from_mask_copy(float mask, unsigned char out[3]) { - float mask_color; + unsigned char color; + + color = gpu_color_from_mask(mask) * 255.0f; - mask_color = gpu_color_from_mask(mask) * 255.0f; - - out[0] = diffuse_color[0] * mask_color; - out[1] = diffuse_color[1] * mask_color; - out[2] = diffuse_color[2] * mask_color; + out[0] = color; + out[1] = color; + out[2] = color; } -static void gpu_color_from_mask_set(float mask, float diffuse_color[4]) +static void gpu_color_from_mask_set(float mask) { float color = gpu_color_from_mask(mask); - glColor3f(diffuse_color[0] * color, diffuse_color[1] * color, diffuse_color[2] * color); + glColor3f(color, color, color); } static float gpu_color_from_mask_quad(const CCGKey *key, @@ -1363,32 +1360,29 @@ static float gpu_color_from_mask_quad(const CCGKey *key, static void gpu_color_from_mask_quad_copy(const CCGKey *key, CCGElem *a, CCGElem *b, CCGElem *c, CCGElem *d, - const float *diffuse_color, unsigned char out[3]) { - float mask_color = + unsigned char color = gpu_color_from_mask((*CCG_elem_mask(key, a) + *CCG_elem_mask(key, b) + *CCG_elem_mask(key, c) + *CCG_elem_mask(key, d)) * 0.25f) * 255.0f; - out[0] = diffuse_color[0] * mask_color; - out[1] = diffuse_color[1] * mask_color; - out[2] = diffuse_color[2] * mask_color; + out[0] = color; + out[1] = color; + out[2] = color; } static void gpu_color_from_mask_quad_set(const CCGKey *key, CCGElem *a, CCGElem *b, - CCGElem *c, CCGElem *d, - float diffuse_color[4]) + CCGElem *c, CCGElem *d) { float color = gpu_color_from_mask_quad(key, a, b, c, d); - glColor3f(diffuse_color[0] * color, diffuse_color[1] * color, diffuse_color[2] * color); + glColor3f(color, color, color); } -void GPU_update_mesh_buffers(GPU_Buffers *buffers, MFace *mface, int *face_indices, int totface, - MVert *mvert, int *vert_indices, int totvert, - int (*face_vert_indices)[4], const float *vmask) +void GPU_update_mesh_buffers(GPU_Buffers *buffers, MVert *mvert, + int *vert_indices, int totvert, const float *vmask) { VertexBufferFormat *vert_data; int i; @@ -1410,40 +1404,8 @@ void GPU_update_mesh_buffers(GPU_Buffers *buffers, MFace *mface, int *face_indic copy_v3_v3(out->co, v->co); memcpy(out->no, v->no, sizeof(short) * 3); - zero_v3(out->accum_color); - out->tot_color = 0; - } - -#define UPDATE_VERTEX(face, vertex, index, diffuse_color) \ - { \ - VertexBufferFormat *out = vert_data + face_vert_indices[face][index]; \ - add_v3_v3(out->accum_color, diffuse_color); \ - out->tot_color++; \ - } (void)0 - - for (i = 0; i < totface; ++i) { - MFace *f = mface + face_indices[i]; - float diffuse_color[4]; - - GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); - - UPDATE_VERTEX(i, f->v1, 0, diffuse_color); - UPDATE_VERTEX(i, f->v2, 1, diffuse_color); - UPDATE_VERTEX(i, f->v3, 2, diffuse_color); - if (f->v4) - UPDATE_VERTEX(i, f->v4, 3, diffuse_color); - } -#undef UPDATE_VERTEX - - for (i = 0; i < totvert; ++i) { - VertexBufferFormat *out = vert_data + i; - if (out->tot_color) { - float diffuse_color[4]; - - mul_v3_v3fl(diffuse_color, out->accum_color, 1.0f / out->tot_color); - - gpu_color_from_mask_copy(vmask[vert_indices[i]], diffuse_color, out->color); - } + gpu_color_from_mask_copy(vmask[vert_indices[i]], + out->color); } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); @@ -1555,10 +1517,6 @@ void GPU_update_grid_buffers(GPU_Buffers *buffers, CCGElem **grids, for (i = 0; i < totgrid; ++i) { VertexBufferFormat *vd = vert_data; CCGElem *grid = grids[grid_indices[i]]; - const DMFlagMat *flags = &grid_flag_mats[grid_indices[i]]; - float diffuse_color[4]; - - GPU_material_diffuse_get(flags->mat_nr + 1, diffuse_color); for (y = 0; y < key->grid_size; y++) { for (x = 0; x < key->grid_size; x++) { @@ -1566,9 +1524,11 @@ void GPU_update_grid_buffers(GPU_Buffers *buffers, CCGElem **grids, copy_v3_v3(vd->co, CCG_elem_co(key, elem)); if (smooth) { - normal_float_to_short_v3(vd->no, CCG_elem_no(key, elem)); + normal_float_to_short_v3(vd->no, + CCG_elem_no(key, elem)); - gpu_color_from_mask_copy(*CCG_elem_mask(key, elem), diffuse_color, vd->color); + gpu_color_from_mask_copy(*CCG_elem_mask(key, elem), + vd->color); } vd++; } @@ -1601,7 +1561,6 @@ void GPU_update_grid_buffers(GPU_Buffers *buffers, CCGElem **grids, elems[1], elems[2], elems[3], - diffuse_color, vd->color); } } @@ -1810,9 +1769,6 @@ static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth) { const MVert *mvert = buffers->mvert; int i, j; - float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; - - glGetMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse_color); gpu_colors_enable(VBO_DISABLED); @@ -1828,7 +1784,7 @@ static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth) if (smooth) { for (j = 0; j < S; j++) { - gpu_color_from_mask_set(buffers->vmask[fv[j]], diffuse_color); + gpu_color_from_mask_set(buffers->vmask[fv[j]]); glNormal3sv(mvert[fv[j]].no); glVertex3fv(mvert[fv[j]].co); } @@ -1853,7 +1809,7 @@ static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth) fmask = (fmask + buffers->vmask[fv[3]]) * 0.25; else fmask /= 3.0f; - gpu_color_from_mask_set(fmask, diffuse_color); + gpu_color_from_mask_set(fmask); for (j = 0; j < S; j++) glVertex3fv(mvert[fv[j]].co); @@ -1869,9 +1825,6 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) { const CCGKey *key = &buffers->gridkey; int i, j, x, y, gridsize = buffers->gridkey.grid_size; - float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; - - glGetMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse_color); gpu_colors_enable(VBO_DISABLED); @@ -1900,7 +1853,7 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) if (smooth) { for (j = 0; j < 4; j++) { - gpu_color_from_mask_set(*CCG_elem_mask(key, e[j]), diffuse_color); + gpu_color_from_mask_set(*CCG_elem_mask(key, e[j])); glNormal3fv(CCG_elem_no(key, e[j])); glVertex3fv(CCG_elem_co(key, e[j])); } @@ -1913,7 +1866,7 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) CCG_elem_co(key, e[2]), CCG_elem_co(key, e[3])); glNormal3fv(fno); - gpu_color_from_mask_quad_set(key, e[0], e[1], e[2], e[3], diffuse_color); + gpu_color_from_mask_quad_set(key, e[0], e[1], e[2], e[3]); for (j = 0; j < 4; j++) glVertex3fv(CCG_elem_co(key, e[j])); @@ -1930,10 +1883,10 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) CCGElem *a = CCG_grid_elem(key, grid, x, y); CCGElem *b = CCG_grid_elem(key, grid, x, y + 1); - gpu_color_from_mask_set(*CCG_elem_mask(key, a), diffuse_color); + gpu_color_from_mask_set(*CCG_elem_mask(key, a)); glNormal3fv(CCG_elem_no(key, a)); glVertex3fv(CCG_elem_co(key, a)); - gpu_color_from_mask_set(*CCG_elem_mask(key, b), diffuse_color); + gpu_color_from_mask_set(*CCG_elem_mask(key, b)); glNormal3fv(CCG_elem_no(key, b)); glVertex3fv(CCG_elem_co(key, b)); } @@ -1959,7 +1912,7 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) CCG_elem_co(key, c)); glNormal3fv(fno); - gpu_color_from_mask_quad_set(key, a, b, c, d, diffuse_color); + gpu_color_from_mask_quad_set(key, a, b, c, d); } glVertex3fv(CCG_elem_co(key, a)); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 60e3c19a419..962bb0aed22 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -1440,21 +1440,6 @@ void GPU_disable_material(void) GPU_set_material_alpha_blend(GPU_BLEND_SOLID); } -void GPU_material_diffuse_get(int nr, float diff[4]) -{ - /* prevent index to use un-initialized array items */ - if (nr >= GMS.totmat) - nr = 0; - - /* no GPU_begin_object_materials, use default material */ - if (!GMS.matbuf) { - mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit); - } - else { - copy_v4_v4(diff, GMS.matbuf[nr].diff); - } -} - void GPU_end_object_materials(void) { GPU_disable_material(); From 846f11587674a0739f53ba3287f9ae6ccf6ee545 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 01:26:54 +0000 Subject: [PATCH 005/143] updated themes with active pose bone color. --- release/scripts/presets/interface_theme/back_to_black.xml | 1 + release/scripts/presets/interface_theme/blender_24x.xml | 1 + release/scripts/presets/interface_theme/elsyiun.xml | 1 + release/scripts/presets/interface_theme/hexagon.xml | 1 + release/scripts/presets/interface_theme/ubuntu_ambiance.xml | 1 + 5 files changed, 5 insertions(+) diff --git a/release/scripts/presets/interface_theme/back_to_black.xml b/release/scripts/presets/interface_theme/back_to_black.xml index 24f135e8548..805aa9bd184 100644 --- a/release/scripts/presets/interface_theme/back_to_black.xml +++ b/release/scripts/presets/interface_theme/back_to_black.xml @@ -9,6 +9,7 @@ handle_auto="#909000" handle_sel_auto="#f0ff40" bone_pose="#50c8ff" + bone_pose_active="#8cffff" bone_solid="#c8c8c8" bundle_solid="#c8c8c8" camera="#000000" diff --git a/release/scripts/presets/interface_theme/blender_24x.xml b/release/scripts/presets/interface_theme/blender_24x.xml index 79d1ed4ecf4..232276e300e 100644 --- a/release/scripts/presets/interface_theme/blender_24x.xml +++ b/release/scripts/presets/interface_theme/blender_24x.xml @@ -9,6 +9,7 @@ handle_auto="#909000" handle_sel_auto="#f0ff40" bone_pose="#50c8ff" + bone_pose_active="#8cffff" bone_solid="#c8c8c8" bundle_solid="#c8c8c8" camera="#000000" diff --git a/release/scripts/presets/interface_theme/elsyiun.xml b/release/scripts/presets/interface_theme/elsyiun.xml index bfeb3a0175e..7d4db75dc89 100644 --- a/release/scripts/presets/interface_theme/elsyiun.xml +++ b/release/scripts/presets/interface_theme/elsyiun.xml @@ -9,6 +9,7 @@ handle_auto="#909000" handle_sel_auto="#f0ff40" bone_pose="#50c8ff" + bone_pose_active="#8cffff" bone_solid="#c8c8c8" bundle_solid="#c8c8c8" camera="#000000" diff --git a/release/scripts/presets/interface_theme/hexagon.xml b/release/scripts/presets/interface_theme/hexagon.xml index 7727d860a90..61730583396 100644 --- a/release/scripts/presets/interface_theme/hexagon.xml +++ b/release/scripts/presets/interface_theme/hexagon.xml @@ -9,6 +9,7 @@ handle_auto="#909000" handle_sel_auto="#f0ff40" bone_pose="#50c8ff" + bone_pose_active="#8cffff" bone_solid="#c8c8c8" bundle_solid="#c8c8c8" camera="#000000" diff --git a/release/scripts/presets/interface_theme/ubuntu_ambiance.xml b/release/scripts/presets/interface_theme/ubuntu_ambiance.xml index 72852e27604..d54766ec88f 100644 --- a/release/scripts/presets/interface_theme/ubuntu_ambiance.xml +++ b/release/scripts/presets/interface_theme/ubuntu_ambiance.xml @@ -9,6 +9,7 @@ handle_auto="#909000" handle_sel_auto="#f0ff40" bone_pose="#50c8ff" + bone_pose_active="#8cffff" bone_solid="#c8c8c8" bundle_solid="#c8c8c8" camera="#000000" From fb2f24972308192cec68a20769eaa2f72fe61032 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 02:04:06 +0000 Subject: [PATCH 006/143] update UI introspection script for changes to blender. --- release/scripts/startup/bl_ui/space_userpref.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 444e9349e9f..64bf1e29348 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -20,7 +20,6 @@ import bpy from bpy.types import Header, Menu, Panel import os -import addon_utils def ui_items_general(col, context): @@ -1033,6 +1032,8 @@ class USERPREF_PT_addons(Panel): box.label(l) def draw(self, context): + import addon_utils + layout = self.layout userpref = context.user_preferences From a5367802acee857d4b36eb8c6ed2eef4c9ec17a8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 03:45:31 +0000 Subject: [PATCH 007/143] fix for crash deleting higher multi-res levels without mask data. --- source/blender/blenkernel/intern/multires.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 1c06d95a70b..245fa4aa375 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -666,7 +666,9 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) mdisp->totdisp = totdisp; mdisp->level = lvl; - multires_grid_paint_mask_downsample(&gpm[g], lvl); + if (gpm) { + multires_grid_paint_mask_downsample(&gpm[g], lvl); + } } } } From ded317840bffbf2bddc7887587292f2c5e9f8ce3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 04:00:41 +0000 Subject: [PATCH 008/143] fix for leak when freeing mask data in editmode. --- source/blender/editors/mesh/mesh_data.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 4637d926a62..735492cb553 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -761,7 +761,12 @@ static int mesh_customdata_clear_exec__internal(bContext *C, BLI_assert(CustomData_layertype_is_singleton(type) == TRUE); if (CustomData_has_layer(data, type)) { - CustomData_free_layers(data, type, tot); + if (me->edit_btmesh) { + BM_data_layer_free(me->edit_btmesh->bm, data, type); + } + else { + CustomData_free_layers(data, type, tot); + } DAG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); From a9efe26ab8ba8eca7f3d73c38e05fa007b665e61 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 04:59:21 +0000 Subject: [PATCH 009/143] DM_set_only_copy() wasn't setting only-copy flags for loops and polygons. (should have been added during bmesh merge) --- source/blender/blenkernel/intern/DerivedMesh.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 5e13fe78a43..cdae3148e6b 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -578,6 +578,8 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask) CustomData_set_only_copy(&dm->vertData, mask); CustomData_set_only_copy(&dm->edgeData, mask); CustomData_set_only_copy(&dm->faceData, mask); + CustomData_set_only_copy(&dm->loopData, mask); + CustomData_set_only_copy(&dm->polyData, mask); } void DM_add_vert_layer(DerivedMesh *dm, int type, int alloctype, void *layer) From df298490b841b4aa59f887dfd6fe720705cf5ca8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 05:19:57 +0000 Subject: [PATCH 010/143] mask data is no longer automatically added when sculpting (except when there is a multi-res modifier). --- source/blender/blenkernel/intern/multires.c | 15 ++- source/blender/blenlib/BLI_pbvh.h | 2 +- source/blender/editors/include/ED_sculpt.h | 6 +- source/blender/editors/object/object_bake.c | 4 +- .../blender/editors/object/object_modifier.c | 11 +- .../blender/editors/sculpt_paint/paint_hide.c | 2 +- source/blender/editors/sculpt_paint/sculpt.c | 86 +++++++++---- .../editors/sculpt_paint/sculpt_intern.h | 3 +- .../editors/sculpt_paint/sculpt_undo.c | 17 ++- source/blender/gpu/intern/gpu_buffers.c | 120 ++++++++++++------ .../blender/modifiers/intern/MOD_multires.c | 5 +- 11 files changed, 191 insertions(+), 80 deletions(-) diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 245fa4aa375..591524e5156 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -895,15 +895,16 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl CCGKey highGridKey, lowGridKey; CCGSubSurf *ss; int i, numGrids, highGridSize; + int has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); /* create subsurf DM from original mesh at high level */ cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, TRUE); + highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask); ss = ((CCGDerivedMesh *)highdm)->ss; /* create multires DM from original mesh at low level */ - lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, TRUE); + lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask); cddm->release(cddm); /* copy subsurf grids and replace them with low displaced grids */ @@ -1166,17 +1167,18 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm) CCGKey highGridKey, lowGridKey; CCGSubSurf *ss; int i, j, numGrids, highGridSize, lowGridSize; + int has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); /* create subsurf DM from original mesh at high level */ if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform); else cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, TRUE); + highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask); ss = ((CCGDerivedMesh *)highdm)->ss; /* create multires DM from original mesh and displacements */ - lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple, TRUE); + lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple, has_mask); cddm->release(cddm); /* gather grid data */ @@ -1228,12 +1230,13 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm) } else { DerivedMesh *cddm, *subdm; + int has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform); else cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, TRUE); + subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask); cddm->release(cddm); multiresModifier_disp_run(dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl); @@ -2109,7 +2112,7 @@ void multires_load_old(Object *ob, Mesh *me) * reference subsurfed dm with this option, before calling multiresModifier_disp_run(), * which implicitly expects both subsurfs from its first dm and oldGridData parameters to * be of the same "format"! */ - dm = multires_make_derived_from_derived(orig, mmd, ob, MULTIRES_ALLOC_PAINT_MASK); + dm = multires_make_derived_from_derived(orig, mmd, ob, 0); multires_load_old_dm(dm, me, mmd->totlvl + 1); diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h index 20d04f7881e..810b3b56386 100644 --- a/source/blender/blenlib/BLI_pbvh.h +++ b/source/blender/blenlib/BLI_pbvh.h @@ -233,7 +233,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, if (vi.grid) { \ vi.co = CCG_elem_co(vi.key, vi.grid); \ vi.fno = CCG_elem_no(vi.key, vi.grid); \ - vi.mask = CCG_elem_mask(vi.key, vi.grid); \ + vi.mask = vi.key->has_mask ? CCG_elem_mask(vi.key, vi.grid) : NULL; \ vi.grid = CCG_elem_next(vi.key, vi.grid); \ if (vi.gh) { \ if (BLI_BITMAP_GET(vi.gh, vi.gy * vi.gridsize + vi.gx)) \ diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index e908868df75..0381ecc1fb3 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -45,8 +45,12 @@ void sculpt_get_redraw_planes(float planes[4][4], struct ARegion *ar, void ED_sculpt_force_update(struct bContext *C); float *ED_sculpt_get_last_stroke(struct Object *ob); int ED_sculpt_minmax(struct bContext *C, float min[3], float max[3]); -void ED_sculpt_mask_layers_ensure(struct Object *ob, +int ED_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd); +enum { + ED_SCULPT_MASK_LAYER_CALC_VERT = (1 << 0), + ED_SCULPT_MASK_LAYER_CALC_LOOP = (1 << 1) +}; /* paint_ops.c */ void ED_operatortypes_paint(void); diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 0ea2f78a415..6d124377821 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -1031,7 +1031,7 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l tmp_mmd.lvl = *lvl; tmp_mmd.sculptlvl = *lvl; dm = multires_make_derived_from_derived(cddm, &tmp_mmd, ob, - MULTIRES_USE_LOCAL_MMD); + 0); cddm->release(cddm); } @@ -1052,7 +1052,7 @@ static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *l tmp_mmd.lvl = mmd->totlvl; tmp_mmd.sculptlvl = mmd->totlvl; dm = multires_make_derived_from_derived(cddm, &tmp_mmd, ob, - MULTIRES_USE_LOCAL_MMD); + 0); cddm->release(cddm); return dm; diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 6fe7ad05a70..d75ef78fc4c 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -159,8 +159,10 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc /* set totlvl from existing MDISPS layer if object already had it */ multiresModifier_set_levels_from_disps((MultiresModifierData *)new_md, ob); - /* ensure that grid paint mask layer is created */ - ED_sculpt_mask_layers_ensure(ob, (MultiresModifierData *)new_md); + if (ob->mode & OB_MODE_SCULPT) { + /* ensure that grid paint mask layer is created */ + ED_sculpt_mask_layers_ensure(ob, (MultiresModifierData *)new_md); + } } else if (type == eModifierType_Skin) { /* ensure skin-node customdata exists */ @@ -710,11 +712,6 @@ int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, Modi BLI_remlink(&ob->modifiers, md); modifier_free(md); - if (ob->type == OB_MESH) { - /* ensure mesh paint mask layer remains after applying */ - ED_sculpt_mask_layers_ensure(ob, NULL); - } - return 1; } diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index 2970bdfb5a4..bdd73cd6db3 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -197,7 +197,7 @@ static void partialvis_update_grids(Object *ob, for (x = 0; x < key.grid_size; x++) { CCGElem *elem = CCG_grid_elem(&key, grids[g], x, y); const float *co = CCG_elem_co(&key, elem); - float mask = *CCG_elem_mask(&key, elem); + float mask = key.has_mask ? *CCG_elem_mask(&key, elem) : 0.0f; /* skip grid element if not in the effected area */ if (is_effected(area, planes, co, mask)) { diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 05b5b90344c..5f17d44a881 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1225,7 +1225,7 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, ss->cache->view_normal, vd.no, vd.fno, - smooth_mask ? 0 : *vd.mask); + smooth_mask ? 0 : (vd.mask ? *vd.mask : 0.0f)); if (smooth_mask) { float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask; val *= fade * bstrength; @@ -1524,7 +1524,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) /* offset vertex */ float fade = tex_strength(ss, brush, vd.co, test.dist, ss->cache->sculpt_normal_symm, vd.no, - vd.fno, *vd.mask); + vd.fno, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -1580,7 +1580,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod /* offset vertex */ const float fade = tex_strength(ss, brush, vd.co, test.dist, ss->cache->sculpt_normal_symm, - vd.no, vd.fno, *vd.mask); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); float val1[3]; float val2[3]; @@ -1623,7 +1623,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode if (sculpt_brush_test(&test, vd.co)) { float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, ss->cache->view_normal, vd.no, - vd.fno, *vd.mask); + vd.fno, vd.mask ? *vd.mask : 0.0f); float val[3]; sub_v3_v3v3(val, test.location, vd.co); @@ -1677,7 +1677,8 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { if (sculpt_brush_test(&test, origco[vd.i])) { const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist, - ss->cache->sculpt_normal_symm, origno[vd.i], NULL, *vd.mask); + ss->cache->sculpt_normal_symm, origno[vd.i], + NULL, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -1718,7 +1719,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, ss->cache->sculpt_normal_symm, - vd.no, vd.fno, *vd.mask); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -1767,7 +1768,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, ss->cache->sculpt_normal_symm, - vd.no, vd.fno, *vd.mask); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -1815,7 +1816,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode if (sculpt_brush_test(&test, origco[vd.i])) { const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist, ss->cache->sculpt_normal_symm, - origno[vd.i], NULL, *vd.mask); + origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -1868,7 +1869,7 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod if (sculpt_brush_test(&test, origco[vd.i])) { const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist, ss->cache->sculpt_normal_symm, - origno[vd.i], NULL, *vd.mask); + origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f); mul_v3_m4v3(proxy[vd.i], m, origco[vd.i]); sub_v3_v3(proxy[vd.i], origco[vd.i]); @@ -1921,7 +1922,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode if (sculpt_brush_test(&test, origco[vd.i])) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, ss->cache->sculpt_normal_symm, - vd.no, vd.fno, *vd.mask); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); float *disp = &layer_disp[vd.i]; float val[3]; @@ -1974,7 +1975,8 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno { if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, - ss->cache->view_normal, vd.no, vd.fno, *vd.mask); + ss->cache->view_normal, + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); float val[3]; if (vd.fno) copy_v3_v3(val, vd.fno); @@ -2315,7 +2317,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrt(test.dist), - an, vd.no, vd.fno, *vd.mask); + an, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2389,7 +2391,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrt(test.dist), - an, vd.no, vd.fno, *vd.mask); + an, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2491,7 +2493,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, ss->cache->radius * test.dist, - an, vd.no, vd.fno, *vd.mask); + an, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2555,7 +2557,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrt(test.dist), - an, vd.no, vd.fno, *vd.mask); + an, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2619,7 +2621,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrt(test.dist), - an, vd.no, vd.fno, *vd.mask); + an, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -3062,7 +3064,11 @@ static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss) } } -void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_pmap) +/** + * \param need_mask So the DerivedMesh thats returned has mask data + */ +void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, + int need_pmap, int need_mask) { DerivedMesh *dm; SculptSession *ss = ob->sculpt; @@ -3071,6 +3077,27 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_ ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob); + if (need_mask) { + if (mmd == NULL) { + if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) { + ED_sculpt_mask_layers_ensure(ob, NULL); + } + } + else { + if (!CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) { +#if 1 + ED_sculpt_mask_layers_ensure(ob, mmd); +#else /* if we wanted to support adding mask data while multi-res painting, we would need to do this */ + if ((ED_sculpt_mask_layers_ensure(ob, mmd) & ED_SCULPT_MASK_LAYER_CALC_LOOP)) { + /* remake the derived mesh */ + ob->recalc |= OB_RECALC_DATA; + BKE_object_handle_update(scene, ob); + } +#endif + } + } + } + /* BMESH ONLY --- at some point we should move sculpt code to use polygons only - but for now it needs tessfaces */ BKE_mesh_tessface_ensure(me); @@ -3676,7 +3703,7 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob) Brush *brush = paint_brush(&sd->paint); sculpt_update_mesh_elements(CTX_data_scene(C), sd, ob, - sculpt_any_smooth_mode(brush, ss->cache, 0)); + sculpt_any_smooth_mode(brush, ss->cache, 0), FALSE); } } @@ -3782,12 +3809,17 @@ static int sculpt_brush_stroke_init(bContext *C, wmOperator *op) Brush *brush = paint_brush(&sd->paint); int mode = RNA_enum_get(op->ptr, "mode"); int is_smooth = 0; + int need_mask = FALSE; + + if (brush->sculpt_tool == SCULPT_TOOL_MASK) { + need_mask = TRUE; + } view3d_operator_needs_opengl(C); sculpt_brush_init_tex(scene, sd, ss); is_smooth = sculpt_any_smooth_mode(brush, NULL, mode); - sculpt_update_mesh_elements(scene, sd, ob, is_smooth); + sculpt_update_mesh_elements(scene, sd, ob, is_smooth, need_mask); return 1; } @@ -4103,13 +4135,14 @@ static void sculpt_init_session(Scene *scene, Object *ob) { ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); - sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, 0); + sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, 0, FALSE); } -void ED_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) +int ED_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) { float *paint_mask; Mesh *me = ob->data; + int ret = 0; paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); @@ -4162,13 +4195,18 @@ void ED_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) } } } + + ret |= ED_SCULPT_MASK_LAYER_CALC_LOOP; } /* create vertex paint mask layer if there isn't one already */ if (!paint_mask) { CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_CALLOC, NULL, me->totvert); + ret |= ED_SCULPT_MASK_LAYER_CALC_VERT; } + + return ret; } static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) @@ -4218,7 +4256,11 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) sculpt_init_session(scene, ob); /* Mask layer is required */ - ED_sculpt_mask_layers_ensure(ob, mmd); + if (mmd) { + /* XXX, we could attempt to support adding mask data mid-sculpt mode (with multi-res) + * but this ends up being quite tricky (and slow) */ + ED_sculpt_mask_layers_ensure(ob, mmd); + } BKE_paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 5e79616b0b0..0852378974e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -58,7 +58,8 @@ void sculpt(struct Sculpt *sd); int sculpt_mode_poll(struct bContext *C); int sculpt_mode_poll_view3d(struct bContext *C); int sculpt_poll(struct bContext *C); -void sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, int need_pmap); +void sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, + int need_pmap, int need_mask); /* Deformed mesh sculpt */ void free_sculptsession_deformMats(struct SculptSession *ss); diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 25555f2526f..b204fc75255 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -113,7 +113,7 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo if (kb) { ob->shapenr = BLI_findindex(&key->block, kb) + 1; - sculpt_update_mesh_elements(scene, sd, ob, 0); + sculpt_update_mesh_elements(scene, sd, ob, 0, FALSE); WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob); } else { @@ -271,8 +271,21 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) SculptUndoNode *unode; MultiresModifierData *mmd; int update = FALSE, rebuild = FALSE; + int need_mask = FALSE; + + for (unode = lb->first; unode; unode = unode->next) { + if (strcmp(unode->idname, ob->id.name) == 0) { + if (unode->type == SCULPT_UNDO_MASK) { + /* is possible that we can't do the mask undo (below) + * because of the vertex count */ + need_mask = TRUE; + break; + } + } + } + + sculpt_update_mesh_elements(scene, sd, ob, 0, need_mask); - sculpt_update_mesh_elements(scene, sd, ob, 0); /* call _after_ sculpt_update_mesh_elements() which may update 'ob->derivedFinal' */ dm = mesh_get_derived_final(scene, ob, 0); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index c44a181841e..2aa7bb9cc6b 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -1404,8 +1404,10 @@ void GPU_update_mesh_buffers(GPU_Buffers *buffers, MVert *mvert, copy_v3_v3(out->co, v->co); memcpy(out->no, v->no, sizeof(short) * 3); - gpu_color_from_mask_copy(vmask[vert_indices[i]], - out->color); + if (vmask) { + gpu_color_from_mask_copy(vmask[vert_indices[i]], + out->color); + } } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); @@ -1507,6 +1509,7 @@ void GPU_update_grid_buffers(GPU_Buffers *buffers, CCGElem **grids, if (buffers->vert_buf) { int totvert = key->grid_area * totgrid; int smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; + const int has_mask = key->has_mask; glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); glBufferDataARB(GL_ARRAY_BUFFER_ARB, @@ -1527,8 +1530,10 @@ void GPU_update_grid_buffers(GPU_Buffers *buffers, CCGElem **grids, normal_float_to_short_v3(vd->no, CCG_elem_no(key, elem)); - gpu_color_from_mask_copy(*CCG_elem_mask(key, elem), - vd->color); + if (has_mask) { + gpu_color_from_mask_copy(*CCG_elem_mask(key, elem), + vd->color); + } } vd++; } @@ -1556,12 +1561,15 @@ void GPU_update_grid_buffers(GPU_Buffers *buffers, CCGElem **grids, vd = vert_data + (j + 1) * key->grid_size + (k + 1); normal_float_to_short_v3(vd->no, fno); - gpu_color_from_mask_quad_copy(key, - elems[0], - elems[1], - elems[2], - elems[3], - vd->color); + + if (has_mask) { + gpu_color_from_mask_quad_copy(key, + elems[0], + elems[1], + elems[2], + elems[3], + vd->color); + } } } } @@ -1769,8 +1777,11 @@ static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth) { const MVert *mvert = buffers->mvert; int i, j; + const int has_mask = (buffers->vmask != NULL); - gpu_colors_enable(VBO_DISABLED); + if (has_mask) { + gpu_colors_enable(VBO_DISABLED); + } for (i = 0; i < buffers->totface; ++i) { MFace *f = buffers->mface + buffers->face_indices[i]; @@ -1784,13 +1795,15 @@ static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth) if (smooth) { for (j = 0; j < S; j++) { - gpu_color_from_mask_set(buffers->vmask[fv[j]]); + if (has_mask) { + gpu_color_from_mask_set(buffers->vmask[fv[j]]); + } glNormal3sv(mvert[fv[j]].no); glVertex3fv(mvert[fv[j]].co); } } else { - float fmask, fno[3]; + float fno[3]; /* calculate face normal */ if (f->v4) { @@ -1801,15 +1814,19 @@ static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth) normal_tri_v3(fno, mvert[fv[0]].co, mvert[fv[1]].co, mvert[fv[2]].co); glNormal3fv(fno); - /* calculate face mask color */ - fmask = (buffers->vmask[fv[0]] + - buffers->vmask[fv[1]] + - buffers->vmask[fv[2]]); - if (f->v4) - fmask = (fmask + buffers->vmask[fv[3]]) * 0.25; - else - fmask /= 3.0f; - gpu_color_from_mask_set(fmask); + if (has_mask) { + float fmask; + + /* calculate face mask color */ + fmask = (buffers->vmask[fv[0]] + + buffers->vmask[fv[1]] + + buffers->vmask[fv[2]]); + if (f->v4) + fmask = (fmask + buffers->vmask[fv[3]]) * 0.25; + else + fmask /= 3.0f; + gpu_color_from_mask_set(fmask); + } for (j = 0; j < S; j++) glVertex3fv(mvert[fv[j]].co); @@ -1818,15 +1835,20 @@ static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth) glEnd(); } - gpu_colors_disable(VBO_DISABLED); + if (has_mask) { + gpu_colors_disable(VBO_DISABLED); + } } static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) { const CCGKey *key = &buffers->gridkey; int i, j, x, y, gridsize = buffers->gridkey.grid_size; + const int has_mask = key->has_mask; - gpu_colors_enable(VBO_DISABLED); + if (has_mask) { + gpu_colors_enable(VBO_DISABLED); + } for (i = 0; i < buffers->totgrid; ++i) { int g = buffers->grid_indices[i]; @@ -1853,7 +1875,9 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) if (smooth) { for (j = 0; j < 4; j++) { - gpu_color_from_mask_set(*CCG_elem_mask(key, e[j])); + if (has_mask) { + gpu_color_from_mask_set(*CCG_elem_mask(key, e[j])); + } glNormal3fv(CCG_elem_no(key, e[j])); glVertex3fv(CCG_elem_co(key, e[j])); } @@ -1866,7 +1890,10 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) CCG_elem_co(key, e[2]), CCG_elem_co(key, e[3])); glNormal3fv(fno); - gpu_color_from_mask_quad_set(key, e[0], e[1], e[2], e[3]); + + if (has_mask) { + gpu_color_from_mask_quad_set(key, e[0], e[1], e[2], e[3]); + } for (j = 0; j < 4; j++) glVertex3fv(CCG_elem_co(key, e[j])); @@ -1883,10 +1910,14 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) CCGElem *a = CCG_grid_elem(key, grid, x, y); CCGElem *b = CCG_grid_elem(key, grid, x, y + 1); - gpu_color_from_mask_set(*CCG_elem_mask(key, a)); + if (has_mask) { + gpu_color_from_mask_set(*CCG_elem_mask(key, a)); + } glNormal3fv(CCG_elem_no(key, a)); glVertex3fv(CCG_elem_co(key, a)); - gpu_color_from_mask_set(*CCG_elem_mask(key, b)); + if (has_mask) { + gpu_color_from_mask_set(*CCG_elem_mask(key, b)); + } glNormal3fv(CCG_elem_no(key, b)); glVertex3fv(CCG_elem_co(key, b)); } @@ -1912,7 +1943,9 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) CCG_elem_co(key, c)); glNormal3fv(fno); - gpu_color_from_mask_quad_set(key, a, b, c, d); + if (has_mask) { + gpu_color_from_mask_quad_set(key, a, b, c, d); + } } glVertex3fv(CCG_elem_co(key, a)); @@ -1923,11 +1956,14 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) } } - gpu_colors_disable(VBO_DISABLED); + if (has_mask) { + gpu_colors_disable(VBO_DISABLED); + } } void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) { + const int has_mask = (buffers->vmask || buffers->gridkey.has_mask); int smooth = 0; if (buffers->totface) { @@ -1950,7 +1986,13 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) if (buffers->vert_buf && buffers->index_buf) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - gpu_colors_enable(VBO_ENABLED); + if (buffers->vmask || buffers->gridkey.has_mask) { + gpu_colors_enable(VBO_ENABLED); + } + else { + gpu_colors_enable(VBO_DISABLED); + glColor4ub(0xff, 0xff, 0xff, 0xff); + } glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); @@ -1963,8 +2005,10 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) offset + offsetof(VertexBufferFormat, co)); glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), offset + offsetof(VertexBufferFormat, no)); - glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, color)); + if (has_mask) { + glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), + offset + offsetof(VertexBufferFormat, color)); + } glDrawElements(GL_QUADS, buffers->tot_quad * 4, buffers->index_type, 0); @@ -1976,8 +2020,10 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) (void *)offsetof(VertexBufferFormat, co)); glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void *)offsetof(VertexBufferFormat, no)); - glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), - (void *)offsetof(VertexBufferFormat, color)); + if (has_mask) { + glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), + (void *)offsetof(VertexBufferFormat, color)); + } glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0); } @@ -1987,7 +2033,9 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); - gpu_colors_disable(VBO_ENABLED); + if (has_mask) { + gpu_colors_disable(VBO_ENABLED); + } } /* fallbacks if we are out of memory or VBO is disabled */ else if (buffers->totface) { diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index afc85a8144e..4292246d8cc 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -80,6 +80,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, Mesh *me = (Mesh *)ob->data; const int useRenderParams = flag & MOD_APPLY_RENDER; MultiresFlags flags = 0; + int has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); if (mmd->totlvl) { if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) { @@ -88,7 +89,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, } } - flags = MULTIRES_ALLOC_PAINT_MASK; + if (has_mask) + flags |= MULTIRES_ALLOC_PAINT_MASK; + if (useRenderParams) flags |= MULTIRES_USE_RENDER_PARAMS; From ae32c946e167bed6e427dd00b4da53e2b60be782 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 06:18:45 +0000 Subject: [PATCH 011/143] style cleanup: define float sizes for interpolation functions, add retirn's on newlines (to better add breakpoints). --- source/blender/imbuf/IMB_imbuf.h | 8 ++--- source/blender/imbuf/intern/imageprocess.c | 38 ++++++++++++++-------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 1503b9f6f67..28dbe110528 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -410,10 +410,10 @@ void bicubic_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float v void neareast_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout); void bilinear_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout); -void bicubic_interpolation_color(struct ImBuf *in, unsigned char *col, float *col_float, float u, float v); -void neareast_interpolation_color(struct ImBuf *in, unsigned char *col, float *col_float, float u, float v); -void bilinear_interpolation_color(struct ImBuf *in, unsigned char *col, float *col_float, float u, float v); -void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char *col, float *col_float, float u, float v); +void bicubic_interpolation_color(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v); +void neareast_interpolation_color(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v); +void bilinear_interpolation_color(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v); +void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v); /** * diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c index 3fd06a7c34d..863b8424cc2 100644 --- a/source/blender/imbuf/intern/imageprocess.c +++ b/source/blender/imbuf/intern/imageprocess.c @@ -125,15 +125,16 @@ static float P(float k) } #endif -void bicubic_interpolation_color(struct ImBuf *in, unsigned char *outI, float *outF, float u, float v) +void bicubic_interpolation_color(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v) { int i, j, n, m, x1, y1; unsigned char *dataI; float a, b, w, wx, wy[4], outR, outG, outB, outA, *dataF; /* sample area entirely outside image? */ - if (ceil(u) < 0 || floor(u) > in->x - 1 || ceil(v) < 0 || floor(v) > in->y - 1) + if (ceil(u) < 0 || floor(u) > in->x - 1 || ceil(v) < 0 || floor(v) > in->y - 1) { return; + } /* ImBuf in must have a valid rect or rect_float, assume this is already checked */ @@ -226,11 +227,12 @@ void bicubic_interpolation_color(struct ImBuf *in, unsigned char *outI, float *o void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout) { - unsigned char *outI = NULL; float *outF = NULL; - if (in == NULL || (in->rect == NULL && in->rect_float == NULL)) return; + if (in == NULL || (in->rect == NULL && in->rect_float == NULL)) { + return; + } pixel_from_buffer(out, &outI, &outF, xout, yout); /* gcc warns these could be uninitialized, but its ok */ @@ -239,7 +241,7 @@ void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in /* function assumes out to be zero'ed, only does RGBA */ /* BILINEAR INTERPOLATION */ -void bilinear_interpolation_color(struct ImBuf *in, unsigned char *outI, float *outF, float u, float v) +void bilinear_interpolation_color(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v) { float *row1, *row2, *row3, *row4, a, b; unsigned char *row1I, *row2I, *row3I, *row4I; @@ -257,7 +259,9 @@ void bilinear_interpolation_color(struct ImBuf *in, unsigned char *outI, float * y2 = (int)ceil(v); /* sample area entirely outside image? */ - if (x2 < 0 || x1 > in->x - 1 || y2 < 0 || y1 > in->y - 1) return; + if (x2 < 0 || x1 > in->x - 1 || y2 < 0 || y1 > in->y - 1) { + return; + } if (outF) { /* sample including outside of edges of image */ @@ -315,7 +319,7 @@ void bilinear_interpolation_color(struct ImBuf *in, unsigned char *outI, float * /* Note about wrapping, the u/v still needs to be within the image bounds, * just the interpolation is wrapped. * This the same as bilinear_interpolation_color except it wraps rather than using empty and emptyI */ -void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char *outI, float *outF, float u, float v) +void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v) { float *row1, *row2, *row3, *row4, a, b; unsigned char *row1I, *row2I, *row3I, *row4I; @@ -331,7 +335,9 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char *outI, fl y2 = (int)ceil(v); /* sample area entirely outside image? */ - if (x2 < 0 || x1 > in->x - 1 || y2 < 0 || y1 > in->y - 1) return; + if (x2 < 0 || x1 > in->x - 1 || y2 < 0 || y1 > in->y - 1) { + return; + } /* wrap interpolation pixels - main difference from bilinear_interpolation_color */ if (x1 < 0) x1 = in->x + x1; @@ -378,11 +384,12 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char *outI, fl void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout) { - unsigned char *outI = NULL; float *outF = NULL; - if (in == NULL || (in->rect == NULL && in->rect_float == NULL)) return; + if (in == NULL || (in->rect == NULL && in->rect_float == NULL)) { + return; + } pixel_from_buffer(out, &outI, &outF, xout, yout); /* gcc warns these could be uninitialized, but its ok */ @@ -391,7 +398,7 @@ void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, i /* function assumes out to be zero'ed, only does RGBA */ /* NEAREST INTERPOLATION */ -void neareast_interpolation_color(struct ImBuf *in, unsigned char *outI, float *outF, float u, float v) +void neareast_interpolation_color(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v) { float *dataF; unsigned char *dataI; @@ -403,7 +410,9 @@ void neareast_interpolation_color(struct ImBuf *in, unsigned char *outI, float * y1 = (int)(v); /* sample area entirely outside image? */ - if (x1 < 0 || x1 > in->x - 1 || y1 < 0 || y1 > in->y - 1) return; + if (x1 < 0 || x1 > in->x - 1 || y1 < 0 || y1 > in->y - 1) { + return; + } /* sample including outside of edges of image */ if (x1 < 0 || y1 < 0) { @@ -440,11 +449,12 @@ void neareast_interpolation_color(struct ImBuf *in, unsigned char *outI, float * void neareast_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, int yout) { - unsigned char *outI = NULL; float *outF = NULL; - if (in == NULL || (in->rect == NULL && in->rect_float == NULL)) return; + if (in == NULL || (in->rect == NULL && in->rect_float == NULL)) { + return; + } pixel_from_buffer(out, &outI, &outF, xout, yout); /* gcc warns these could be uninitialized, but its ok */ From 4b0e41b0a724a98bb69aec413e1aa18a6461b42a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 06:34:02 +0000 Subject: [PATCH 012/143] fix [#32709] Color mix node produces artifacts from other frames --- .../compositor/operations/COM_MixColorOperation.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/blender/compositor/operations/COM_MixColorOperation.cpp b/source/blender/compositor/operations/COM_MixColorOperation.cpp index f8aca92abc7..56aca27eaef 100644 --- a/source/blender/compositor/operations/COM_MixColorOperation.cpp +++ b/source/blender/compositor/operations/COM_MixColorOperation.cpp @@ -53,9 +53,12 @@ void MixColorOperation::executePixel(float output[4], float x, float y, PixelSam float tmpr, tmpg, tmpb; rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb); - output[0] = valuem * (inputColor1[0]) + value * tmpr; - output[1] = valuem * (inputColor1[1]) + value * tmpg; - output[2] = valuem * (inputColor1[2]) + value * tmpb; + output[0] = (valuem * inputColor1[0]) + (value * tmpr); + output[1] = (valuem * inputColor1[1]) + (value * tmpg); + output[2] = (valuem * inputColor1[2]) + (value * tmpb); + } + else { + copy_v3_v3(output, inputColor1); } output[3] = inputColor1[3]; From 323ad98496cc4b5b95be69d1a81c2bb07ff5bf56 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Mon, 1 Oct 2012 07:53:54 +0000 Subject: [PATCH 013/143] Fix: gpu_colors_enable could cause 3d display corruption because it always enables glColorMaterial. Make sure to call gpu_colors_disable even if we don't have a mask layer, to match gpu_colors_enable above --- source/blender/gpu/intern/gpu_buffers.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 2aa7bb9cc6b..3e5a14774c2 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -1986,7 +1986,7 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) if (buffers->vert_buf && buffers->index_buf) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - if (buffers->vmask || buffers->gridkey.has_mask) { + if (has_mask) { gpu_colors_enable(VBO_ENABLED); } else { @@ -2036,6 +2036,9 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) if (has_mask) { gpu_colors_disable(VBO_ENABLED); } + else { + gpu_colors_disable(VBO_DISABLED); + } } /* fallbacks if we are out of memory or VBO is disabled */ else if (buffers->totface) { From 1a19cbb166ce66b427a2dd0d0f9e65b1863e35b0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 07:54:37 +0000 Subject: [PATCH 014/143] fix for some errors when unlinking. - movieclip unlink didn't clear node ID pointers from the scene (leaving dangling pointers). - mask datablock unlink was clearning references from scene nodes twice. --- source/blender/blenkernel/BKE_node.h | 2 ++ source/blender/blenkernel/intern/mask.c | 25 +------------------- source/blender/blenkernel/intern/movieclip.c | 7 ++++++ source/blender/nodes/intern/node_common.c | 12 ++++++++++ 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 6ad2ad924e2..acd6f120f93 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -475,6 +475,8 @@ struct bNodeSocket *node_group_add_extern_socket(struct bNodeTree *ntree, ListBa void register_node_type_frame(struct bNodeTreeType *ttype); void register_node_type_reroute(struct bNodeTreeType *ttype); +void BKE_node_tree_unlink_id_cb(void *calldata, struct ID *owner_id, struct bNodeTree *ntree); + /* ************** SHADER NODES *************** */ struct ShadeInput; diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 3564071334c..cacbf988ba9 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -916,19 +916,6 @@ void BKE_mask_free_nolib(Mask *mask) BKE_mask_layer_free_list(&mask->masklayers); } - -static void ntree_unlink_mask_cb(void *calldata, struct ID *UNUSED(owner_id), struct bNodeTree *ntree) -{ - ID *id = (ID *)calldata; - bNode *node; - - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id == id) { - node->id = NULL; - } - } -} - void BKE_mask_free(Main *bmain, Mask *mask) { bScreen *scr; @@ -975,21 +962,11 @@ void BKE_mask_free(Main *bmain, Mask *mask) } SEQ_END } - - - if (scene->nodetree) { - bNode *node; - for (node = scene->nodetree->nodes.first; node; node = node->next) { - if (node->id == &mask->id) { - node->id = NULL; - } - } - } } { bNodeTreeType *treetype = ntreeGetType(NTREE_COMPOSIT); - treetype->foreach_nodetree(bmain, (void *)mask, &ntree_unlink_mask_cb); + treetype->foreach_nodetree(bmain, (void *)mask, &BKE_node_tree_unlink_id_cb); } /* free mask data */ diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 386e4163fd2..8a2bdd81da2 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -52,6 +52,7 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_movieclip_types.h" +#include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_view3d_types.h" @@ -71,6 +72,7 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_movieclip.h" +#include "BKE_node.h" #include "BKE_image.h" /* openanim */ #include "BKE_tracking.h" @@ -1326,6 +1328,11 @@ void BKE_movieclip_unlink(Main *bmain, MovieClip *clip) } } + { + bNodeTreeType *treetype = ntreeGetType(NTREE_COMPOSIT); + treetype->foreach_nodetree(bmain, (void *)clip, &BKE_node_tree_unlink_id_cb); + } + clip->id.us = 0; } diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index a61cf00d81c..301dea22c17 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -650,3 +650,15 @@ void ntree_update_reroute_nodes(bNodeTree *ntree) if (node->type == NODE_REROUTE && !node->done) node_reroute_inherit_type_recursive(ntree, node); } + +void BKE_node_tree_unlink_id_cb(void *calldata, struct ID *UNUSED(owner_id), struct bNodeTree *ntree) +{ + ID *id = (ID *)calldata; + bNode *node; + + for (node = ntree->nodes.first; node; node = node->next) { + if (node->id == id) { + node->id = NULL; + } + } +} From da656957c366c32fca1a8782aa6c05111a802515 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 10:43:52 +0000 Subject: [PATCH 015/143] fix [#31654] Non-proportional edge slide behaving incorrectly. --- source/blender/editors/transform/transform.c | 58 ++++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 777f239d55c..343fa6681f3 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -5529,42 +5529,42 @@ static int doEdgeSlide(TransInfo *t, float perc) int i; sld->perc = perc; - sv = svlist; - for (i = 0; i < sld->totsv; i++, sv++) { - if (sld->is_proportional == FALSE) { - TransDataSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; - float cur_sel = curr_sv->edge_len; - float cur_sv = sv->edge_len; - float extd = 0.0f; - float recip_cur_sv = 0.0f; - if (cur_sel == 0.0f) cur_sel = 1.0f; - if (cur_sv == 0.0f) cur_sv = 1.0f; - - recip_cur_sv = 1.0f / cur_sv; - - if (!sld->flipped_vtx) { - extd = (cur_sv - cur_sel) * recip_cur_sv; + if (sld->is_proportional == TRUE) { + for (i = 0; i < sld->totsv; i++, sv++) { + if (perc > 0.0f) { + copy_v3_v3(vec, sv->upvec); + mul_v3_fl(vec, perc); + add_v3_v3v3(sv->v->co, sv->origvert.co, vec); } else { - extd = (cur_sel - cur_sv) * recip_cur_sv; + copy_v3_v3(vec, sv->downvec); + mul_v3_fl(vec, -perc); + add_v3_v3v3(sv->v->co, sv->origvert.co, vec); } - - extd += (sld->perc * cur_sel) * recip_cur_sv; - CLAMP(extd, -1.0f, 1.0f); - perc = extd; } + } + else { + /** + * Implementation note, non proportional mode ignores the starting positions and uses only the + * up/down verts, this could be changed/improved so the distance is still met but the verts are moved along + * their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell + */ + TransDataSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; + const float curr_length_perc = len_v3v3(curr_sv->up->co, curr_sv->down->co) * + (((sld->flipped_vtx ? perc : -perc) + 1.0f) / 2.0f); - if (perc > 0.0f) { - copy_v3_v3(vec, sv->upvec); - mul_v3_fl(vec, perc); - add_v3_v3v3(sv->v->co, sv->origvert.co, vec); - } - else { - copy_v3_v3(vec, sv->downvec); - mul_v3_fl(vec, -perc); - add_v3_v3v3(sv->v->co, sv->origvert.co, vec); + for (i = 0; i < sld->totsv; i++, sv++) { + const float sv_length = len_v3v3(sv->up->co, sv->down->co); + const float fac = minf(sv_length, curr_length_perc) / sv_length; + + if (sld->flipped_vtx) { + interp_v3_v3v3(sv->v->co, sv->down->co, sv->up->co, fac); + } + else { + interp_v3_v3v3(sv->v->co, sv->up->co, sv->down->co, fac); + } } } From b6bf0e49527d174c51e8644f05569c6618d32604 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 11:05:09 +0000 Subject: [PATCH 016/143] fix [#32713] Crash with modifiers + GLSL mode crash caused by own commit r50969, the fix exposed a crash in an area of code that must have never been used before. --- source/blender/blenkernel/intern/mask.c | 2 +- .../blenkernel/intern/modifiers_bmesh.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index cacbf988ba9..aa19350c456 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -1525,7 +1525,7 @@ void BKE_mask_parent_init(MaskParent *parent) } -/* *** own animation/shapekey implimentation *** +/* *** own animation/shapekey implementation *** * BKE_mask_layer_shape_XXX */ int BKE_mask_layer_shape_totvert(MaskLayer *masklay) diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c index 72c3cda9272..4129f4231f1 100644 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -49,7 +49,7 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm) MLoop *mloop, *ml; BMVert *v, **vtable, **verts = NULL; BMEdge *e, **etable, **edges = NULL; - float has_face_normals; + float (*face_normals)[3]; BMFace *f; BMIter liter; BLI_array_declare(verts); @@ -72,8 +72,8 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm) BM_data_layer_add(bm, &bm->edata, CD_BWEIGHT); BM_data_layer_add(bm, &bm->vdata, CD_BWEIGHT); - vtable = MEM_callocN(sizeof(void **) * totvert, "vert table in BMDM_Copy"); - etable = MEM_callocN(sizeof(void **) * totedge, "edge table in BMDM_Copy"); + vtable = MEM_callocN(sizeof(void **) * totvert, __func__); + etable = MEM_callocN(sizeof(void **) * totedge, __func__); /*do verts*/ mv = mvert = dm->dupVertArray(dm); @@ -110,7 +110,7 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm) /*do faces*/ mp = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); - has_face_normals = CustomData_has_layer(&dm->polyData, CD_NORMAL); + face_normals = CustomData_get_layer(&dm->polyData, CD_NORMAL); /* can be NULL */ for (i = 0; i < dm->numPolyData; i++, mp++) { BMLoop *l; @@ -143,11 +143,11 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm) CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, i, &f->head.data); - if (has_face_normals) { - float *fno; - - fno = CustomData_bmesh_get(&bm->pdata, &f->head.data, CD_NORMAL); - copy_v3_v3(f->no, fno); + if (face_normals) { + copy_v3_v3(f->no, face_normals[i]); + } + else { + BM_face_normal_update(f); } } From c9c76a9a68ff9f0c32c6a1f77d386349ca5abaca Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 11:12:49 +0000 Subject: [PATCH 017/143] add compiler hints that failing to create a bmesh face is unlikely. --- source/blender/blenkernel/intern/modifiers_bmesh.c | 3 ++- source/blender/bmesh/intern/bmesh_construct.c | 3 ++- source/blender/bmesh/intern/bmesh_core.c | 2 +- source/blender/bmesh/intern/bmesh_mesh_conv.c | 2 +- source/blender/bmesh/operators/bmo_bevel.c | 6 +++--- source/blender/bmesh/operators/bmo_connect.c | 2 +- source/blender/bmesh/operators/bmo_create.c | 3 ++- source/blender/bmesh/operators/bmo_extrude.c | 3 ++- source/blender/python/bmesh/bmesh_py_types.c | 2 +- 9 files changed, 15 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c index 4129f4231f1..dc3d4a89e62 100644 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -129,8 +129,9 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm) f = BM_face_create_ngon(bm, verts[0], verts[1], edges, mp->totloop, FALSE); - if (!f) + if (UNLIKELY(f == NULL)) { continue; + } f->head.hflag = BM_face_flag_from_mflag(mp->flag); f->mat_nr = mp->mat_nr; diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 72d9c9ab342..bc121303046 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -902,8 +902,9 @@ BMesh *BM_mesh_copy(BMesh *bm_old) } f2 = BM_face_create_ngon(bm_new, v, v2, edges, f->len, FALSE); - if (!f2) + if (UNLIKELY(f2 == NULL)) { continue; + } /* use totface in case adding some faces fails */ BM_elem_index_set(f2, (bm_new->totface - 1)); /* set_inline */ diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index ccbbb6f170b..d50c94d5e6a 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -1021,7 +1021,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const short do_del /* create region face */ newf = BM_face_create_ngon(bm, v1, v2, edges, tote, FALSE); - if (!newf || BMO_error_occurred(bm)) { + if (UNLIKELY(!newf || BMO_error_occurred(bm))) { if (!BMO_error_occurred(bm)) err = "Invalid boundary region to join faces"; goto error; diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c index e6827b1f2cd..b0a9168ffda 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.c +++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c @@ -314,7 +314,7 @@ void BM_mesh_bm_from_me(BMesh *bm, Mesh *me, int set_key, int act_key_nr) f = BM_face_create(bm, verts, fedges, mpoly->totloop, FALSE); - if (!f) { + if (UNLIKELY(f == NULL)) { printf("%s: Warning! Bad face in mesh" " \"%s\" at index %d!, skipping\n", __func__, me->id.name + 2, i); diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 8210ea973e6..10a9d511c77 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -475,7 +475,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) BLI_array_append(edges, e); f = BM_face_create_ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), FALSE); - if (!f) { + if (UNLIKELY(f == NULL)) { printf("%s: could not make face!\n", __func__); continue; } @@ -592,7 +592,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) *d3 = (d1 + d2) * 0.5f; } - if (!f) { + if (UNLIKELY(f == NULL)) { fprintf(stderr, "%s: face index out of range! (bmesh internal error)\n", __func__); continue; } @@ -771,7 +771,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) continue; f = BM_face_create_ngon(bm, lastv, vstart, edges, BLI_array_count(edges), FALSE); - if (!f) { + if (UNLIKELY(f == NULL)) { fprintf(stderr, "%s: in bevel vert fill! (bmesh internal error)\n", __func__); } else { diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index bb2e49d043c..fde475c2d6a 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -506,7 +506,7 @@ void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op) vv2[i2next], vv1[i1next], f_example, TRUE); - if (!f || f->len != 4) { + if (UNLIKELY((f == NULL) || (f->len != 4))) { fprintf(stderr, "%s: in bridge! (bmesh internal error)\n", __func__); } else { diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c index 519778cb638..731170f963c 100644 --- a/source/blender/bmesh/operators/bmo_create.c +++ b/source/blender/bmesh/operators/bmo_create.c @@ -275,8 +275,9 @@ static int UNUSED_FUNCTION(rotsys_fill_faces)(BMesh *bm, EdgeData *edata, VertDa continue; f = BM_face_create_ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), TRUE); - if (!f) + if (UNLIKELY(f == NULL)) { continue; + } } } diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index c8be7c9ce34..81cad277bee 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -87,7 +87,7 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) BMO_elem_flag_enable(bm, f, EXT_DEL); f2 = BM_face_create_ngon(bm, firstv, BM_edge_other_vert(edges[0], firstv), edges, f->len, FALSE); - if (!f2) { + if (UNLIKELY(f2 == NULL)) { BMO_error_raise(bm, op, BMERR_MESH_ERROR, "Extrude failed; could not create face"); BLI_array_free(edges); return; @@ -104,6 +104,7 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) l4 = l2->next; f3 = BM_face_create_quad_tri(bm, l3->v, l4->v, l2->v, l->v, f, FALSE); + /* XXX, no error check here, why? - Campbell */ l_tmp = BM_FACE_FIRST_LOOP(f3); diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index fefccceeb6e..fd5fa63647b 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -1808,7 +1808,7 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args) f_new = BM_face_create(bm, vert_array, edge_array, vert_seq_len, FALSE); - if (f_new == NULL) { + if (UNLIKELY(f_new == NULL)) { PyErr_SetString(PyExc_ValueError, "faces.new(verts): couldn't create the new face, internal error"); goto cleanup; From 1d7bf727ff50a9dc21de3c002311eb670fc680b4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 1 Oct 2012 11:14:02 +0000 Subject: [PATCH 018/143] Fix #32695: Can't disable color management for 3D view Made it so viewport will disable color management if display device set to None. This solves couple of regressions, mainly related on old BGE files and made None display behave exactly as old color management disabled. --- source/blender/blenkernel/BKE_scene.h | 1 + source/blender/blenkernel/intern/scene.c | 5 +++++ source/blender/editors/space_view3d/drawmesh.c | 8 +------- source/blender/gpu/intern/gpu_draw.c | 5 +---- source/blender/gpu/intern/gpu_material.c | 6 ++---- source/blender/render/intern/source/shadeinput.c | 8 ++------ 6 files changed, 12 insertions(+), 21 deletions(-) diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 023b7e85c40..c12e913be45 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -109,6 +109,7 @@ float get_render_aosss_error(struct RenderData *r, float error); int BKE_scene_use_new_shading_nodes(struct Scene *scene); void BKE_scene_disable_color_management(struct Scene *scene); +int BKE_scene_check_color_management_enabled(const struct Scene *scene); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 4a172ab4476..41d300a95de 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1278,3 +1278,8 @@ void BKE_scene_disable_color_management(Scene *scene) BLI_strncpy(view_settings->view_transform, view, sizeof(view_settings->view_transform)); } } + +int BKE_scene_check_color_management_enabled(const Scene *scene) +{ + return strcmp(scene->display_settings.display_device, "None") != 0; +} diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index f05c78e8512..e4c21a9c2c8 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -373,13 +373,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O Gtexdraw.ob = ob; Gtexdraw.is_tex = is_tex; - /* OCIO_TODO: for now assume OpenGL is always doing color management and working in sRGB space - * supporting for real display conversion could be nice here, but it's a bit challenging - * since all the shaders should be aware of such a transform - * perhaps this flag could be completely removed before release in separated commit and - * be re-implemented if real display transform would be needed - */ - Gtexdraw.color_profile = TRUE; + Gtexdraw.color_profile = BKE_scene_check_color_management_enabled(scene); memcpy(Gtexdraw.obcol, obcol, sizeof(obcol)); set_draw_settings_cached(1, NULL, NULL, Gtexdraw); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 962bb0aed22..956c76aec20 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -1209,10 +1209,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O GPUBlendMode alphablend; int a; - /* OCIO_TODO: assume color management is always enabled. could be nice to support real display transform here, - * but that's not so important and could be done later - */ - int gamma = TRUE; + int gamma = BKE_scene_check_color_management_enabled(scene); int new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index dd92b561235..4732586b912 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -389,10 +389,8 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node) int GPU_material_do_color_management(GPUMaterial *mat) { - /* OCIO_TODO: for now assume scene always does color management. probably could be - * improved in the future to support real display transform - * also probably we'll need to get rid ofgame engine's color management flag - */ + if (!BKE_scene_check_color_management_enabled(mat->scene)) + return FALSE; return !((mat->scene->gm.flag & GAME_GLSL_NO_COLOR_MANAGEMENT)); } diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 35ab06cc564..ff543b8ce06 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -44,6 +44,7 @@ #include "DNA_material_types.h" #include "BKE_colortools.h" +#include "BKE_scene.h" #include "BKE_node.h" @@ -1321,12 +1322,7 @@ void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, in shi->thread = pa->thread; shi->do_preview = (R.r.scemode & R_MATNODE_PREVIEW) != 0; - /* OCIO_TODO: for now assume color management is always enabled and vertes colors are in sRGB space - * probably would be nice to have this things configurable, but for now it should work - * also probably this flag could be removed (in separated commit) before the release - * since it's not actually meaningful anymore - */ - shi->do_manage = TRUE; + shi->do_manage = BKE_scene_check_color_management_enabled(R.scene); shi->lay = rl->lay; shi->layflag = rl->layflag; From 3e24c2546463a774ee10c915e3c8f8457f36290c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 1 Oct 2012 11:26:52 +0000 Subject: [PATCH 019/143] Fix #32686: MovieClip background initialisaton error Undistorted rendering with original footage settings does not require proxies to be enabled. --- release/scripts/startup/bl_ui/space_clip.py | 31 +++++++++++--------- source/blender/blenkernel/intern/movieclip.c | 18 +++++------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index efac7a66086..b0e8a847084 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -790,42 +790,45 @@ class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel): sc = context.space_data clip = sc.clip - layout.active = clip.use_proxy + col = layout.column() + col.active = clip.use_proxy - layout.label(text="Build Original:") + col.label(text="Build Original:") - row = layout.row(align=True) + row = col.row(align=True) row.prop(clip.proxy, "build_25", toggle=True) row.prop(clip.proxy, "build_50", toggle=True) row.prop(clip.proxy, "build_75", toggle=True) row.prop(clip.proxy, "build_100", toggle=True) - layout.label(text="Build Undistorted:") + col.label(text="Build Undistorted:") - row = layout.row(align=True) + row = col.row(align=True) row.prop(clip.proxy, "build_undistorted_25", toggle=True) row.prop(clip.proxy, "build_undistorted_50", toggle=True) row.prop(clip.proxy, "build_undistorted_75", toggle=True) row.prop(clip.proxy, "build_undistorted_100", toggle=True) - layout.prop(clip.proxy, "quality") + col.prop(clip.proxy, "quality") - layout.prop(clip, "use_proxy_custom_directory") + col.prop(clip, "use_proxy_custom_directory") if clip.use_proxy_custom_directory: - layout.prop(clip.proxy, "directory") + col.prop(clip.proxy, "directory") - layout.operator("clip.rebuild_proxy", text="Build Proxy") + col.operator("clip.rebuild_proxy", text="Build Proxy") if clip.source == 'MOVIE': - col = layout.column() + col2 = col.column() - col.label(text="Use timecode index:") - col.prop(clip.proxy, "timecode", text="") + col2.label(text="Use timecode index:") + col2.prop(clip.proxy, "timecode", text="") - col = layout.column() - col.label(text="Proxy render size:") + col2 = col.column() + col2.label(text="Proxy render size:") col.prop(sc.clip_user, "proxy_render_size", text="") + + col = layout.column() col.prop(sc.clip_user, "use_render_undistorted") diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 8a2bdd81da2..0aa1f9e0822 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -626,24 +626,22 @@ static ImBuf *get_undistorted_ibuf(MovieClip *clip, struct MovieDistortion *dist return undistibuf; } -static int need_undistortion_postprocess(MovieClipUser *user, int flag) +static int need_undistortion_postprocess(MovieClipUser *user) { int result = 0; /* only full undistorted render can be used as on-fly undistorting image */ - if (flag & MCLIP_USE_PROXY) { - result |= (user->render_size == MCLIP_PROXY_RENDER_SIZE_FULL) && - (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0; - } + result |= (user->render_size == MCLIP_PROXY_RENDER_SIZE_FULL) && + (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0; return result; } -static int need_postprocessed_frame(MovieClipUser *user, int flag, int postprocess_flag) +static int need_postprocessed_frame(MovieClipUser *user, int postprocess_flag) { int result = postprocess_flag; - result |= need_undistortion_postprocess(user, flag); + result |= need_undistortion_postprocess(user); return result; } @@ -690,7 +688,7 @@ static ImBuf *get_postprocessed_cached_frame(MovieClip *clip, MovieClipUser *use if (cache->postprocessed.flag != postprocess_flag) return NULL; - if (need_undistortion_postprocess(user, flag)) { + if (need_undistortion_postprocess(user)) { if (!check_undistortion_cache_flags(clip)) return NULL; } @@ -721,7 +719,7 @@ static ImBuf *put_postprocessed_frame_to_cache(MovieClip *clip, MovieClipUser *u cache->postprocessed.render_flag = 0; } - if (need_undistortion_postprocess(user, flag)) { + if (need_undistortion_postprocess(user)) { copy_v2_v2(cache->postprocessed.principal, camera->principal); copy_v3_v3(&cache->postprocessed.k1, &camera->k1); cache->postprocessed.undistortion_used = TRUE; @@ -765,7 +763,7 @@ static ImBuf *movieclip_get_postprocessed_ibuf(MovieClip *clip, MovieClipUser *u BLI_lock_thread(LOCK_MOVIECLIP); /* try to obtain cached postprocessed frame first */ - if (need_postprocessed_frame(user, flag, postprocess_flag)) { + if (need_postprocessed_frame(user, postprocess_flag)) { ibuf = get_postprocessed_cached_frame(clip, user, flag, postprocess_flag); if (!ibuf) From e7089c06439014aeefd7e8e0efdb07b375eca9ad Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 1 Oct 2012 12:41:20 +0000 Subject: [PATCH 020/143] Disable render part of display transformation for icon/texture preview This change mainly caused by too dark icon generated for texture brushes, but also makes it a bit more straightforward from what's going on point of view. --- source/blender/editors/render/render_preview.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 6b6018e51d2..817067422af 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -271,9 +271,19 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre else sce->r.xparts = sce->r.yparts = 4; - /* exception: don't color manage texture previews or icons */ - if ((id && sp->pr_method == PR_ICON_RENDER) || id_type == ID_TE) - BKE_scene_disable_color_management(sce); + /* exception: don't apply render part of display transform for texture previews or icons */ + if ((id && sp->pr_method == PR_ICON_RENDER) || id_type == ID_TE) { + ColorManagedDisplaySettings *display_settings = &sce->display_settings; + ColorManagedViewSettings *view_settings = &sce->view_settings; + + const char *default_view_name = IMB_colormanagement_view_get_default_name(display_settings->display_device); + + view_settings->exposure = 0.0f; + view_settings->gamma = 1.0f; + view_settings->flag &= ~COLORMANAGE_VIEW_USE_CURVES; + + BLI_strncpy(view_settings->view_transform, default_view_name, sizeof(view_settings->view_transform)); + } if ((id && sp->pr_method == PR_ICON_RENDER) && id_type != ID_WO) sce->r.alphamode = R_ALPHAPREMUL; From fbc056c9f5569f50797459a0430ce68d1d1b7c2f Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Mon, 1 Oct 2012 14:02:47 +0000 Subject: [PATCH 021/143] File Output Node: * Small cosmetic change, move up/down buttons next to the list, instead of beneath. * Removed redundant "uiLayout" declarations. --- source/blender/editors/space_node/drawnode.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 8ad02ad7d8b..1d04855666e 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -2031,7 +2031,7 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C { PointerRNA imfptr = RNA_pointer_get(ptr, "format"); PointerRNA active_input_ptr, op_ptr; - uiLayout *row; + uiLayout *row, *col; int active_index; int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER); @@ -2042,32 +2042,34 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C uiItemO(layout, IFACE_("Add Input"), ICON_ZOOMIN, "NODE_OT_output_file_add_socket"); + row = uiLayoutRow(layout, FALSE); + col = uiLayoutColumn(row, TRUE); + active_index = RNA_int_get(ptr, "active_input_index"); /* using different collection properties if multilayer format is enabled */ if (multilayer) { - uiTemplateList(layout, C, ptr, "layer_slots", ptr, "active_input_index", NULL, 0, 0, 0); + uiTemplateList(col, C, ptr, "layer_slots", ptr, "active_input_index", NULL, 0, 0, 0); RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr); } else { - uiTemplateList(layout, C, ptr, "file_slots", ptr, "active_input_index", NULL, 0, 0, 0); + uiTemplateList(col, C, ptr, "file_slots", ptr, "active_input_index", NULL, 0, 0, 0); RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr); } /* XXX collection lookup does not return the ID part of the pointer, setting this manually here */ active_input_ptr.id.data = ptr->id.data; - row = uiLayoutRow(layout, TRUE); - op_ptr = uiItemFullO(row, "NODE_OT_output_file_move_active_socket", "", + col = uiLayoutColumn(row, TRUE); + op_ptr = uiItemFullO(col, "NODE_OT_output_file_move_active_socket", "", ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&op_ptr, "direction", 1); - op_ptr = uiItemFullO(row, "NODE_OT_output_file_move_active_socket", "", + op_ptr = uiItemFullO(col, "NODE_OT_output_file_move_active_socket", "", ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&op_ptr, "direction", 2); if (active_input_ptr.data) { if (multilayer) { - uiLayout *row, *col; col = uiLayoutColumn(layout, TRUE); uiItemL(col, IFACE_("Layer:"), ICON_NONE); @@ -2077,7 +2079,6 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C ICON_X, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_R_ICON_ONLY); } else { - uiLayout *row, *col; col = uiLayoutColumn(layout, TRUE); uiItemL(col, IFACE_("File Path:"), ICON_NONE); From 77b90a94c978bd58e1a236b75745152b7b03f682 Mon Sep 17 00:00:00 2001 From: Jens Verwiebe Date: Mon, 1 Oct 2012 14:03:02 +0000 Subject: [PATCH 022/143] OSX/cmake: simplificate compile conditions and silence lot of CLANG warnings --- CMakeLists.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 51d900ae35d..79070a77bb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1648,12 +1648,13 @@ elseif(APPLE) set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g") set(CMAKE_CXX_FLAGS_DEBUG "-fno-strict-aliasing -g") - if(CMAKE_OSX_ARCHITECTURES MATCHES "i386") - set(CMAKE_CXX_FLAGS_RELEASE "-O2 -mdynamic-no-pic -ftree-vectorize -msse -msse2 -fvariable-expansion-in-unroller") - set(CMAKE_C_FLAGS_RELEASE "-O2 -mdynamic-no-pic -ftree-vectorize -msse -msse2 -fvariable-expansion-in-unroller") - elseif(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64") - set(CMAKE_CXX_FLAGS_RELEASE "-O2 -mdynamic-no-pic -ftree-vectorize -msse -msse2 -msse3 -mssse3 -fvariable-expansion-in-unroller") - set(CMAKE_C_FLAGS_RELEASE "-O2 -mdynamic-no-pic -ftree-vectorize -msse -msse2 -msse3 -mssse3 -fvariable-expansion-in-unroller") + if(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" OR CMAKE_OSX_ARCHITECTURES MATCHES "i386") + set(CMAKE_CXX_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3") + set(CMAKE_C_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3") + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ftree-vectorize -fvariable-expansion-in-unroller") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ftree-vectorize -fvariable-expansion-in-unroller") + endif() else() set(CMAKE_C_FLAGS_RELEASE "-mdynamic-no-pic -fno-strict-aliasing") set(CMAKE_CXX_FLAGS_RELEASE "-mdynamic-no-pic -fno-strict-aliasing") From b04b8fd0e85f0504bd726e52a5f94413e61012c7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 14:14:21 +0000 Subject: [PATCH 023/143] fix for crash found when attempting to setup testing environment to find crashes :) scripts that have `Register` enabled and load another blend file would crash blender. --- source/blender/python/intern/bpy_interface.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 85f6163c721..d5ef6905b51 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -678,6 +678,11 @@ void BPY_modules_load_user(bContext *C) else { Py_DECREF(module); } + + /* check if the script loaded a new file */ + if (bmain != CTX_data_main(C)) { + break; + } } } } From 1795bd600b56f04b21d5e3435e4d61b6396e96d9 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 1 Oct 2012 14:15:05 +0000 Subject: [PATCH 024/143] Fixed memory leak in CustomData_interp in cases when sources count is more than SOURCE_BUF_SIZE and there's no more destination layers in main cycle of this function. --- source/blender/blenkernel/intern/customdata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index ba859cadf92..de55751f2ec 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1999,7 +1999,7 @@ void CustomData_interp(const CustomData *source, CustomData *dest, } /* if there are no more dest layers, we're done */ - if (dest_i >= dest->totlayer) return; + if (dest_i >= dest->totlayer) break; /* if we found a matching layer, copy the data */ if (dest->layers[dest_i].type == source->layers[src_i].type) { From 35639040504a1933b877c13904fcef1b33c2b0d3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 14:23:57 +0000 Subject: [PATCH 025/143] revert r50969, gives problems with weight paint + modifiers, need to investigate further after release. --- source/blender/blenkernel/intern/DerivedMesh.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index cdae3148e6b..9aaeb4c8baf 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -578,8 +578,13 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask) CustomData_set_only_copy(&dm->vertData, mask); CustomData_set_only_copy(&dm->edgeData, mask); CustomData_set_only_copy(&dm->faceData, mask); + /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with + * weight paint mode when there are modifiers applied, needs further investigation, + * see replies to r50969, Campbell */ +#if 0 CustomData_set_only_copy(&dm->loopData, mask); CustomData_set_only_copy(&dm->polyData, mask); +#endif } void DM_add_vert_layer(DerivedMesh *dm, int type, int alloctype, void *layer) From c01dc37e7a4208328e0d610a3de2cc722de59ea1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 14:51:53 +0000 Subject: [PATCH 026/143] fix [#32716] continuous grab bevel inset faces --- source/blender/editors/mesh/editmesh_tools.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 42979e6f2f4..a76d09827f0 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -4776,7 +4776,7 @@ void MESH_OT_bevel(wmOperatorType *ot) ot->poll = ED_operator_editmesh; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING; RNA_def_float(ot->srna, "percent", 0.0f, -FLT_MAX, FLT_MAX, "Percentage", "", 0.0f, 1.0f); /* XXX, disabled for 2.63 release, needs to work much better without overlap before we can give to users. */ @@ -5195,7 +5195,7 @@ void MESH_OT_inset(wmOperatorType *ot) ot->poll = ED_operator_editmesh; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING; /* properties */ RNA_def_boolean(ot->srna, "use_boundary", TRUE, "Boundary", "Inset face boundaries"); From 71499c16da307b451ff5484a28018a5cd9349f16 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 15:17:03 +0000 Subject: [PATCH 027/143] possible fix for crashing when re-doing mouse select operator, there was a missing NULL check on space-image. --- source/blender/editors/uvedit/uvedit_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 06da1c8bfea..70f2bf70ec8 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1744,7 +1744,7 @@ static int mouse_select(bContext *C, const float co[2], int extend, int loop) * the selection rather than de-selecting the closest. */ uvedit_pixel_to_float(sima, limit, 0.05f); - uvedit_pixel_to_float(sima, penalty, 5.0f / sima->zoom); + uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); /* retrieve operation mode */ if (ts->uv_flag & UV_SYNC_SELECTION) { From 7d1da8b60a5c404a263267477707455bcb7f3c3f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 15:26:48 +0000 Subject: [PATCH 028/143] fix for unlikely crash if smoke collision data couldn't be read. (pointer was used before doing NULL check) --- source/blender/blenloader/intern/readfile.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 38d6254b613..80943c2858b 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4368,13 +4368,14 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) smd->flow = NULL; smd->domain = NULL; smd->coll = newdataadr(fd, smd->coll); - smd->coll->smd = smd; if (smd->coll) { + smd->coll->smd = smd; smd->coll->points = NULL; smd->coll->numpoints = 0; } - else + else { smd->type = 0; + } } } else if (md->type == eModifierType_DynamicPaint) { From 4eb8bceaf82ea30782d7383ed94a0cb6f1b0e257 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 15:27:50 +0000 Subject: [PATCH 029/143] quiet some warnings. --- source/blender/editors/interface/interface_layout.c | 4 ++-- source/blender/editors/space_node/node_ops.c | 2 +- source/blender/editors/util/numinput.c | 4 +++- source/blender/opencl/intern/OCL_opencl.c | 8 ++++---- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 8ffbcd6d399..7a369019ac4 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -2870,12 +2870,12 @@ void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op, WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add"); RNA_string_set(&op_ptr, "operator", op->type->idname); - op_ptr = uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMIN, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0); + uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMIN, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0); WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add"); RNA_string_set(&op_ptr, "operator", op->type->idname); RNA_boolean_set(&op_ptr, "remove_active", TRUE); - op_ptr = uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMOUT, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0); + uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMOUT, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0); } if (op->type->ui) { diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index a5032fb6465..560ef9e8a29 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -167,7 +167,7 @@ void ED_operatormacros_node(void) ot = WM_operatortype_append_macro("NODE_OT_move_detach_links_release", "Detach", "Move a node to detach links", OPTYPE_UNDO | OPTYPE_REGISTER); WM_operatortype_macro_define(ot, "NODE_OT_links_detach"); - mot = WM_operatortype_macro_define(ot, "NODE_OT_translate_attach"); + WM_operatortype_macro_define(ot, "NODE_OT_translate_attach"); } /* helper function for repetitive select operator keymap */ diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c index 281b682465d..b73f5fa0869 100644 --- a/source/blender/editors/util/numinput.c +++ b/source/blender/editors/util/numinput.c @@ -279,7 +279,9 @@ char handleNumInput(NumInput *n, wmEvent *event) if (!n->ctrl[idx]) n->ctrl[idx] = 1; - if (fabsf(n->val[idx]) > 9999999.0f) ; + if (fabsf(n->val[idx]) > 9999999.0f) { + /* pass */ + } else if (n->ctrl[idx] == 1) { n->val[idx] *= 10; n->val[idx] += Val; diff --git a/source/blender/opencl/intern/OCL_opencl.c b/source/blender/opencl/intern/OCL_opencl.c index fa22acbc1a2..e3130e16bde 100644 --- a/source/blender/opencl/intern/OCL_opencl.c +++ b/source/blender/opencl/intern/OCL_opencl.c @@ -22,14 +22,14 @@ #include "OCL_opencl.h" -void OCL_init() +void OCL_init(void) { #ifdef _WIN32 - const char *path = "OpenCL.dll"; + const char *path = "OpenCL.dll"; #elif defined(__APPLE__) - const char *path = "/Library/Frameworks/OpenCL.framework/OpenCL"; + const char *path = "/Library/Frameworks/OpenCL.framework/OpenCL"; #else - const char *path = "libOpenCL.so"; + const char *path = "libOpenCL.so"; #endif clewInit(path); From 35ae7dae9ec8502bfca37f4ca4a0d176a73668d8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Oct 2012 15:39:29 +0000 Subject: [PATCH 030/143] fix for own bug in bmesh api, setting a byte string customdata layer assumed the input data was 256 length, assigning smaller values would read past the buffer. --- source/blender/editors/transform/transform_conversions.c | 2 ++ source/blender/python/bmesh/bmesh_py_types_customdata.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 540cbb97609..39a5da94798 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -1489,6 +1489,8 @@ static void createTransCurveVerts(TransInfo *t) count++; tail++; } + + (void)hdata; /* quiet warning */ } else if (propmode && head != tail) { calc_distanceCurveVerts(head, tail - 1); diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index 2a9592d21e2..0391839c763 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -1079,7 +1079,7 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj ret = -1; } else { - BLI_strncpy(mstring->s, tmp_val, sizeof(mstring->s)); + BLI_strncpy(mstring->s, tmp_val, MIN2(PyBytes_Size(py_value), sizeof(mstring->s))); } break; } From e5faa314f263bc572286a01442543b246a1eb81c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 1 Oct 2012 16:45:50 +0000 Subject: [PATCH 031/143] CMake: disable some warnings on mac that cause prints in nearly every file, and remove duplicate -Wundef entries. --- CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79070a77bb2..557c442c9db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1828,9 +1828,6 @@ if(CMAKE_COMPILER_IS_GNUCC) ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_MISSING_INCLUDE_DIRS -Wmissing-include-dirs) ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_DIV_BY_ZERO -Wno-div-by-zero) - # # this causes too many warnings, disable - # ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_UNDEFINED -Wundef) - # disable because it gives warnings for printf() & friends. # ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_DOUBLE_PROMOTION -Wdouble-promotion -Wno-error=double-promotion) @@ -1841,14 +1838,17 @@ if(CMAKE_COMPILER_IS_GNUCC) ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ALL -Wall) ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_INVALID_OFFSETOF -Wno-invalid-offsetof) ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_SIGN_COMPARE -Wno-sign-compare) - ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_MISSING_DECLARATIONS -Wmissing-declarations) ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_LOGICAL_OP -Wlogical-op) - ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_UNDEF -Wundef) ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_UNINITIALIZED -Wuninitialized) ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_INIT_SELF -Winit-self) # needs -Wuninitialized ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_MISSING_INCLUDE_DIRS -Wmissing-include-dirs) ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_DIV_BY_ZERO -Wno-div-by-zero) - ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_UNDEFINED -Wundef) + + # causes too many warnings + if(NOT APPLE) + ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_UNDEF -Wundef) + ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_MISSING_DECLARATIONS -Wmissing-declarations) + endif() # flags to undo strict flags ADD_CHECK_C_COMPILER_FLAG(CC_REMOVE_STRICT_FLAGS C_WARN_NO_DEPRECATED_DECLARATIONS -Wno-deprecated-declarations) From 02fc3eb56cbb544222276c31c8bbe2be804f1cbb Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 1 Oct 2012 17:09:12 +0000 Subject: [PATCH 032/143] Fix #32725: cycles border render + panorama camera not working in viewport. It will still look a bit strange since the viewport can't actually render such panorama views, so the opengl drawn scene behind the border render will not match up. --- intern/cycles/blender/blender_camera.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 46d5fefd4dc..e16677336d5 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -94,7 +94,7 @@ static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera) return fabsf(transform_get_column(&mat, 3).z); } -static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob) +static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob, bool skip_panorama = false) { BL::ID b_ob_data = b_ob.data(); @@ -111,7 +111,10 @@ static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob) bcam->type = CAMERA_ORTHOGRAPHIC; break; case BL::Camera::type_PANO: - bcam->type = CAMERA_PANORAMA; + if(!skip_panorama) + bcam->type = CAMERA_PANORAMA; + else + bcam->type = CAMERA_PERSPECTIVE; break; case BL::Camera::type_PERSP: default: @@ -378,7 +381,7 @@ void BlenderSync::sync_camera_motion(BL::Object b_ob, int motion) /* Sync 3D View Camera */ -static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height) +static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height, bool skip_panorama = false) { /* 3d view parameters */ bcam->nearclip = b_v3d.clip_start(); @@ -391,7 +394,7 @@ static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL: BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera(); if(b_ob) { - blender_camera_from_object(bcam, b_ob); + blender_camera_from_object(bcam, b_ob, skip_panorama); /* magic zoom formula */ bcam->zoom = (float)b_rv3d.view_camera_zoom(); @@ -447,7 +450,7 @@ static void blender_camera_border(BlenderCamera *bcam, BL::Scene b_scene, BL::Sp /* get viewport viewplane */ BlenderCamera view_bcam; blender_camera_init(&view_bcam); - blender_camera_from_view(&view_bcam, b_scene, b_v3d, b_rv3d, width, height); + blender_camera_from_view(&view_bcam, b_scene, b_v3d, b_rv3d, width, height, true); blender_camera_viewplane(&view_bcam, width, height, &view_left, &view_right, &view_bottom, &view_top, &view_aspect, &sensor_size); @@ -460,7 +463,7 @@ static void blender_camera_border(BlenderCamera *bcam, BL::Scene b_scene, BL::Sp /* get camera viewplane */ BlenderCamera cam_bcam; blender_camera_init(&cam_bcam); - blender_camera_from_object(&cam_bcam, b_ob); + blender_camera_from_object(&cam_bcam, b_ob, true); width = (int)(r.resolution_x()*r.resolution_percentage()/100); height = (int)(r.resolution_y()*r.resolution_percentage()/100); From 20ca67bc3570f01ce2f9f6163382df51648b11a3 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 1 Oct 2012 17:38:22 +0000 Subject: [PATCH 033/143] Fix #32728: File Output node always save as RGBA, even when RGB is selected Seems to be a regression in new compositor system -- wrong number of planes was using for image buffer allocation. --- .../blender/compositor/operations/COM_OutputFileOperation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp index c8b6a4ee330..b3c2df7230f 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp @@ -129,7 +129,7 @@ void OutputSingleLayerOperation::deinitExecution() if (this->getWidth() * this->getHeight() != 0) { int size = get_datatype_size(this->m_datatype); - ImBuf *ibuf = IMB_allocImBuf(this->getWidth(), this->getHeight(), size * 8, 0); + ImBuf *ibuf = IMB_allocImBuf(this->getWidth(), this->getHeight(), this->m_format->planes, 0); Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; From 8fa211dd81a6767cef8913dd05189ec8ad3a12a5 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 1 Oct 2012 17:40:02 +0000 Subject: [PATCH 034/143] Fix [#32719] "New object align to view" option doesn't work on lamps and force fields There was strange context changes in the Add menu... Now everything uses the EXEC_REGION_WIN one (no need to invoke here, and metaballs have a strange specific invoke func...). This fixes the problem when using Add menu from a 3D view. Obviously, it still doesn't work when used from Info window's header, but that can't be helped for now (and never worked for any kind of object). Anyway, imho all this "add object" code could use some review/cleanup, both on py menu and C ops side, but this is obviously postponed to after 2.64! --- release/scripts/startup/bl_ui/space_info.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 04ea6b818ac..a67c30e2b85 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -272,7 +272,9 @@ class INFO_MT_add(Menu): # note, don't use 'EXEC_SCREEN' or operators wont get the 'v3d' context. - layout.operator_context = 'EXEC_AREA' + # Note: was EXEC_AREA, but this context does not have the 'rv3d', which prevents + # "align_view" to work on first call (see [#32719]). + layout.operator_context = 'EXEC_REGION_WIN' #layout.operator_menu_enum("object.mesh_add", "type", text="Mesh", icon='OUTLINER_OB_MESH') layout.menu("INFO_MT_mesh_add", icon='OUTLINER_OB_MESH') @@ -282,7 +284,7 @@ class INFO_MT_add(Menu): #layout.operator_menu_enum("object.surface_add", "type", text="Surface", icon='OUTLINER_OB_SURFACE') layout.menu("INFO_MT_surface_add", icon='OUTLINER_OB_SURFACE') layout.operator_menu_enum("object.metaball_add", "type", text="Metaball", icon='OUTLINER_OB_META') - layout.operator_context = 'INVOKE_REGION_WIN' +# layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT') layout.separator() @@ -295,7 +297,7 @@ class INFO_MT_add(Menu): layout.separator() layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA') - layout.operator_context = 'EXEC_AREA' +# layout.operator_context = 'EXEC_AREA' layout.operator_menu_enum("object.lamp_add", "type", text="Lamp", icon='OUTLINER_OB_LAMP') layout.separator() From b1f1ee5138a1398fb5a824732a9ec9d74b3113e1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 1 Oct 2012 18:31:32 +0000 Subject: [PATCH 035/143] Fix/workaround #31987: sample as lamp for environment textures not working with multi GPU when resolution > 128. --- intern/cycles/render/light.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 6445c04257f..5c1737bd60a 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -67,13 +67,19 @@ static void dump_background_pixels(Device *device, DeviceScene *dscene, int res, main_task.shader_x = 0; main_task.shader_w = width*height; + /* disabled splitting for now, there's an issue with multi-GPU mem_copy_from */ +#if 0 list split_tasks; - main_task.split_max_size(split_tasks, 128*128); + main_task.split_max_size(split_tasks, 128*128); foreach(DeviceTask& task, split_tasks) { device->task_add(task); device->task_wait(); } +#else + device->task_add(main_task); + device->task_wait(); +#endif device->mem_copy_from(d_output, 0, 1, d_output.size(), sizeof(float4)); device->mem_free(d_input); From 4572a82de76668c671c37951fcf1c459b8231a86 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 1 Oct 2012 20:21:50 +0000 Subject: [PATCH 036/143] Fix #32712: non-multilayer openexr file save for a single channel image would write wrong colors for float and crash for half-float. --- source/blender/imbuf/intern/openexr/openexr_api.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 13078921d1c..066d07a36c5 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -372,10 +372,10 @@ static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags for (int j = ibuf->x; j > 0; j--) { to->r = from[0]; - to->g = from[1]; - to->b = from[2]; + to->g = (channels >= 2) ? from[1] : from[0]; + to->b = (channels >= 3) ? from[2] : from[0]; to->a = (channels >= 4) ? from[3] : 1.0f; - to++; from += 4; + to++; from += channels; } } } @@ -383,7 +383,7 @@ static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags unsigned char *from; for (int i = ibuf->y - 1; i >= 0; i--) { - from = (unsigned char *)ibuf->rect + channels * i * width; + from = (unsigned char *)ibuf->rect + 4 * i * width; for (int j = ibuf->x; j > 0; j--) { to->r = srgb_to_linearrgb((float)from[0] / 255.0f); @@ -448,8 +448,8 @@ static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flag /* last scanline, stride negative */ rect[0] = ibuf->rect_float + channels * (height - 1) * width; - rect[1] = rect[0] + 1; - rect[2] = rect[0] + 2; + rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0]; + rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0]; rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */ frameBuffer.insert("R", Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride)); From 0d647f68a389014bf2fc733a9121f3422905ed9e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 2 Oct 2012 00:28:01 +0000 Subject: [PATCH 037/143] fix: path looper was checking the path of old tessface external data rather then loop data. (missed with bmesh upgrade) --- source/blender/blenlib/intern/bpath.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenlib/intern/bpath.c b/source/blender/blenlib/intern/bpath.c index be1f4eb3a35..f72b5882f22 100644 --- a/source/blender/blenlib/intern/bpath.c +++ b/source/blender/blenlib/intern/bpath.c @@ -544,8 +544,8 @@ void BLI_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int case ID_ME: { Mesh *me = (Mesh *)id; - if (me->fdata.external) { - rewrite_path_fixed(me->fdata.external->filename, visit_cb, absbase, bpath_user_data); + if (me->ldata.external) { + rewrite_path_fixed(me->ldata.external->filename, visit_cb, absbase, bpath_user_data); } } break; From 9a8e82ae561db67f057fbb1799d1341b6d14018c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 2 Oct 2012 00:54:41 +0000 Subject: [PATCH 038/143] fix for crash loading durian file '08.5e_comp.blend' - external data pointer for face data was NULL. --- source/blender/blenkernel/intern/mesh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index e45a052db4d..1aaeebf5109 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2043,7 +2043,7 @@ static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, int side, corners; if (CustomData_external_test(fdata, CD_MDISPS)) { - if (id) { + if (id && fdata->external) { CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filename); } From 959dc02f96b9366b3a73acf918ca0360c55d387f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 2 Oct 2012 01:10:18 +0000 Subject: [PATCH 039/143] fix for error in mask drawing, was using glVertex3fv on 2d verts. (buffer overrun) --- source/blender/editors/mask/mask_draw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index fe6567424b6..a60b771d179 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -202,16 +202,16 @@ static void draw_spline_points(MaskLayer *masklay, MaskSpline *spline, glLineWidth(3); glColor4ubv(rgb_gray); glBegin(GL_LINES); - glVertex3fv(vert); - glVertex3fv(handle); + glVertex2fv(vert); + glVertex2fv(handle); glEnd(); glLineWidth(1); } glColor3ubv(rgb_spline); glBegin(GL_LINES); - glVertex3fv(vert); - glVertex3fv(handle); + glVertex2fv(vert); + glVertex2fv(handle); glEnd(); } @@ -226,7 +226,7 @@ static void draw_spline_points(MaskLayer *masklay, MaskSpline *spline, glColor3f(0.5f, 0.5f, 0.0f); glBegin(GL_POINTS); - glVertex3fv(vert); + glVertex2fv(vert); glEnd(); /* draw handle points */ @@ -242,7 +242,7 @@ static void draw_spline_points(MaskLayer *masklay, MaskSpline *spline, } glBegin(GL_POINTS); - glVertex3fv(handle); + glVertex2fv(handle); glEnd(); } } From dc8340fa331164b78ba3414a67ec625bc80d30b6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 2 Oct 2012 03:18:48 +0000 Subject: [PATCH 040/143] correct some include dirs not being included as SYSTEM paths in cmake. --- extern/carve/CMakeLists.txt | 2 +- intern/bsp/CMakeLists.txt | 2 +- intern/cycles/render/CMakeLists.txt | 1 - intern/opencolorio/CMakeLists.txt | 32 +++++++++++-------- source/blender/editors/mask/CMakeLists.txt | 2 +- .../editors/sculpt_paint/CMakeLists.txt | 2 +- .../blender/editors/space_clip/CMakeLists.txt | 2 +- .../gameengine/BlenderRoutines/CMakeLists.txt | 2 +- 8 files changed, 24 insertions(+), 21 deletions(-) diff --git a/extern/carve/CMakeLists.txt b/extern/carve/CMakeLists.txt index 3916047ff32..5e917ac1e44 100644 --- a/extern/carve/CMakeLists.txt +++ b/extern/carve/CMakeLists.txt @@ -158,7 +158,7 @@ if(WITH_BOOST) -DCARVE_SYSTEM_BOOST ) - list(APPEND INC + list(APPEND INC_SYS ${BOOST_INCLUDE_DIR} ) endif() diff --git a/intern/bsp/CMakeLists.txt b/intern/bsp/CMakeLists.txt index e492c04423e..136c168bdb8 100644 --- a/intern/bsp/CMakeLists.txt +++ b/intern/bsp/CMakeLists.txt @@ -62,7 +62,7 @@ if(WITH_BOOST) -DCARVE_SYSTEM_BOOST ) - list(APPEND INC + list(APPEND INC_SYS ${BOOST_INCLUDE_DIR} ) endif() diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index 6b8e3702d03..e75a3b37f3b 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -7,7 +7,6 @@ set(INC ../kernel/osl ../bvh ../util - ${GLEW_INCLUDE_PATH} ) set(INC_SYS ${GLEW_INCLUDE_PATH} diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt index 479bbd3ab0a..9f5d4cd332c 100644 --- a/intern/opencolorio/CMakeLists.txt +++ b/intern/opencolorio/CMakeLists.txt @@ -23,25 +23,33 @@ # # ***** END GPL LICENSE BLOCK ***** +set(INC + . + ../guardedalloc +) + +set(INC_SYS +) + + if(WITH_OPENCOLORIO) - set(INC - . + + list(APPEND INC_SYS ${OPENCOLORIO_INCLUDE_DIRS} ) + if(WIN32 AND NOT MINGW) + list(APPEND INC_SYS + ${BOOST_INCLUDE_DIR} + ) + endif() + set(SRC ocio_capi.cpp ocio_capi.h ) - - if(WIN32 AND NOT MINGW) - list(APPEND INC - ${BOOST_INCLUDE_DIR} - ) - endif() else() - set(INC - . + list(APPEND INC ../../source/blender/blenlib ) @@ -51,10 +59,6 @@ else() ) endif() -set(INC_SYS - ../guardedalloc -) - add_definitions( ) diff --git a/source/blender/editors/mask/CMakeLists.txt b/source/blender/editors/mask/CMakeLists.txt index 57be5a2234a..25fb9cb6430 100644 --- a/source/blender/editors/mask/CMakeLists.txt +++ b/source/blender/editors/mask/CMakeLists.txt @@ -30,10 +30,10 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc - ${GLEW_INCLUDE_PATH} ) set(INC_SYS + ${GLEW_INCLUDE_PATH} ) set(SRC diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 043b7ecb5cb..ae72dce1415 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -20,6 +20,7 @@ set(INC ../include + ../uvedit ../../blenkernel ../../blenlib ../../blenloader @@ -28,7 +29,6 @@ set(INC ../../imbuf ../../makesdna ../../makesrna - ../uvedit ../../render/extern/include ../../windowmanager ../../../../intern/guardedalloc diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt index ecc4dea8b05..75e3d8d5685 100644 --- a/source/blender/editors/space_clip/CMakeLists.txt +++ b/source/blender/editors/space_clip/CMakeLists.txt @@ -33,10 +33,10 @@ set(INC ../../windowmanager ../../gpu ../../../../intern/guardedalloc - ${GLEW_INCLUDE_PATH} ) set(INC_SYS + ${GLEW_INCLUDE_PATH} ) set(SRC diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt index 96b56768b8f..fa0994d788a 100644 --- a/source/gameengine/BlenderRoutines/CMakeLists.txt +++ b/source/gameengine/BlenderRoutines/CMakeLists.txt @@ -28,11 +28,11 @@ set(INC ../../../intern/guardedalloc ../../../intern/moto/include ../../../intern/string - ${GLEW_INCLUDE_PATH} ) set(INC_SYS ${PTHREADS_INCLUDE_DIRS} + ${GLEW_INCLUDE_PATH} ) set(SRC From 16c4795e96f6dd7674dbcc3b44bd7b629237a81c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 2 Oct 2012 04:31:51 +0000 Subject: [PATCH 041/143] fix for mesh_foreachScreenEdge__mapFunc running the callback with V3D_CLIP_TEST_RV3D_CLIPPING'd verts. (used uninitialised stack memory) --- source/blender/editors/space_view3d/drawobject.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index c49e7eebb48..7badca304c4 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -2162,6 +2162,10 @@ static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, const flo if (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) { view3d_project_short_clip(data->vc.ar, v0co, s[0], TRUE); view3d_project_short_clip(data->vc.ar, v1co, s[1], TRUE); + + if (s[0][0] == IS_CLIPPED || s[1][0] == IS_CLIPPED) { + return; + } } else { float v1_co[3], v2_co[3]; @@ -2169,6 +2173,8 @@ static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, const flo mul_v3_m4v3(v1_co, data->vc.obedit->obmat, v0co); mul_v3_m4v3(v2_co, data->vc.obedit->obmat, v1co); + /* XXX, todo, use ED_view3d_project_int_noclip(...), however these functions work differently + * and need to be cleaned up, Campbell */ ED_view3d_project_short_noclip(data->vc.ar, v1_co, s[0]); ED_view3d_project_short_noclip(data->vc.ar, v2_co, s[1]); From 636a8d49a67b453fef2693c602966c1c115168fc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 2 Oct 2012 05:12:49 +0000 Subject: [PATCH 042/143] fix for crash in own recent masking commit with 'flood fill' operator. --- source/blender/editors/sculpt_paint/paint_mask.c | 7 ++++++- source/blender/editors/sculpt_paint/sculpt.c | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index e309bdb99cb..697d7c63d1f 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -54,6 +54,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_sculpt.h" #include "paint_intern.h" #include "sculpt_intern.h" /* for undo push */ @@ -77,7 +78,9 @@ static void mask_flood_fill_set_elem(float *elem, static int mask_flood_fill_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); + struct Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); + struct MultiresModifierData *mmd = sculpt_multires_active(scene, ob); PaintMaskFloodMode mode; float value; DerivedMesh *dm; @@ -88,7 +91,9 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) mode = RNA_enum_get(op->ptr, "mode"); value = RNA_float_get(op->ptr, "value"); - dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH); + ED_sculpt_mask_layers_ensure(ob, mmd); + + dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); pbvh = dm->getPBVH(ob, dm); ob->sculpt->pbvh = pbvh; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 5f17d44a881..ec0478d128f 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4267,7 +4267,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) paint_cursor_start(C, sculpt_poll); } - WM_event_add_notifier(C, NC_SCENE | ND_MODE, CTX_data_scene(C)); + WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); return OPERATOR_FINISHED; } From c17cf368531cebfbf2cb300779f536d19d558bed Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Tue, 2 Oct 2012 06:24:02 +0000 Subject: [PATCH 043/143] UI: * Fix RNA name for "turbulence_strength" property. --- source/blender/makesrna/intern/rna_texture.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 483e3ab7f8a..45e3d15b9be 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -1733,6 +1733,7 @@ static void rna_def_texture_pointdensity(BlenderRNA *brna) prop = RNA_def_property(srna, "turbulence_strength", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "noise_fac"); RNA_def_property_range(prop, 0.01, FLT_MAX); + RNA_def_property_ui_text(prop, "Turbulence Strength", "Strength of the added turbulent noise"); RNA_def_property_update(prop, 0, "rna_Texture_update"); prop = RNA_def_property(srna, "turbulence_depth", PROP_INT, PROP_NONE); From ecbeb0f575b2e6152795211c1fa807b384a6288d Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 2 Oct 2012 10:03:16 +0000 Subject: [PATCH 044/143] * fix for regression file [compo_map_zcombine_cubes.blend] the alpha mix formula was wrong. updated it. Be aware that the regression file does not take the alpha into account, but it should. or at least one z combine should and the other not. this fails in 2.63a. - At Mind - --- .../compositor/operations/COM_ZCombineOperation.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cpp b/source/blender/compositor/operations/COM_ZCombineOperation.cpp index 7e23e7290f8..c3ae42a6d8a 100644 --- a/source/blender/compositor/operations/COM_ZCombineOperation.cpp +++ b/source/blender/compositor/operations/COM_ZCombineOperation.cpp @@ -69,7 +69,7 @@ void ZCombineAlphaOperation::executePixel(float output[4], float x, float y, Pix this->m_depth1Reader->read(depth1, x, y, sampler); this->m_depth2Reader->read(depth2, x, y, sampler); - if (depth1[0] < depth2[0]) { + if (depth1[0] <= depth2[0]) { this->m_image1Reader->read(color1, x, y, sampler); this->m_image2Reader->read(color2, x, y, sampler); } @@ -79,9 +79,9 @@ void ZCombineAlphaOperation::executePixel(float output[4], float x, float y, Pix } float fac = color1[3]; float ifac = 1.0f - fac; - output[0] = color1[0] + ifac * color2[0]; - output[1] = color1[1] + ifac * color2[1]; - output[2] = color1[2] + ifac * color2[2]; + output[0] = fac*color1[0] + ifac * color2[0]; + output[1] = fac*color1[1] + ifac * color2[1]; + output[2] = fac*color1[2] + ifac * color2[2]; output[3] = MAX2(color1[3], color2[3]); } From e795b8410b4964192791834faa0f94d0a017403b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 2 Oct 2012 11:37:15 +0000 Subject: [PATCH 045/143] * fix for regression test [compo_map_uv.blend] the wrapping was resized to fit the uv map. this step was wrong and has been deleted. --- source/blender/compositor/operations/COM_MapUVOperation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp index fe6ebcebf97..1fa484ea2b6 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.cpp +++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp @@ -24,7 +24,7 @@ MapUVOperation::MapUVOperation() : NodeOperation() { - this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); this->addInputSocket(COM_DT_VECTOR); this->addOutputSocket(COM_DT_COLOR); this->m_alpha = 0.0f; From 78d6288be33a45f5a4227941c238f5de92da24fb Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 2 Oct 2012 13:13:26 +0000 Subject: [PATCH 046/143] correct spelling error in operator property --- release/scripts/startup/bl_operators/anim.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py index 98bad276109..c5fc3c50f3f 100644 --- a/release/scripts/startup/bl_operators/anim.py +++ b/release/scripts/startup/bl_operators/anim.py @@ -189,7 +189,7 @@ class BakeAction(Operator): name="Only Selected", default=True, ) - clear_consraints = BoolProperty( + clear_constraints = BoolProperty( name="Clear Constraints", default=False, ) @@ -212,7 +212,7 @@ class BakeAction(Operator): self.only_selected, 'POSE' in self.bake_types, 'OBJECT' in self.bake_types, - self.clear_consraints, + self.clear_constraints, True, ) From 75fff053483341d1b163c14bf6b18019c077f5dd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 2 Oct 2012 13:24:28 +0000 Subject: [PATCH 047/143] revert fix for [#31555] Username with special chars in Windows 7 this breaks and causes bug: [#32720], where sys.stdout becomes invalid and print() does nothing. On investigation - python is not getting the environment variable from blender (aparently because its a DLL?) so this should be resolved rather then overwriting sys.stdout. --- source/blender/python/intern/bpy_interface.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index d5ef6905b51..b628f42e759 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -251,6 +251,10 @@ void BPY_python_start(int argc, const char **argv) * an error, this is highly annoying, another stumbling block for devs, * so use a more relaxed error handler and enforce utf-8 since the rest of * blender is utf-8 too - campbell */ + + /* XXX, update: this is unreliable! 'PYTHONIOENCODING' is ignored in MS-Windows + * when dynamically linked, see: [#31555] for details. + * Python doesn't expose a good way to set this. */ BLI_setenv("PYTHONIOENCODING", "utf-8:surrogateescape"); /* Python 3.2 now looks for '2.xx/python/include/python3.2d/pyconfig.h' to @@ -264,15 +268,6 @@ void BPY_python_start(int argc, const char **argv) Py_Initialize(); -#ifdef WIN32 - /* this is disappointing, its likely a bug in python? - * for some reason 'PYTHONIOENCODING' is ignored in windows - * see: [#31555] for details. */ - PyRun_SimpleString("import sys, io\n" - "sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='surrogateescape', line_buffering=True)\n" - "sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='surrogateescape', line_buffering=True)\n"); -#endif /* WIN32 */ - // PySys_SetArgv(argc, argv); // broken in py3, not a huge deal /* sigh, why do python guys not have a (char **) version anymore? */ { From 62c151bd1c15b1f74b2b23736e06e5b43627381c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 2 Oct 2012 13:59:05 +0000 Subject: [PATCH 048/143] freeing node trees no longer decreases their user counts, this cause causing invalid memory access when freeing the blend file. --- source/blender/blenkernel/intern/node.c | 8 ++++++++ .../compositor/operations/COM_ZCombineOperation.cpp | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index ade418e409f..1760b3ad03a 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1047,7 +1047,15 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user) /* same as ntreeFreeTree_ex but always manage users */ void ntreeFreeTree(bNodeTree *ntree) { + /* XXX, this is correct, however when freeing the entire database + * this ends up accessing freed data which isn't properly unlinking + * its self from scene nodes, SO - for now prefer invalid usercounts + * on free rather then bad memory access - Campbell */ +#if 0 ntreeFreeTree_ex(ntree, TRUE); +#else + ntreeFreeTree_ex(ntree, FALSE); +#endif } void ntreeFreeCache(bNodeTree *ntree) diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cpp b/source/blender/compositor/operations/COM_ZCombineOperation.cpp index c3ae42a6d8a..5e4f90b0269 100644 --- a/source/blender/compositor/operations/COM_ZCombineOperation.cpp +++ b/source/blender/compositor/operations/COM_ZCombineOperation.cpp @@ -79,10 +79,10 @@ void ZCombineAlphaOperation::executePixel(float output[4], float x, float y, Pix } float fac = color1[3]; float ifac = 1.0f - fac; - output[0] = fac*color1[0] + ifac * color2[0]; - output[1] = fac*color1[1] + ifac * color2[1]; - output[2] = fac*color1[2] + ifac * color2[2]; - output[3] = MAX2(color1[3], color2[3]); + output[0] = fac * color1[0] + ifac * color2[0]; + output[1] = fac * color1[1] + ifac * color2[1]; + output[2] = fac * color1[2] + ifac * color2[2]; + output[3] = max(color1[3], color2[3]); } void ZCombineOperation::deinitExecution() From 27c4c1f417676b5bfd0ef240167e23dbc3ea9556 Mon Sep 17 00:00:00 2001 From: Alex Fraser Date: Tue, 2 Oct 2012 14:15:02 +0000 Subject: [PATCH 049/143] Added example of KX_GameObject subclassing to game engine docs. --- doc/python_api/rst/bge.logic.rst | 6 +-- doc/python_api/rst/bge.types.rst | 73 ++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/doc/python_api/rst/bge.logic.rst b/doc/python_api/rst/bge.logic.rst index 0d1d0df88c3..260a86f7c59 100644 --- a/doc/python_api/rst/bge.logic.rst +++ b/doc/python_api/rst/bge.logic.rst @@ -2,9 +2,9 @@ Game Logic (bge.logic) ====================== -***** -Intro -***** +************ +Introduction +************ Module to access logic functions, imported automatically into the python controllers namespace. diff --git a/doc/python_api/rst/bge.types.rst b/doc/python_api/rst/bge.types.rst index 31ae45b9bf0..f4374f7f355 100644 --- a/doc/python_api/rst/bge.types.rst +++ b/doc/python_api/rst/bge.types.rst @@ -4,6 +4,33 @@ Game Types (bge.types) .. module:: bge.types +************ +Introduction +************ + +This module contains the classes that appear as instances in the Game Engine. A +script must interact with these classes if it is to affect the behaviour of +objects in a game. + +The following example would move an object (i.e. an instance of +:class:`KX_GameObject`) one unit up. + +.. code-block:: python + + # bge.types.SCA_PythonController + cont = bge.logic.getCurrentController() + + # bge.types.KX_GameObject + obj = cont.owner + obj.worldPosition.z += 1 + +To run the code, it could be placed in a Blender text block and executed with +a :class:`SCA_PythonController` logic brick. + +***** +Types +***** + .. class:: PyObjectPlus PyObjectPlus base class of most other types in the Game Engine. @@ -854,6 +881,52 @@ Game Types (bge.types) Calling ANY method or attribute on an object that has been removed from a scene will raise a SystemError, if an object may have been removed since last accessing it use the :data:`invalid` attribute to check. + KX_GameObject can be subclassed to extend functionality. For example: + + .. code-block:: python + + import bge + + class CustomGameObject(bge.types.KX_GameObject): + RATE = 0.05 + + def __init__(self, old_owner): + # "old_owner" can just be ignored. At this point, "self" is + # already the object in the scene, and "old_owner" has been + # destroyed. + + # New attributes can be defined - but we could also use a game + # property, like "self['rate']". + self.rate = CustomGameObject.RATE + + def update(self): + self.worldPosition.z += self.rate + + # switch direction + if self.worldPosition.z > 1.0: + self.rate = -CustomGameObject.RATE + elif self.worldPosition.z < 0.0: + self.rate = CustomGameObject.RATE + + # Called first + def mutate(cont): + old_object = cont.owner + mutated_object = CustomGameObject(cont.owner) + + # After calling the constructor above, references to the old object + # should not be used. + assert(old_object is not mutated_object) + assert(old_object.invalid) + assert(mutated_object is cont.owner) + + # Called later - note we are now working with the mutated object. + def update(cont): + cont.owner.update() + + When subclassing objects other than empties and meshes, the specific type + should be used - e.g. inherit from :class:`BL_ArmatureObject` when the object + to mutate is an armature. + .. attribute:: name The object's name. (read-only). From 8b718bee472f5b42b4109c772c0aa10f3688a8cb Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 2 Oct 2012 16:39:37 +0000 Subject: [PATCH 050/143] Entering Bcon5 stage! - Bump version to 2.64 - No version char for this cycle - This is finally release stage! Splash would be commited in some hours from now. Thanks everyone! --- source/blender/blenkernel/BKE_blender.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index dd45ab19eb1..a7bf491c382 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -41,8 +41,8 @@ extern "C" { /* these lines are grep'd, watch out for our not-so-awesome regex * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ -#define BLENDER_VERSION 263 -#define BLENDER_SUBVERSION 22 +#define BLENDER_VERSION 264 +#define BLENDER_SUBVERSION 0 /* 262 was the last editmesh release but its has compatibility code for bmesh data, * so set the minversion to 2.61 */ @@ -51,9 +51,9 @@ extern "C" { /* used by packaging tools */ /* can be left blank, otherwise a,b,c... etc with no quotes */ -#define BLENDER_VERSION_CHAR a +#define BLENDER_VERSION_CHAR /* alpha/beta/rc/release, docs use this */ -#define BLENDER_VERSION_CYCLE rc +#define BLENDER_VERSION_CYCLE release extern char versionstr[]; /* from blender.c */ From 9e0a1b613f6b741bbdaaab6af35a1fc0743fe4b2 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 3 Oct 2012 05:49:22 +0000 Subject: [PATCH 051/143] fix for cmake constructing an invalid include path. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 557c442c9db..a91b5a3bdac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -569,7 +569,7 @@ if(UNIX AND NOT APPLE) # lame, but until we have proper find module for ffmpeg set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include) if(EXISTS "${FFMPEG}/include/ffmpeg/") - set(FFMPEG_INCLUDE_DIRS "${FFMPEG_INCLUDE_DIRS} ${FFMPEG}/include/ffmpeg") + list(APPEND FFMPEG_INCLUDE_DIRS "${FFMPEG}/include/ffmpeg") endif() # end lameness From b288bc4ea4329c1097216979faef93295fcdb0db Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 3 Oct 2012 07:33:04 +0000 Subject: [PATCH 052/143] fix [#32739] Glare node does "add" instead of "lighten" --- .../compositor/operations/COM_MixGlareOperation.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source/blender/compositor/operations/COM_MixGlareOperation.cpp b/source/blender/compositor/operations/COM_MixGlareOperation.cpp index b6a9aa3da3c..1c6555206da 100644 --- a/source/blender/compositor/operations/COM_MixGlareOperation.cpp +++ b/source/blender/compositor/operations/COM_MixGlareOperation.cpp @@ -40,9 +40,13 @@ void MixGlareOperation::executePixel(float output[4], float x, float y, PixelSam value = inputValue[0]; float mf = 2.f - 2.f * fabsf(value - 0.5f); - output[0] = mf * ((inputColor1[0]) + value * (inputColor2[0] - inputColor1[0])); - output[1] = mf * ((inputColor1[1]) + value * (inputColor2[1] - inputColor1[1])); - output[2] = mf * ((inputColor1[2]) + value * (inputColor2[2] - inputColor1[2])); + if (inputColor1[0] < 0.0f) inputColor1[0] = 0.0f; + if (inputColor1[1] < 0.0f) inputColor1[1] = 0.0f; + if (inputColor1[2] < 0.0f) inputColor1[2] = 0.0f; + + output[0] = mf * max(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); + output[1] = mf * max(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); + output[2] = mf * max(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); output[3] = inputColor1[3]; clampIfNeeded(output); From 916a58f4e09e2fbb4be9a79517b39e9a086fa199 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 3 Oct 2012 07:35:29 +0000 Subject: [PATCH 053/143] fix [#32743] Freed memory access when freeing materials. --- source/blender/blenkernel/intern/node.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 1760b3ad03a..8cede4f51a5 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1030,9 +1030,18 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user) next = node->next; /* ntreeUserIncrefID inline */ + + /* XXX, this is correct, however when freeing the entire database + * this ends up accessing freed data which isn't properly unlinking + * its self from scene nodes, SO - for now prefer invalid usercounts + * on free rather then bad memory access - Campbell */ +#if 0 if (do_id_user) { id_us_min(node->id); } +#else + (void)do_id_user; +#endif nodeFreeNode(ntree, node); } @@ -1047,15 +1056,7 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user) /* same as ntreeFreeTree_ex but always manage users */ void ntreeFreeTree(bNodeTree *ntree) { - /* XXX, this is correct, however when freeing the entire database - * this ends up accessing freed data which isn't properly unlinking - * its self from scene nodes, SO - for now prefer invalid usercounts - * on free rather then bad memory access - Campbell */ -#if 0 ntreeFreeTree_ex(ntree, TRUE); -#else - ntreeFreeTree_ex(ntree, FALSE); -#endif } void ntreeFreeCache(bNodeTree *ntree) From 98698753b15a172a0605b0b76f3652f36a63d8a2 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 3 Oct 2012 08:51:05 +0000 Subject: [PATCH 054/143] Fix #32742: Motion path calculation on linked armatures locks up Blender Issue was happening when linking armature object and making proxy and was caused by not copying visualization settings in BKE_pose_copy_data. This lead to deadlocks in motion path drawing code. After discussion with Campbell decided it is crucial fix since it fixes bug appearing in really common scenario of using armatures. --- source/blender/blenkernel/intern/action.c | 1 + source/blender/blenloader/intern/readfile.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 925658b84f4..66df7eccbd0 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -539,6 +539,7 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, int copycon) outPose->iksolver = src->iksolver; outPose->ikdata = NULL; outPose->ikparam = MEM_dupallocN(src->ikparam); + outPose->avs = src->avs; for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) { /* TODO: rename this argument... */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 80943c2858b..97aa21cea40 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -8008,6 +8008,22 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } + /* correction for files saved in blender version when BKE_pose_copy_data + * didn't copy animation visualization, which lead to deadlocks on motion + * path calculation for proxied armatures, see [#32742] + */ + if (main->versionfile < 264) { + Object *ob; + + for (ob = main->object.first; ob; ob = ob->id.next) { + if (ob->pose) { + if (ob->pose->avs.path_step == 0) { + animviz_settings_init(&ob->pose->avs); + } + } + } + } + /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */ From 139524b144e40e46d08d9d1f24f436ff0cb152f2 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Wed, 3 Oct 2012 09:37:36 +0000 Subject: [PATCH 055/143] * Fix for the elsyiun.xml theme, Reports in Info Header were not readable (grey on grey). Patch by "ejnersan" in IRC. --- release/scripts/presets/interface_theme/elsyiun.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/presets/interface_theme/elsyiun.xml b/release/scripts/presets/interface_theme/elsyiun.xml index 7d4db75dc89..581f5ce82d6 100644 --- a/release/scripts/presets/interface_theme/elsyiun.xml +++ b/release/scripts/presets/interface_theme/elsyiun.xml @@ -283,7 +283,7 @@ Date: Wed, 3 Oct 2012 12:07:29 +0000 Subject: [PATCH 056/143] Correction to commit rev48866 -- convert_tface_mt must happen before BKE_mesh_do_versions_convert_mfaces_to_mpolys Discovered when were looking into crystal_cube.blend from our regression files collection. Now it should look the same as in 2.62 release. 2.63 release wouldn't work correct for this file because of wrong mtface->material conversion after bmesh merge. --- source/blender/blenloader/intern/readfile.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 97aa21cea40..aa44b01544f 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3665,7 +3665,14 @@ static void lib_link_mesh(FileData *fd, Main *main) if (me->mr && me->mr->levels.first) lib_link_customdata_mtface(fd, me, &me->mr->fdata, ((MultiresLevel*)me->mr->levels.first)->totface); - + } + } + + /* convert texface options to material */ + convert_tface_mt(fd, main); + + for (me = main->mesh.first; me; me = me->id.next) { + if (me->id.flag & LIB_NEED_LINK) { /*check if we need to convert mfaces to mpolys*/ if (me->totface && !me->totpoly) { /* temporarily switch main so that reading from @@ -3677,14 +3684,7 @@ static void lib_link_mesh(FileData *fd, Main *main) G.main = gmain; } - } - } - /* convert texface options to material */ - convert_tface_mt(fd, main); - - for (me = main->mesh.first; me; me = me->id.next) { - if (me->id.flag & LIB_NEED_LINK) { /* * Re-tessellate, even if the polys were just created from tessfaces, this * is important because it: From 29898418c8cb6134aa8a057146b67cefd4a16fed Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 3 Oct 2012 14:16:07 +0000 Subject: [PATCH 057/143] Artifacts on splash are resolved. --- release/datafiles/splash.png | Bin 229594 -> 212426 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png index 2dab9257905f0bb51fb8383f2a4d13fcb07cd03d..7f40ead3911a72ea22362d50239e169107df00ce 100644 GIT binary patch delta 211374 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 s9151Xs5J3)@T>t<807*qoM6N<$g3@=NjQ{`u delta 228679 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 BxiDBGh`~tO;%7$s>Rz^Q~A58P#Qod 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 z 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%0ASY^Y>fT%n5`6+T&mL;jdm$#bN3~iA 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 z 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 Date: Wed, 3 Oct 2012 21:52:36 +0000 Subject: [PATCH 058/143] colormanage_colorspace_get_named() can (and does) return NULL, added checks to prevent null pointer dereference if the named color profile isn't found --- source/blender/imbuf/intern/colormanagement.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 02d84819924..1a86932b0a9 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -881,7 +881,7 @@ void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace) { ColorSpace *colorspace = colormanage_colorspace_get_named(from_colorspace); - if (colorspace->is_data) { + if (colorspace && colorspace->is_data) { ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; return; } @@ -1074,7 +1074,7 @@ void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name) { ColorSpace *colorspace = colormanage_colorspace_get_named(name); - if (colorspace->is_data) + if (colorspace && colorspace->is_data) ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; else ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA; @@ -1086,7 +1086,7 @@ void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name) ibuf->float_colorspace = colorspace; - if (colorspace->is_data) + if (colorspace && colorspace->is_data) ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; else ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA; @@ -1098,7 +1098,7 @@ void IMB_colormanagement_assign_rect_colorspace(ImBuf *ibuf, const char *name) ibuf->rect_colorspace = colorspace; - if (colorspace->is_data) + if (colorspace && colorspace->is_data) ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; else ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA; From 7f5603607cb47407e8f6d36cabe3930f27aceb2f Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Thu, 4 Oct 2012 08:56:37 +0000 Subject: [PATCH 059/143] * Trunk is open again, BCon 1. --- source/blender/blenkernel/BKE_blender.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index a7bf491c382..080eb7bc541 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -53,7 +53,7 @@ extern "C" { /* can be left blank, otherwise a,b,c... etc with no quotes */ #define BLENDER_VERSION_CHAR /* alpha/beta/rc/release, docs use this */ -#define BLENDER_VERSION_CYCLE release +#define BLENDER_VERSION_CYCLE alpha extern char versionstr[]; /* from blender.c */ From f609d0f22e57c2ac0d0e0bc0dd04dbb862d72933 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 4 Oct 2012 09:12:08 +0000 Subject: [PATCH 060/143] code cleanup: remove USE_BMESH_FORWARD_COMPAT - this was added to load bmesh in pre-bmesh blender version, remove MODSTACK_DEBUG, was never used. --- source/blender/blenloader/intern/readfile.c | 29 ------------------- .../blender/makesdna/DNA_customdata_types.h | 2 -- source/blender/makesdna/DNA_defs.h | 3 -- source/blender/makesdna/DNA_mesh_types.h | 2 -- source/blender/makesdna/DNA_modifier_types.h | 3 -- 5 files changed, 39 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index aa44b01544f..9fe1d6ca00f 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3841,35 +3841,6 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) direct_link_customdata(fd, &mesh->ldata, mesh->totloop); direct_link_customdata(fd, &mesh->pdata, mesh->totpoly); - -#ifdef USE_BMESH_FORWARD_COMPAT - /* NEVER ENABLE THIS CODE INTO BMESH! - * THIS IS FOR LOADING BMESH INTO OLDER FILES ONLY */ - mesh->mpoly = newdataadr(fd, mesh->mpoly); - mesh->mloop = newdataadr(fd, mesh->mloop); - - direct_link_customdata(fd, &mesh->pdata, mesh->totpoly); - direct_link_customdata(fd, &mesh->ldata, mesh->totloop); - - if (mesh->mpoly) { - /* be clever and load polygons as mfaces */ - mesh->totface= BKE_mesh_mpoly_to_mface(&mesh->fdata, &mesh->ldata, &mesh->pdata, - mesh->totface, mesh->totloop, mesh->totpoly); - - CustomData_free(&mesh->pdata, mesh->totpoly); - memset(&mesh->pdata, 0, sizeof(CustomData)); - mesh->totpoly = 0; - - CustomData_free(&mesh->ldata, mesh->totloop); - memset(&mesh->ldata, 0, sizeof(CustomData)); - mesh->totloop = 0; - - mesh_update_customdata_pointers(mesh); - } - -#endif - - mesh->bb = NULL; mesh->edit_btmesh = NULL; diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index c22de3cb7eb..9d40af92638 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -36,8 +36,6 @@ extern "C" { #endif -#include "DNA_defs.h" /* USE_BMESH_FORWARD_COMPAT */ - /** descriptor and storage for a custom data layer */ typedef struct CustomDataLayer { int type; /* type of data in layer */ diff --git a/source/blender/makesdna/DNA_defs.h b/source/blender/makesdna/DNA_defs.h index 762e027f934..774fbcf081a 100644 --- a/source/blender/makesdna/DNA_defs.h +++ b/source/blender/makesdna/DNA_defs.h @@ -45,9 +45,6 @@ /* hrmf, we need a better include then this */ #include "../blenloader/BLO_sys_types.h" /* needed for int64_t only! */ -/* Must not be defined for BMesh, as this guards code for pre-BMesh code to load BMesh .blend files */ -/* #define USE_BMESH_FORWARD_COMPAT */ - /* non-id name variables should use this length */ #define MAX_NAME 64 diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index c7f90eea176..dd0845dbf1e 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -37,8 +37,6 @@ #include "DNA_ID.h" #include "DNA_customdata_types.h" -#include "DNA_defs.h" /* USE_BMESH_FORWARD_COMPAT */ - struct AnimData; struct DerivedMesh; struct Ipo; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index b40af805f77..99df51e9ec4 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -28,9 +28,6 @@ #include "DNA_defs.h" #include "DNA_listBase.h" - -#define MODSTACK_DEBUG 1 - /* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE! * (ONLY ADD NEW ITEMS AT THE END) */ From e2bf6eacb37cbc1ac44ae04d0f4a704556930151 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 4 Oct 2012 09:20:58 +0000 Subject: [PATCH 061/143] use GCC's -Wpadded on DNA files, gives more useful warnings then makesdna. --- source/blender/makesdna/DNA_curve_types.h | 2 +- source/blender/makesdna/intern/makesdna.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 284694f2b48..9fbe045226e 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -74,7 +74,7 @@ typedef struct Path { typedef struct BevList { struct BevList *next, *prev; int nr, dupe_nr; - short poly, hole; + int poly, hole; } BevList; /* These two Lines with # tell makesdna this struct can be excluded. */ diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index fec3aa22e92..88c5ea3e910 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -1187,6 +1187,13 @@ int main(int argc, char **argv) } /* include files for automatic dependencies */ + +/* extra safety check that we are aligned, + * warnings here are easier to fix the makesdna's */ +#ifdef __GNUC__ +# pragma GCC diagnostic error "-Wpadded" +#endif + #include "DNA_listBase.h" #include "DNA_vec_types.h" #include "DNA_ID.h" From 753b627cb6fb92ec1b168c6ea6270eb5115911b7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 4 Oct 2012 09:33:14 +0000 Subject: [PATCH 062/143] avoid a sqrtf call in ui_hsvcircle_vals_from_pos() for values outside the circle. --- .../editors/interface/interface_intern.h | 3 ++- .../editors/interface/interface_widgets.c | 27 +++++++------------ 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index b48c9bcab7e..e345296b69f 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -365,7 +365,8 @@ extern void ui_set_but_hsv(uiBut *but); extern void ui_get_but_vectorf(uiBut *but, float vec[3]); extern void ui_set_but_vectorf(uiBut *but, const float vec[3]); -extern void ui_hsvcircle_vals_from_pos(float *valrad, float *valdist, rcti *rect, float mx, float my); +extern void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect, + const float mx, const float my); extern void ui_get_but_string(uiBut *but, char *str, size_t maxlen); extern void ui_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 87a7d1957c5..6f819bd0491 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1889,27 +1889,18 @@ static void ui_hsv_cursor(float x, float y) } -void ui_hsvcircle_vals_from_pos(float *valrad, float *valdist, rcti *rect, float mx, float my) +void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect, + const float mx, const float my) { /* duplication of code... well, simple is better now */ - float centx = BLI_rcti_cent_x_fl(rect); - float centy = BLI_rcti_cent_y_fl(rect); - float radius, dist; - - if (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect)) - radius = (float)BLI_rcti_size_y(rect) / 2; - else - radius = (float)BLI_rcti_size_x(rect) / 2; + const float centx = BLI_rcti_cent_x_fl(rect); + const float centy = BLI_rcti_cent_y_fl(rect); + const float radius = (float)mini(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f; + const float m_delta[2] = {mx - centx, my - centy}; + const float dist_squared = len_squared_v2(m_delta); - mx -= centx; - my -= centy; - dist = sqrt(mx * mx + my * my); - if (dist < radius) - *valdist = dist / radius; - else - *valdist = 1.0f; - - *valrad = atan2f(mx, my) / (2.0f * (float)M_PI) + 0.5f; + *val_dist = (dist_squared < (radius * radius)) ? sqrtf(dist_squared) / radius : 1.0f; + *val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f; } static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, rcti *rect) From c872ffd94f1b94f8da725080e53d2e5400cb3a04 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 4 Oct 2012 09:43:27 +0000 Subject: [PATCH 063/143] code cleanup: make the behavior of set_current_material_texture() clearer and remove redundant NULL check there. also small changes to ui_draw_but_HSVCIRCLE(). --- source/blender/blenkernel/intern/texture.c | 18 +++++++------- .../editors/interface/interface_widgets.c | 24 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index bdd9b424f3b..9dd83181521 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -1073,19 +1073,21 @@ void set_current_material_texture(Material *ma, Tex *newtex) { Tex *tex = NULL; bNode *node; - - if (ma && ma->use_nodes && ma->nodetree) { - node = nodeGetActiveID(ma->nodetree, ID_TE); - if (node) { - tex = (Tex *)node->id; - id_us_min(&tex->id); + if ((ma->use_nodes && ma->nodetree) && + (node = nodeGetActiveID(ma->nodetree, ID_TE))) + { + tex = (Tex *)node->id; + id_us_min(&tex->id); + if (newtex) { node->id = &newtex->id; id_us_plus(&newtex->id); - ma = NULL; + } + else { + node->id = NULL; } } - if (ma) { + else { int act = (int)ma->texact; tex = (ma->mtex[act]) ? ma->mtex[act]->tex : NULL; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 6f819bd0491..aa74ee8e49a 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1903,27 +1903,25 @@ void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rec *val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f; } -static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, rcti *rect) +static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *rect) { + const int tot = 32; + const float radstep = 2.0f * (float)M_PI / (float)tot; + + const float centx = BLI_rcti_cent_x_fl(rect); + const float centy = BLI_rcti_cent_y_fl(rect); + float radius = (float)mini(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f; + /* gouraud triangle fan */ - float radstep, ang = 0.0f; - float centx, centy, radius, cursor_radius; + float ang = 0.0f; + float cursor_radius; float rgb[3], hsvo[3], hsv[3], col[3], colcent[3]; - int a, tot = 32; + int a; int color_profile = but->block->color_profile; if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) color_profile = FALSE; - radstep = 2.0f * (float)M_PI / (float)tot; - centx = BLI_rcti_cent_x_fl(rect); - centy = BLI_rcti_cent_y_fl(rect); - - if (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect)) - radius = (float)BLI_rcti_size_y(rect) / 2; - else - radius = (float)BLI_rcti_size_x(rect) / 2; - /* color */ ui_get_but_vectorf(but, rgb); /* copy_v3_v3(hsv, ui_block_hsv_get(but->block)); */ /* UNUSED */ From c8bd3b7cf89258f2dba1bc073c8f09e0ee7574ea Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 4 Oct 2012 09:55:10 +0000 Subject: [PATCH 064/143] fix for using hsv uninitialized in ui_draw_but_HSVCIRCLE() --- source/blender/editors/interface/interface_widgets.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index aa74ee8e49a..06d47156598 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1913,6 +1913,7 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti * float radius = (float)mini(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f; /* gouraud triangle fan */ + const float *hsv_ptr = ui_block_hsv_get(but->block); float ang = 0.0f; float cursor_radius; float rgb[3], hsvo[3], hsv[3], col[3], colcent[3]; @@ -1924,7 +1925,11 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti * /* color */ ui_get_but_vectorf(but, rgb); - /* copy_v3_v3(hsv, ui_block_hsv_get(but->block)); */ /* UNUSED */ + + /* since we use compat functions on both 'hsv' and 'hsvo', they need to be initialized */ + hsvo[0] = hsv[0] = hsv_ptr[0]; + hsvo[1] = hsv[1] = hsv_ptr[1]; + hsvo[2] = hsv[2] = hsv_ptr[2]; rgb_to_hsv_compat_v(rgb, hsvo); From a273d45a5dbe75fd312897632717cd707dd2c017 Mon Sep 17 00:00:00 2001 From: Jens Verwiebe Date: Thu, 4 Oct 2012 10:48:17 +0000 Subject: [PATCH 065/143] OSX/cmake: fix warning: -Wuninitialized is not supported without -O, in debug-mode --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a91b5a3bdac..313ea23c71f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1646,8 +1646,8 @@ elseif(APPLE) set(EXETYPE MACOSX_BUNDLE) - set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g") - set(CMAKE_CXX_FLAGS_DEBUG "-fno-strict-aliasing -g") + set(CMAKE_C_FLAGS_DEBUG "-O0 -fno-strict-aliasing -g") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-strict-aliasing -g") if(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" OR CMAKE_OSX_ARCHITECTURES MATCHES "i386") set(CMAKE_CXX_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3") set(CMAKE_C_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3") From d2833d9f0f1daa25f359e034b10bb4234c68a47d Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 4 Oct 2012 10:58:03 +0000 Subject: [PATCH 066/143] Added convenience operator to clear animation (i.e. all keyframes = F-Curves) from selected objects and bones --- release/scripts/startup/bl_ui/space_view3d.py | 3 +- .../blender/editors/animation/anim_intern.h | 2 + source/blender/editors/animation/anim_ops.c | 1 + source/blender/editors/animation/keyframing.c | 112 +++++++++++++++--- 4 files changed, 99 insertions(+), 19 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 1786c19ebdf..a77c5818fca 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -807,7 +807,8 @@ class VIEW3D_MT_object_animation(Menu): layout = self.layout layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...") - layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframe...") + layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframes...") + layout.operator("anim.keyframe_clear_v3d", text="Clear Keyframes...") layout.operator("anim.keying_set_active_set", text="Change Keying Set...") layout.separator() diff --git a/source/blender/editors/animation/anim_intern.h b/source/blender/editors/animation/anim_intern.h index cf84eb04b10..bc07bf091de 100644 --- a/source/blender/editors/animation/anim_intern.h +++ b/source/blender/editors/animation/anim_intern.h @@ -50,7 +50,9 @@ void ANIM_OT_keyframe_delete(struct wmOperatorType *ot); * required for each space. */ void ANIM_OT_keyframe_insert_menu(struct wmOperatorType *ot); + void ANIM_OT_keyframe_delete_v3d(struct wmOperatorType *ot); +void ANIM_OT_keyframe_clear_v3d(struct wmOperatorType *ot); /* Keyframe managment operators for UI buttons (RMB menu). */ void ANIM_OT_keyframe_insert_button(struct wmOperatorType *ot); diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index e24a4d49a05..f2711ec3bb5 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -290,6 +290,7 @@ void ED_operatortypes_anim(void) WM_operatortype_append(ANIM_OT_keyframe_delete); WM_operatortype_append(ANIM_OT_keyframe_insert_menu); WM_operatortype_append(ANIM_OT_keyframe_delete_v3d); + WM_operatortype_append(ANIM_OT_keyframe_clear_v3d); WM_operatortype_append(ANIM_OT_keyframe_insert_button); WM_operatortype_append(ANIM_OT_keyframe_delete_button); WM_operatortype_append(ANIM_OT_keyframe_clear_button); diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 1791d84d90b..a8aba82fb03 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1440,46 +1440,122 @@ void ANIM_OT_keyframe_delete(wmOperatorType *ot) } /* Delete Key Operator ------------------------ */ - -/* XXX WARNING: - * This is currently just a basic operator, which work in 3d-view context on objects only. - * Should this be kept? It does have advantages over a version which requires selecting a keyingset to use... - * -- Joshua Leung, Jan 2009 +/* NOTE: Although this version is simpler than the more generic version for KeyingSets, + * it is more useful for animators working in the 3D view. */ -static int delete_key_v3d_exec(bContext *C, wmOperator *op) +static int clear_anim_v3d_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap - // XXX more comprehensive tests will be needed CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - ID *id = (ID *)ob; - FCurve *fcu, *fcn; - short success = 0; - - /* loop through all curves in animdata and delete keys on this frame */ + /* just those in active action... */ if ((ob->adt) && (ob->adt->action)) { AnimData *adt = ob->adt; bAction *act = adt->action; + FCurve *fcu, *fcn; for (fcu = act->curves.first; fcu; fcu = fcn) { + short can_delete = FALSE; + fcn = fcu->next; - success += delete_keyframe(op->reports, id, NULL, NULL, fcu->rna_path, fcu->array_index, cfra, 0); + + /* in pose mode, only delete the F-Curve if it belongs to a selected bone */ + if (ob->mode & OB_MODE_POSE) { + if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones[")) { + bPoseChannel *pchan; + char *bone_name; + + /* get bone-name, and check if this bone is selected */ + bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + if (bone_name) MEM_freeN(bone_name); + + /* delete if bone is selected*/ + if ((pchan) && (pchan->bone)) { + if (pchan->bone->flag & BONE_SELECTED) + can_delete = TRUE; + } + } + } + else { + /* object mode - all of Object's F-Curves are affected */ + can_delete = TRUE; + } + + /* delete F-Curve completely */ + if (can_delete) { + ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); + } } } - BKE_reportf(op->reports, RPT_INFO, "Ob '%s' - Successfully had %d keyframes removed", id->name + 2, success); - + /* update... */ ob->recalc |= OB_RECALC_OB; } CTX_DATA_END; /* send updates */ DAG_ids_flush_update(bmain, 0); + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); + return OPERATOR_FINISHED; +} + +void ANIM_OT_keyframe_clear_v3d(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Animation"; + ot->description = "Remove all keyframe animation for selected objects"; + ot->idname = "ANIM_OT_keyframe_clear_v3d"; + + /* callbacks */ + ot->invoke = WM_operator_confirm; + ot->exec = clear_anim_v3d_exec; + + ot->poll = ED_operator_areaactive; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +static int delete_key_v3d_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + float cfra = (float)CFRA; + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + { + ID *id = &ob->id; + size_t success = 0; + + /* just those in active action... */ + if ((ob->adt) && (ob->adt->action)) { + AnimData *adt = ob->adt; + bAction *act = adt->action; + FCurve *fcu, *fcn; + + for (fcu = act->curves.first; fcu; fcu = fcn) { + fcn = fcu->next; + + /* delete keyframes on current frame + * WARNING: this can delete the next F-Curve, hence the "fcn" copying + */ + success += delete_keyframe(op->reports, id, NULL, NULL, fcu->rna_path, fcu->array_index, cfra, 0); + } + } + + /* report success (or failure) */ + BKE_reportf(op->reports, RPT_INFO, "Object '%s' successfully had %u keyframes removed", id->name + 2, success); + ob->recalc |= OB_RECALC_OB; + } + CTX_DATA_END; + + /* send updates */ + DAG_ids_flush_update(bmain, 0); WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); return OPERATOR_FINISHED; @@ -1489,7 +1565,7 @@ void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot) { /* identifiers */ ot->name = "Delete Keyframe"; - ot->description = "Remove keyframes on current frame for selected object"; + ot->description = "Remove keyframes on current frame for selected objects"; ot->idname = "ANIM_OT_keyframe_delete_v3d"; /* callbacks */ From b8231620a52092a1c5cb89e87f70931eee559070 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 4 Oct 2012 11:05:48 +0000 Subject: [PATCH 067/143] Bugfix [#32754] Clear Motion paths button not available on Motion paths panel On second thought, perhaps it is more convenient/natural if this was shown in both places, given that many people may only find the motion paths options through the UI now. --- release/scripts/startup/bl_ui/properties_animviz.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_animviz.py b/release/scripts/startup/bl_ui/properties_animviz.py index 2d15c534e9f..8308c7fc425 100644 --- a/release/scripts/startup/bl_ui/properties_animviz.py +++ b/release/scripts/startup/bl_ui/properties_animviz.py @@ -65,10 +65,13 @@ class MotionPathButtonsPanel(): sub.prop(mpath, "frame_start", text="From") sub.prop(mpath, "frame_end", text="To") + sub = col.row(align=True) if bones: - col.operator("pose.paths_update", text="Update Paths", icon='BONE_DATA') + sub.operator("pose.paths_update", text="Update Paths", icon='BONE_DATA') + sub.operator("pose.paths_clear", text="", icon='X') else: - col.operator("object.paths_update", text="Update Paths", icon='OBJECT_DATA') + sub.operator("object.paths_update", text="Update Paths", icon='OBJECT_DATA') + sub.operator("object.paths_clear", text="", icon='X') else: sub = col.column(align=True) sub.label(text="Nothing to show yet...", icon='ERROR') From ae3c28481b9f25a55186d5b4ef361f1e78a9886f Mon Sep 17 00:00:00 2001 From: Jens Verwiebe Date: Thu, 4 Oct 2012 11:26:02 +0000 Subject: [PATCH 068/143] OSX/cmake: fix warning: second try --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 313ea23c71f..8370044cc2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1646,8 +1646,8 @@ elseif(APPLE) set(EXETYPE MACOSX_BUNDLE) - set(CMAKE_C_FLAGS_DEBUG "-O0 -fno-strict-aliasing -g") - set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-strict-aliasing -g") + set(CMAKE_C_FLAGS_DEBUG "-O0 -fno-strict-aliasing -g" CACHE STRING "" FORCE) + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-strict-aliasing -g"CACHE STRING "" FORCE) if(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" OR CMAKE_OSX_ARCHITECTURES MATCHES "i386") set(CMAKE_CXX_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3") set(CMAKE_C_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3") From 7be70c746c8ca9635699acdec987dc98803ddd21 Mon Sep 17 00:00:00 2001 From: Jens Verwiebe Date: Thu, 4 Oct 2012 11:37:17 +0000 Subject: [PATCH 069/143] OSX/cmake: fix warning: go back to initial state, not the right way to get rid of this --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8370044cc2a..a91b5a3bdac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1646,8 +1646,8 @@ elseif(APPLE) set(EXETYPE MACOSX_BUNDLE) - set(CMAKE_C_FLAGS_DEBUG "-O0 -fno-strict-aliasing -g" CACHE STRING "" FORCE) - set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-strict-aliasing -g"CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g") + set(CMAKE_CXX_FLAGS_DEBUG "-fno-strict-aliasing -g") if(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" OR CMAKE_OSX_ARCHITECTURES MATCHES "i386") set(CMAKE_CXX_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3") set(CMAKE_C_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3") From bdb95acac8757978630a67a187b9ad02d455fb56 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 4 Oct 2012 11:39:30 +0000 Subject: [PATCH 070/143] code cleanup: comment verse outliner views, also correct warning in recent commit. --- source/blender/editors/animation/keyframing.c | 11 +++++------ source/blender/makesdna/DNA_space_types.h | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index a8aba82fb03..fc2647a51f4 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1186,10 +1186,9 @@ static int modify_key_op_poll(bContext *C) /* if Outliner, don't allow in some views */ if (so) { - if (ELEM4(so->outlinevis, SO_GROUPS, SO_LIBRARIES, SO_VERSE_SESSION, SO_VERSE_SESSION)) - return 0; - if (ELEM3(so->outlinevis, SO_SEQUENCE, SO_USERDEF, SO_KEYMAP)) + if (ELEM5(so->outlinevis, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_USERDEF, SO_KEYMAP)) { return 0; + } } /* TODO: checks for other space types can be added here */ @@ -1444,7 +1443,7 @@ void ANIM_OT_keyframe_delete(wmOperatorType *ot) * it is more useful for animators working in the 3D view. */ -static int clear_anim_v3d_exec(bContext *C, wmOperator *op) +static int clear_anim_v3d_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); @@ -1530,7 +1529,7 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { ID *id = &ob->id; - size_t success = 0; + int success = 0; /* just those in active action... */ if ((ob->adt) && (ob->adt->action)) { @@ -1549,7 +1548,7 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op) } /* report success (or failure) */ - BKE_reportf(op->reports, RPT_INFO, "Object '%s' successfully had %u keyframes removed", id->name + 2, success); + BKE_reportf(op->reports, RPT_INFO, "Object '%s' successfully had %d keyframes removed", id->name + 2, success); ob->recalc |= OB_RECALC_OB; } CTX_DATA_END; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index a1534c7b9d3..4b8fc9c7ed6 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -264,8 +264,8 @@ typedef enum eSpaceOutliner_Mode { SO_SAME_TYPE = 5, SO_GROUPS = 6, SO_LIBRARIES = 7, - SO_VERSE_SESSION = 8, - SO_VERSE_MS = 9, + /* SO_VERSE_SESSION = 8, */ /* deprecated! */ + /* SO_VERSE_MS = 9, */ /* deprecated!*/ SO_SEQUENCE = 10, SO_DATABLOCKS = 11, SO_USERDEF = 12, From d8144ef0f57bfba6973b7de34fe8238ab88707cc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 4 Oct 2012 13:26:15 +0000 Subject: [PATCH 071/143] style cleanup: comment blocks --- doc/manpage/blender.1 | 4 +- source/blender/blenkernel/intern/colortools.c | 6 +- source/blender/blenkernel/intern/ipo.c | 4 +- source/blender/blenkernel/intern/object.c | 2 +- source/blender/blenkernel/intern/seqeffects.c | 6 +- source/blender/blenkernel/intern/sequencer.c | 8 +- source/blender/blenloader/intern/readfile.c | 2 +- source/blender/blenloader/intern/writefile.c | 80 +++++++++---------- source/blender/collada/DocumentImporter.cpp | 6 +- source/blender/collada/DocumentImporter.h | 5 +- source/blender/collada/GeometryExporter.cpp | 4 +- .../operations/COM_TrackPositionOperation.h | 8 +- source/blender/editors/mesh/editmesh_knife.c | 4 +- source/blender/editors/mesh/editmesh_tools.c | 4 +- .../editors/space_view3d/view3d_edit.c | 4 +- source/blender/imbuf/intern/indexer.c | 6 +- source/blender/makesrna/intern/rna_nodetree.c | 4 +- .../blender/makesrna/intern/rna_sequencer.c | 4 +- .../nodes/composite/node_composite_tree.c | 6 +- .../blender/render/intern/source/occlusion.c | 10 +-- 20 files changed, 89 insertions(+), 88 deletions(-) diff --git a/doc/manpage/blender.1 b/doc/manpage/blender.1 index c7a762f08c7..e7164fcb96b 100644 --- a/doc/manpage/blender.1 +++ b/doc/manpage/blender.1 @@ -1,4 +1,4 @@ -.TH "BLENDER" "1" "July 19, 2012" "Blender Blender 2\&.63 (sub 14)" +.TH "BLENDER" "1" "October 04, 2012" "Blender Blender 2\&.64 (sub 0)" .SH NAME blender \- a 3D modelling and rendering package @@ -15,7 +15,7 @@ Use Blender to create TV commercials, to make technical visualizations, business http://www.blender.org .SH OPTIONS -Blender 2.63 (sub 14) +Blender 2.64 (sub 0) Usage: blender [args ...] [file] [args ...] .br .SS "Render Options:" diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index b66bd1fd32b..1bd5786debd 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -1289,9 +1289,9 @@ void BKE_color_managed_display_settings_copy(ColorManagedDisplaySettings *new_se void BKE_color_managed_view_settings_init(ColorManagedViewSettings *settings) { /* OCIO_TODO: use default view transform here when OCIO is completely integrated - * and proper versioning stuff is added. - * for now use NONE to be compatible with all current files - */ + * and proper versioning stuff is added. + * for now use NONE to be compatible with all current files + */ BLI_strncpy(settings->view_transform, "Default", sizeof(settings->view_transform)); settings->gamma = 1.0f; diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 953ee673f6b..5216aefab58 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1757,13 +1757,13 @@ void do_versions_ipos_to_animato(Main *main) { /* If we have any empty action actuators, assume they were - converted IPO Actuators using the object IPO */ + * converted IPO Actuators using the object IPO */ bActuator *act; bActionActuator *aa; for (act = ob->actuators.first; act; act = act->next) { /* Any actuators set to ACT_IPO at this point are actually Action Actuators that - need this converted IPO to finish converting the actuator. */ + * need this converted IPO to finish converting the actuator. */ if (act->type == ACT_IPO) { aa = (bActionActuator *)act->data; aa->act = ob->adt->action; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index ab261e79dfc..72a43da94b6 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2261,7 +2261,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const short u Curve *cu = ob->data; /* Use the object bounding box so that modifier output - gets taken into account */ + * gets taken into account */ if (ob->bb) bb = *(ob->bb); else { diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index eaf3ec384c8..33519483843 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -609,9 +609,9 @@ static void makeGammaTables(float gamma) /* The end of the table should match 1.0 carefully. In order to avoid * rounding errors, we just set this explicitly. The last segment may - * have a different length than the other segments, but our - * interpolation is insensitive to that - */ + * have a different length than the other segments, but our + * interpolation is insensitive to that + */ color_domain_table[RE_GAMMA_TABLE_SIZE] = 1.0; gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0; inv_gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index bb845400cef..37f32a12111 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -3959,10 +3959,10 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad sound = sound_new_file(bmain, seq_load->path); /* handles relative paths */ if (sound == NULL || sound->playback_handle == NULL) { - /* +#if 0 if (op) BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); - */ +#endif return NULL; } @@ -3971,10 +3971,10 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad if (info.specs.channels == AUD_CHANNELS_INVALID) { sound_delete(bmain, sound); - /* +#if 0 if (op) BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); - */ +#endif return NULL; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9fe1d6ca00f..9aa7da3ca6e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -206,7 +206,7 @@ * - join all Mains * - link all LibBlocks and indirect pointers to libblocks * - initialize FileGlobal and copy pointers to Global -*/ + */ /* also occurs in library.c */ /* GS reads the memory pointed at in a specific ordering. There are, diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index b8d63b3c5d5..536376ac577 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -30,46 +30,46 @@ /* -FILEFORMAT: IFF-style structure (but not IFF compatible!) - -start file: - BLENDER_V100 12 bytes (versie 1.00) - V = big endian, v = little endian - _ = 4 byte pointer, - = 8 byte pointer - -datablocks: also see struct BHead - 4 chars - int, len data after BHead - void, old pointer - int - int, in case of array: amount of structs - data - ... - ... - -Almost all data in Blender are structures. Each struct saved -gets a BHead header. With BHead the struct can be linked again -and compared with StructDNA . - -WRITE - -Preferred writing order: (not really a must, but why would you do it random?) -Any case: direct data is ALWAYS after the lib block - -(Local file data) -- for each LibBlock - - write LibBlock - - write associated direct data -(External file data) -- per library - - write library block - - per LibBlock - - write the ID of LibBlock -- write TEST (128x128, blend file preview, optional) -- write FileGlobal (some global vars) -- write SDNA -- write USER if filename is ~/X.XX/config/startup.blend -*/ + * FILEFORMAT: IFF-style structure (but not IFF compatible!) + * + * start file: + * BLENDER_V100 12 bytes (versie 1.00) + * V = big endian, v = little endian + * _ = 4 byte pointer, - = 8 byte pointer + * + * datablocks: also see struct BHead + * 4 chars + * int, len data after BHead + * void, old pointer + * int + * int, in case of array: amount of structs + * data + * ... + * ... + * + * Almost all data in Blender are structures. Each struct saved + * gets a BHead header. With BHead the struct can be linked again + * and compared with StructDNA . + * + * WRITE + * + * Preferred writing order: (not really a must, but why would you do it random?) + * Any case: direct data is ALWAYS after the lib block + * + * (Local file data) + * - for each LibBlock + * - write LibBlock + * - write associated direct data + * (External file data) + * - per library + * - write library block + * - per LibBlock + * - write the ID of LibBlock + * - write TEST (128x128, blend file preview, optional) + * - write FileGlobal (some global vars) + * - write SDNA + * - write USER if filename is ~/X.XX/config/startup.blend + */ #include diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 4d4f26561e3..f37f065b03b 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -88,8 +88,8 @@ extern "C" { /* - COLLADA Importer limitations: - - no multiple scene import, all objects are added to active scene + * COLLADA Importer limitations: + * - no multiple scene import, all objects are added to active scene */ // #define COLLADA_DEBUG @@ -878,7 +878,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera) } break; /* XXX correct way to do following four is probably to get also render - size and determine proper settings from that somehow */ + * size and determine proper settings from that somehow */ case COLLADAFW::Camera::ASPECTRATIO_AND_X: case COLLADAFW::Camera::SINGLE_X: case COLLADAFW::Camera::X_AND_Y: diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h index 13f23b23388..e878a5a5b48 100644 --- a/source/blender/collada/DocumentImporter.h +++ b/source/blender/collada/DocumentImporter.h @@ -78,8 +78,9 @@ public: void write_profile_COMMON(COLLADAFW::EffectCommon*, Material*); void translate_anim_recursive(COLLADAFW::Node*, COLLADAFW::Node*, Object*); - /** This method will be called if an error in the loading process occurred and the loader cannot - continue to load. The writer should undo all operations that have been performed. + /** + * This method will be called if an error in the loading process occurred and the loader cannot + * continue to load. The writer should undo all operations that have been performed. \param errorMessage A message containing informations about the error that occurred. */ void cancel(const COLLADAFW::String& errorMessage); diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp index 27700444ba9..e2332b7cd55 100644 --- a/source/blender/collada/GeometryExporter.cpp +++ b/source/blender/collada/GeometryExporter.cpp @@ -358,8 +358,8 @@ void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me) param.push_back("X"); param.push_back("Y"); param.push_back("Z"); - /*main function, it creates , */ + /* main function, it creates , */ source.prepareToAppendValues(); //appends data to int i = 0; diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.h b/source/blender/compositor/operations/COM_TrackPositionOperation.h index 3a9e6f25cd9..b934719a92b 100644 --- a/source/blender/compositor/operations/COM_TrackPositionOperation.h +++ b/source/blender/compositor/operations/COM_TrackPositionOperation.h @@ -35,8 +35,8 @@ #include "BLI_listbase.h" /** - * Class with implementation of green screen gradient rasterization - */ + * Class with implementation of green screen gradient rasterization + */ class TrackPositionOperation : public NodeOperation { protected: enum { @@ -58,8 +58,8 @@ protected: float m_relativePos[2]; /** - * Determine the output resolution. The resolution is retrieved from the Renderer - */ + * Determine the output resolution. The resolution is retrieved from the Renderer + */ void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); public: diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 790fd0a7cf1..1ddb210398e 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -446,8 +446,8 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float } else { /* kfe cuts across an existing face. - If v1 and v2 are in multiple faces together (e.g., if they - are in doubled polys) then this arbitrarily chooses one of them */ + * If v1 and v2 are in multiple faces together (e.g., if they + * are in doubled polys) then this arbitrarily chooses one of them */ f = knife_find_common_face(&kfe->v1->faces, &kfe->v2->faces); if (f) knife_append_list(kcd, &newkfe->v2->faces, f); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index a76d09827f0..48ffb352247 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -2140,7 +2140,7 @@ static int edbm_select_vertex_path_exec(bContext *C, wmOperator *op) } /* if those are not found, because vertices where selected by e.g. - border or circle select, find two selected vertices */ + * border or circle select, find two selected vertices */ if (svert == NULL) { BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) @@ -2150,7 +2150,7 @@ static int edbm_select_vertex_path_exec(bContext *C, wmOperator *op) else if (evert == NULL) evert = eve; else { /* more than two vertices are selected, - show warning message and cancel operator */ + * show warning message and cancel operator */ svert = evert = NULL; break; } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 744ce6f6209..d3ff64c9f40 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -1235,8 +1235,8 @@ void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot) /* -* this is basically just the pan only code + the rotate only code crammed into one function that does both -*/ + * this is basically just the pan only code + the rotate only code crammed into one function that does both + */ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event) { if (event->type != NDOF_MOTION) diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 97316c48621..f35a4345366 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -955,9 +955,9 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context, } /* process pictures still stuck in decoder engine after EOF - according to ffmpeg docs using 0-size packets. - - At least, if we haven't already stopped... */ + * according to ffmpeg docs using 0-size packets. + * + * At least, if we haven't already stopped... */ if (!*stop) { int frame_finished; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index af3a8691e08..b03d348b49d 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -2195,14 +2195,14 @@ static void def_cmp_inpaint(StructRNA *srna) { PropertyRNA *prop; -/* +#if 0 prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Type", "Type of inpaint algorithm"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); -*/ +#endif prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index d83debd3266..432e3841ad8 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1673,14 +1673,14 @@ static void rna_def_effect_inputs(StructRNA *srna, int count) RNA_def_property_ui_text(prop, "Input 2", "Second input for the effect strip"); } - /* +#if 0 if (count == 3) { // not used by any effects (perhaps one day plugins?) prop = RNA_def_property(srna, "input_3", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "seq3"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL); RNA_def_property_ui_text(prop, "Input 3", "Third input for the effect strip"); } - */ +#endif } static void rna_def_image(BlenderRNA *brna) diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c index 68bafd94ce4..0d86ada8026 100644 --- a/source/blender/nodes/composite/node_composite_tree.c +++ b/source/blender/nodes/composite/node_composite_tree.c @@ -515,9 +515,9 @@ static int setExecutableNodes(bNodeTreeExec *exec, ThreadData *thd) static void freeExecutableNode(bNodeTreeExec *exec) { /* node outputs can be freed when: - - not a render result or image node - - when node outputs go to nodes all being set NODE_FINISHED - */ + * - not a render result or image node + * - when node outputs go to nodes all being set NODE_FINISHED + */ bNodeTree *ntree = exec->nodetree; bNodeExec *nodeexec; bNode *node; diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index c8aad21b322..af774c5be73 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -232,9 +232,9 @@ static void occ_build_shade(Render *re, OcclusionTree *tree) /* ------------------------- Spherical Harmonics --------------------------- */ /* Use 2nd order SH => 9 coefficients, stored in this order: -* 0 = (0,0), -* 1 = (1,-1), 2 = (1,0), 3 = (1,1), -* 4 = (2,-2), 5 = (2,-1), 6 = (2,0), 7 = (2,1), 8 = (2,2) */ + * 0 = (0,0), + * 1 = (1,-1), 2 = (1,0), 3 = (1,1), + * 4 = (2,-2), 5 = (2,-1), 6 = (2,0), 7 = (2,1), 8 = (2,2) */ static void sh_copy(float *shresult, float *sh) { @@ -1056,8 +1056,8 @@ static float occ_quad_form_factor(float *p, float *n, float *q0, float *q1, floa static __m128 sse_approx_acos(__m128 x) { /* needs a better approximation than taylor expansion of acos, since that - * gives big erros for near 1.0 values, sqrt(2*x)*acos(1-x) should work - * better, see http://www.tom.womack.net/projects/sse-fast-arctrig.html */ + * gives big erros for near 1.0 values, sqrt(2*x)*acos(1-x) should work + * better, see http://www.tom.womack.net/projects/sse-fast-arctrig.html */ return _mm_set_ps1(1.0f); } From ef107d1a4d75ffc5645505867efec6b39b114d50 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 4 Oct 2012 13:39:08 +0000 Subject: [PATCH 072/143] Color Management: fallback to stub ocio implementation in cases when ocio configuration file failed to load This solves issues with infinite NULL-checks to prevent crashes in such situations. Currently only happens if there's no configuration file at all, but could be tweaked further to fallback if this file isn't usable by blender. --- intern/opencolorio/CMakeLists.txt | 31 +- intern/opencolorio/SConscript | 10 +- .../{ocio_capi_stub.cpp => fallback_impl.cc} | 126 ++++---- intern/opencolorio/ocio_capi.cc | 286 ++++++++++++++++++ intern/opencolorio/ocio_capi.h | 9 +- .../{ocio_capi.cpp => ocio_impl.cc} | 103 +++---- intern/opencolorio/ocio_impl.h | 240 +++++++++++++++ source/blender/imbuf/intern/colormanagement.c | 56 ++-- 8 files changed, 676 insertions(+), 185 deletions(-) rename intern/opencolorio/{ocio_capi_stub.cpp => fallback_impl.cc} (55%) create mode 100644 intern/opencolorio/ocio_capi.cc rename intern/opencolorio/{ocio_capi.cpp => ocio_impl.cc} (67%) create mode 100644 intern/opencolorio/ocio_impl.h diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt index 9f5d4cd332c..fb74d5e3f4e 100644 --- a/intern/opencolorio/CMakeLists.txt +++ b/intern/opencolorio/CMakeLists.txt @@ -26,41 +26,40 @@ set(INC . ../guardedalloc + ../../source/blender/blenlib ) set(INC_SYS ) +set(SRC + ocio_capi.cc + fallback_impl.cc + + ocio_capi.h + ocio_impl.h +) if(WITH_OPENCOLORIO) + add_definitions( + -DWITH_OCIO + ) list(APPEND INC_SYS ${OPENCOLORIO_INCLUDE_DIRS} ) + list(APPEND SRC + ocio_impl.cc + ) + if(WIN32 AND NOT MINGW) list(APPEND INC_SYS ${BOOST_INCLUDE_DIR} ) endif() - - set(SRC - ocio_capi.cpp - ocio_capi.h - ) -else() - list(APPEND INC - ../../source/blender/blenlib - ) - - set(SRC - ocio_capi_stub.cpp - ocio_capi.h - ) endif() -add_definitions( -) blender_add_lib(bf_intern_opencolorio "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/opencolorio/SConscript b/intern/opencolorio/SConscript index fec07662735..229087a568d 100644 --- a/intern/opencolorio/SConscript +++ b/intern/opencolorio/SConscript @@ -2,18 +2,18 @@ Import('env') -sources = env.Glob('*.cpp') +sources = env.Glob('*.cc') incs = '. ../guardedalloc ../../source/blender/blenlib' +defs = [] if env['WITH_BF_OCIO']: - sources.remove('ocio_capi_stub.cpp') - incs += ' ' + env['BF_OCIO_INC'] + defs.append('WITH_OCIO') if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): incs += ' ' + env['BF_BOOST_INC'] else: - sources.remove('ocio_capi.cpp') + sources.remove('ocio_capi.cc') -env.BlenderLib( 'bf_intern_opencolorio', sources, Split(incs), [], libtype=['extern','player'], priority=[10, 185]) +env.BlenderLib( 'bf_intern_opencolorio', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185]) diff --git a/intern/opencolorio/ocio_capi_stub.cpp b/intern/opencolorio/fallback_impl.cc similarity index 55% rename from intern/opencolorio/ocio_capi_stub.cpp rename to intern/opencolorio/fallback_impl.cc index 2112b88ad72..4badcc54ebd 100644 --- a/intern/opencolorio/ocio_capi_stub.cpp +++ b/intern/opencolorio/fallback_impl.cc @@ -30,7 +30,7 @@ namespace OCIO_NAMESPACE {}; -#include "ocio_capi.h" +#include "ocio_impl.h" #define CONFIG_DEFAULT ((ConstConfigRcPtr*)1) @@ -51,40 +51,35 @@ typedef struct PackedImageDescription { long yStrideBytes; } PackedImageDescription; -ConstConfigRcPtr *OCIO_getCurrentConfig(void) +ConstConfigRcPtr *FallbackImpl::getCurrentConfig(void) { return CONFIG_DEFAULT; } -ConstConfigRcPtr *OCIO_getDefaultConfig(void) +void FallbackImpl::setCurrentConfig(const ConstConfigRcPtr *) +{ +} + +ConstConfigRcPtr *FallbackImpl::configCreateFromEnv(void) { return CONFIG_DEFAULT; } -void OCIO_setCurrentConfig(const ConstConfigRcPtr *) -{ -} - -ConstConfigRcPtr *OCIO_configCreateFromEnv(void) +ConstConfigRcPtr *FallbackImpl::configCreateFromFile(const char *) { return CONFIG_DEFAULT; } -ConstConfigRcPtr *OCIO_configCreateFromFile(const char *) -{ - return CONFIG_DEFAULT; -} - -void OCIO_configRelease(ConstConfigRcPtr *) +void FallbackImpl::configRelease(ConstConfigRcPtr *) { } -int OCIO_configGetNumColorSpaces(ConstConfigRcPtr *) +int FallbackImpl::configGetNumColorSpaces(ConstConfigRcPtr *) { return 2; } -const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *, int index) +const char *FallbackImpl::configGetColorSpaceNameByIndex(ConstConfigRcPtr *, int index) { if (index == 0) return "Linear"; @@ -94,7 +89,7 @@ const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *, int index) return NULL; } -ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *, const char *name) +ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(ConstConfigRcPtr *, const char *name) { if (strcmp(name, "scene_linear") == 0) return COLORSPACE_LINEAR; @@ -116,9 +111,9 @@ ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *, const char *n return NULL; } -int OCIO_configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) +int FallbackImpl::configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) { - ConstColorSpaceRcPtr *cs = OCIO_configGetColorSpace(config, name); + ConstColorSpaceRcPtr *cs = configGetColorSpace(config, name); if (cs == COLORSPACE_LINEAR) return 0; @@ -128,17 +123,17 @@ int OCIO_configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) return -1; } -const char *OCIO_configGetDefaultDisplay(ConstConfigRcPtr *) +const char *FallbackImpl::configGetDefaultDisplay(ConstConfigRcPtr *) { return "sRGB"; } -int OCIO_configGetNumDisplays(ConstConfigRcPtr* config) +int FallbackImpl::configGetNumDisplays(ConstConfigRcPtr* config) { return 1; } -const char *OCIO_configGetDisplay(ConstConfigRcPtr *, int index) +const char *FallbackImpl::configGetDisplay(ConstConfigRcPtr *, int index) { if (index == 0) return "sRGB"; @@ -146,17 +141,17 @@ const char *OCIO_configGetDisplay(ConstConfigRcPtr *, int index) return NULL; } -const char *OCIO_configGetDefaultView(ConstConfigRcPtr *, const char *) +const char *FallbackImpl::configGetDefaultView(ConstConfigRcPtr *, const char *) { return "Default"; } -int OCIO_configGetNumViews(ConstConfigRcPtr *, const char *) +int FallbackImpl::configGetNumViews(ConstConfigRcPtr *, const char *) { return 1; } -const char *OCIO_configGetView(ConstConfigRcPtr *, const char *, int index) +const char *FallbackImpl::configGetView(ConstConfigRcPtr *, const char *, int index) { if (index == 0) return "Default"; @@ -164,29 +159,29 @@ const char *OCIO_configGetView(ConstConfigRcPtr *, const char *, int index) return NULL; } -const char *OCIO_configGetDisplayColorSpaceName(ConstConfigRcPtr *, const char *, const char *) +const char *FallbackImpl::configGetDisplayColorSpaceName(ConstConfigRcPtr *, const char *, const char *) { return "sRGB"; } -int OCIO_colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) +int FallbackImpl::colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) { return 1; } -int OCIO_colorSpaceIsData(ConstColorSpaceRcPtr *cs) +int FallbackImpl::colorSpaceIsData(ConstColorSpaceRcPtr *cs) { return 0; } -void OCIO_colorSpaceRelease(ConstColorSpaceRcPtr *cs) +void FallbackImpl::colorSpaceRelease(ConstColorSpaceRcPtr *cs) { } -ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName) +ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName) { - ConstColorSpaceRcPtr *cs_src = OCIO_configGetColorSpace(config, srcName); - ConstColorSpaceRcPtr *cs_dst = OCIO_configGetColorSpace(config, dstName); + ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName); + ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName); if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) return PROCESSOR_LINEAR_TO_SRGB; @@ -196,12 +191,12 @@ ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, return 0; } -ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *, ConstTransformRcPtr *tfm) +ConstProcessorRcPtr *FallbackImpl::configGetProcessor(ConstConfigRcPtr *, ConstTransformRcPtr *tfm) { return (ConstProcessorRcPtr*)tfm; } -void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) +void FallbackImpl::processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) { /* OCIO_TODO stride not respected, channels must be 3 or 4 */ PackedImageDescription *desc = (PackedImageDescription*)img; @@ -216,14 +211,14 @@ void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) float *pixel = pixels + channels * (y * width + x); if (channels == 4) - OCIO_processorApplyRGBA(processor, pixel); + processorApplyRGBA(processor, pixel); else if (channels == 3) - OCIO_processorApplyRGB(processor, pixel); + processorApplyRGB(processor, pixel); } } } -void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img) +void FallbackImpl::processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img) { /* OCIO_TODO stride not respected, channels must be 3 or 4 */ PackedImageDescription *desc = (PackedImageDescription*)img; @@ -238,14 +233,14 @@ void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDe float *pixel = pixels + channels * (y * width + x); if (channels == 4) - OCIO_processorApplyRGBA_predivide(processor, pixel); + processorApplyRGBA_predivide(processor, pixel); else if (channels == 3) - OCIO_processorApplyRGB(processor, pixel); + processorApplyRGB(processor, pixel); } } } -void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) +void FallbackImpl::processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) { if (processor == PROCESSOR_LINEAR_TO_SRGB) linearrgb_to_srgb_v3_v3(pixel, pixel); @@ -253,7 +248,7 @@ void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) srgb_to_linearrgb_v3_v3(pixel, pixel); } -void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) +void FallbackImpl::processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) { if (processor == PROCESSOR_LINEAR_TO_SRGB) linearrgb_to_srgb_v4(pixel, pixel); @@ -261,10 +256,10 @@ void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) srgb_to_linearrgb_v4(pixel, pixel); } -void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel) +void FallbackImpl::processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel) { if (pixel[3] == 1.0f || pixel[3] == 0.0f) { - OCIO_processorApplyRGBA(processor, pixel); + processorApplyRGBA(processor, pixel); } else { float alpha, inv_alpha; @@ -276,7 +271,7 @@ void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pi pixel[1] *= inv_alpha; pixel[2] *= inv_alpha; - OCIO_processorApplyRGBA(processor, pixel); + processorApplyRGBA(processor, pixel); pixel[0] *= alpha; pixel[1] *= alpha; @@ -284,11 +279,11 @@ void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pi } } -void OCIO_processorRelease(ConstProcessorRcPtr *) +void FallbackImpl::processorRelease(ConstProcessorRcPtr *) { } -const char *OCIO_colorSpaceGetName(ConstColorSpaceRcPtr *cs) +const char *FallbackImpl::colorSpaceGetName(ConstColorSpaceRcPtr *cs) { if (cs == COLORSPACE_LINEAR) return "Linear"; @@ -298,47 +293,47 @@ const char *OCIO_colorSpaceGetName(ConstColorSpaceRcPtr *cs) return NULL; } -const char *OCIO_colorSpaceGetDescription(ConstColorSpaceRcPtr *) +const char *FallbackImpl::colorSpaceGetDescription(ConstColorSpaceRcPtr *) { return ""; } -const char *OCIO_colorSpaceGetFamily(ConstColorSpaceRcPtr *) +const char *FallbackImpl::colorSpaceGetFamily(ConstColorSpaceRcPtr *) { return ""; } -DisplayTransformRcPtr *OCIO_createDisplayTransform(void) +DisplayTransformRcPtr *FallbackImpl::createDisplayTransform(void) { return (DisplayTransformRcPtr*)PROCESSOR_LINEAR_TO_SRGB; } -void OCIO_displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *, const char *) +void FallbackImpl::displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *, const char *) { } -void OCIO_displayTransformSetDisplay(DisplayTransformRcPtr *, const char *) +void FallbackImpl::displayTransformSetDisplay(DisplayTransformRcPtr *, const char *) { } -void OCIO_displayTransformSetView(DisplayTransformRcPtr *, const char *) +void FallbackImpl::displayTransformSetView(DisplayTransformRcPtr *, const char *) { } -void OCIO_displayTransformSetDisplayCC(DisplayTransformRcPtr *, ConstTransformRcPtr *) +void FallbackImpl::displayTransformSetDisplayCC(DisplayTransformRcPtr *, ConstTransformRcPtr *) { } -void OCIO_displayTransformSetLinearCC(DisplayTransformRcPtr *, ConstTransformRcPtr *) +void FallbackImpl::displayTransformSetLinearCC(DisplayTransformRcPtr *, ConstTransformRcPtr *) { } -void OCIO_displayTransformRelease(DisplayTransformRcPtr *) +void FallbackImpl::displayTransformRelease(DisplayTransformRcPtr *) { } -PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height, long numChannels, - long chanStrideBytes, long xStrideBytes, long yStrideBytes) +PackedImageDesc *FallbackImpl::createPackedImageDesc(float *data, long width, long height, long numChannels, + long chanStrideBytes, long xStrideBytes, long yStrideBytes) { PackedImageDescription *desc = (PackedImageDescription*)MEM_callocN(sizeof(PackedImageDescription), "PackedImageDescription"); @@ -353,38 +348,37 @@ PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height return (PackedImageDesc*)desc; } -void OCIO_packedImageDescRelease(PackedImageDesc* id) +void FallbackImpl::packedImageDescRelease(PackedImageDesc* id) { MEM_freeN(id); } -ExponentTransformRcPtr *OCIO_createExponentTransform(void) +ExponentTransformRcPtr *FallbackImpl::createExponentTransform(void) { return (ExponentTransformRcPtr*)PROCESSOR_UNKNOWN; } -void OCIO_exponentTransformSetValue(ExponentTransformRcPtr *, const float *) +void FallbackImpl::exponentTransformSetValue(ExponentTransformRcPtr *, const float *) { } -void OCIO_exponentTransformRelease(ExponentTransformRcPtr *) +void FallbackImpl::exponentTransformRelease(ExponentTransformRcPtr *) { } -MatrixTransformRcPtr *OCIO_createMatrixTransform(void) +MatrixTransformRcPtr *FallbackImpl::createMatrixTransform(void) { return (MatrixTransformRcPtr*)PROCESSOR_UNKNOWN; } -void OCIO_matrixTransformSetValue(MatrixTransformRcPtr *, const float *, const float *) +void FallbackImpl::matrixTransformSetValue(MatrixTransformRcPtr *, const float *, const float *) { } -void OCIO_matrixTransformRelease(MatrixTransformRcPtr *) +void FallbackImpl::matrixTransformRelease(MatrixTransformRcPtr *) { } -void OCIO_matrixTransformScale(float * , float * , const float *) +void FallbackImpl::matrixTransformScale(float * , float * , const float *) { } - diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc new file mode 100644 index 00000000000..20e7cc23daa --- /dev/null +++ b/intern/opencolorio/ocio_capi.cc @@ -0,0 +1,286 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2012 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +namespace OCIO_NAMESPACE {}; + +#include "ocio_impl.h" + +static IOCIOImpl *impl = NULL; + +void OCIO_init(void) +{ +#ifdef WITH_OCIO + impl = new OCIOImpl(); +#else + impl = new FallbackImpl(); +#endif +} + +void OCIO_exit(void) +{ + delete impl; + impl = NULL; +} + +ConstConfigRcPtr *OCIO_getCurrentConfig(void) +{ + return impl->getCurrentConfig(); +} + +ConstConfigRcPtr *OCIO_configCreateFallback(void) +{ + delete impl; + impl = new FallbackImpl(); + + return impl->getCurrentConfig(); +} + +void OCIO_setCurrentConfig(const ConstConfigRcPtr *config) +{ + impl->setCurrentConfig(config); +} + +ConstConfigRcPtr *OCIO_configCreateFromEnv(void) +{ + return impl->configCreateFromEnv(); +} + +ConstConfigRcPtr *OCIO_configCreateFromFile(const char *filename) +{ + return impl->configCreateFromFile(filename); +} + +void OCIO_configRelease(ConstConfigRcPtr *config) +{ + impl->configRelease(config); +} + +int OCIO_configGetNumColorSpaces(ConstConfigRcPtr *config) +{ + return impl->configGetNumColorSpaces(config); +} + +const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index) +{ + return impl->configGetColorSpaceNameByIndex(config, index); +} + +ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *config, const char *name) +{ + return impl->configGetColorSpace(config, name); +} + +int OCIO_configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) +{ + return impl->configGetIndexForColorSpace(config, name); +} + +const char *OCIO_configGetDefaultDisplay(ConstConfigRcPtr *config) +{ + return impl->configGetDefaultDisplay(config); +} + +int OCIO_configGetNumDisplays(ConstConfigRcPtr* config) +{ + return impl->configGetNumDisplays(config); +} + +const char *OCIO_configGetDisplay(ConstConfigRcPtr *config, int index) +{ + return impl->configGetDisplay(config, index); +} + +const char *OCIO_configGetDefaultView(ConstConfigRcPtr *config, const char *display) +{ + return impl->configGetDefaultView(config, display); +} + +int OCIO_configGetNumViews(ConstConfigRcPtr *config, const char *display) +{ + return impl->configGetNumViews(config, display); +} + +const char *OCIO_configGetView(ConstConfigRcPtr *config, const char *display, int index) +{ + return impl->configGetView(config, display, index); +} + +const char *OCIO_configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view) +{ + return impl->configGetDisplayColorSpaceName(config, display, view); +} + +int OCIO_colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) +{ + return impl->colorSpaceIsInvertible(cs); +} + +int OCIO_colorSpaceIsData(ConstColorSpaceRcPtr *cs) +{ + return impl->colorSpaceIsData(cs); +} + +void OCIO_colorSpaceRelease(ConstColorSpaceRcPtr *cs) +{ + impl->colorSpaceRelease(cs); +} + +ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName) +{ + return impl->configGetProcessorWithNames(config, srcName, dstName); +} + +ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform) +{ + return impl->configGetProcessor(config, transform); +} + +void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) +{ + impl->processorApply(processor, img); +} + +void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img) +{ + impl->processorApply_predivide(processor, img); +} + +void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) +{ + impl->processorApplyRGB(processor, pixel); +} + +void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) +{ + impl->processorApplyRGBA(processor, pixel); +} + +void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel) +{ + impl->processorApplyRGBA_predivide(processor, pixel); +} + +void OCIO_processorRelease(ConstProcessorRcPtr *p) +{ + impl->processorRelease(p); +} + +const char *OCIO_colorSpaceGetName(ConstColorSpaceRcPtr *cs) +{ + return impl->colorSpaceGetName(cs); +} + +const char *OCIO_colorSpaceGetDescription(ConstColorSpaceRcPtr *cs) +{ + return impl->colorSpaceGetDescription(cs); +} + +const char *OCIO_colorSpaceGetFamily(ConstColorSpaceRcPtr *cs) +{ + return impl->colorSpaceGetFamily(cs); +} + +DisplayTransformRcPtr *OCIO_createDisplayTransform(void) +{ + return impl->createDisplayTransform(); +} + +void OCIO_displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name) +{ + impl->displayTransformSetInputColorSpaceName(dt, name); +} + +void OCIO_displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name) +{ + impl->displayTransformSetDisplay(dt, name); +} + +void OCIO_displayTransformSetView(DisplayTransformRcPtr *dt, const char *name) +{ + impl->displayTransformSetView(dt, name); +} + +void OCIO_displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t) +{ + impl->displayTransformSetDisplayCC(dt, t); +} + +void OCIO_displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t) +{ + impl->displayTransformSetLinearCC(dt, t); +} + +void OCIO_displayTransformRelease(DisplayTransformRcPtr *dt) +{ + impl->displayTransformRelease(dt); +} + +PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height, long numChannels, + long chanStrideBytes, long xStrideBytes, long yStrideBytes) +{ + return impl->createPackedImageDesc(data, width, height, numChannels, chanStrideBytes, xStrideBytes, yStrideBytes); +} + +void OCIO_packedImageDescRelease(PackedImageDesc* id) +{ + impl->packedImageDescRelease(id); +} + +ExponentTransformRcPtr *OCIO_createExponentTransform(void) +{ + return impl->createExponentTransform(); +} + +void OCIO_exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent) +{ + impl->exponentTransformSetValue(et, exponent); +} + +void OCIO_exponentTransformRelease(ExponentTransformRcPtr *et) +{ + impl->exponentTransformRelease(et); +} + +MatrixTransformRcPtr *OCIO_createMatrixTransform(void) +{ + return impl->createMatrixTransform(); +} + +void OCIO_matrixTransformSetValue(MatrixTransformRcPtr *mt, const float *m44, const float *offset4) +{ + impl->matrixTransformSetValue(mt, m44, offset4); +} + +void OCIO_matrixTransformRelease(MatrixTransformRcPtr *mt) +{ + impl->matrixTransformRelease(mt); +} + +void OCIO_matrixTransformScale(float * m44, float * offset4, const float *scale4f) +{ + impl->matrixTransformScale(m44, offset4, scale4f); +} diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h index 0218ccfafcd..f924bffb8e0 100644 --- a/intern/opencolorio/ocio_capi.h +++ b/intern/opencolorio/ocio_capi.h @@ -28,8 +28,6 @@ #ifndef __OCIO_CAPI_H__ #define __OCIO_CAPI_H__ - - #ifdef __cplusplus using namespace OCIO_NAMESPACE; extern "C" { @@ -37,7 +35,6 @@ extern "C" { #define OCIO_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name - #ifndef OCIO_CAPI_IMPLEMENTATION #define OCIO_ROLE_SCENE_LINEAR "scene_linear" #define OCIO_ROLE_COLOR_PICKING "color_picking" @@ -57,13 +54,15 @@ extern "C" { OCIO_DECLARE_HANDLE(MatrixTransformRcPtr); #endif +void OCIO_init(void); +void OCIO_exit(void); ConstConfigRcPtr *OCIO_getCurrentConfig(void); -ConstConfigRcPtr *OCIO_getDefaultConfig(void); void OCIO_setCurrentConfig(const ConstConfigRcPtr *config); ConstConfigRcPtr *OCIO_configCreateFromEnv(void); ConstConfigRcPtr *OCIO_configCreateFromFile(const char* filename); +ConstConfigRcPtr *OCIO_configCreateFallback(void); void OCIO_configRelease(ConstConfigRcPtr *config); @@ -127,4 +126,4 @@ void OCIO_matrixTransformScale(float * m44, float * offset4, const float * scale } #endif -#endif //OCIO_CAPI_H +#endif /* OCIO_CAPI_H */ diff --git a/intern/opencolorio/ocio_capi.cpp b/intern/opencolorio/ocio_impl.cc similarity index 67% rename from intern/opencolorio/ocio_capi.cpp rename to intern/opencolorio/ocio_impl.cc index 152b537ab9b..5d5c66cd356 100644 --- a/intern/opencolorio/ocio_capi.cpp +++ b/intern/opencolorio/ocio_impl.cc @@ -33,7 +33,7 @@ #include "MEM_guardedalloc.h" #define OCIO_CAPI_IMPLEMENTATION -#include "ocio_capi.h" +#include "ocio_impl.h" #if !defined(WITH_ASSERT_ABORT) # define OCIO_abort() @@ -61,7 +61,7 @@ static void OCIO_reportException(Exception &exception) OCIO_reportError(exception.what()); } -ConstConfigRcPtr *OCIO_getCurrentConfig(void) +ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void) { ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr); @@ -80,12 +80,7 @@ ConstConfigRcPtr *OCIO_getCurrentConfig(void) return NULL; } -ConstConfigRcPtr *OCIO_getDefaultConfig(void) -{ - return NULL; -} - -void OCIO_setCurrentConfig(const ConstConfigRcPtr *config) +void OCIOImpl::setCurrentConfig(const ConstConfigRcPtr *config) { try { SetCurrentConfig(*config); @@ -95,7 +90,7 @@ void OCIO_setCurrentConfig(const ConstConfigRcPtr *config) } } -ConstConfigRcPtr *OCIO_configCreateFromEnv(void) +ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void) { ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr); @@ -115,7 +110,7 @@ ConstConfigRcPtr *OCIO_configCreateFromEnv(void) } -ConstConfigRcPtr *OCIO_configCreateFromFile(const char *filename) +ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename) { ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr); @@ -134,12 +129,12 @@ ConstConfigRcPtr *OCIO_configCreateFromFile(const char *filename) return NULL; } -void OCIO_configRelease(ConstConfigRcPtr *config) +void OCIOImpl::configRelease(ConstConfigRcPtr *config) { MEM_DELETE(config, ConstConfigRcPtr); } -int OCIO_configGetNumColorSpaces(ConstConfigRcPtr *config) +int OCIOImpl::configGetNumColorSpaces(ConstConfigRcPtr *config) { try { return (*config)->getNumColorSpaces(); @@ -151,7 +146,7 @@ int OCIO_configGetNumColorSpaces(ConstConfigRcPtr *config) return 0; } -const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index) +const char *OCIOImpl::configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index) { try { return (*config)->getColorSpaceNameByIndex(index); @@ -163,7 +158,7 @@ const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int in return NULL; } -ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *config, const char *name) +ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(ConstConfigRcPtr *config, const char *name) { ConstColorSpaceRcPtr *cs = MEM_NEW(ConstColorSpaceRcPtr); @@ -182,7 +177,7 @@ ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *config, const c return NULL; } -int OCIO_configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) +int OCIOImpl::configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) { try { return (*config)->getIndexForColorSpace(name); @@ -194,7 +189,7 @@ int OCIO_configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) return -1; } -const char *OCIO_configGetDefaultDisplay(ConstConfigRcPtr *config) +const char *OCIOImpl::configGetDefaultDisplay(ConstConfigRcPtr *config) { try { return (*config)->getDefaultDisplay(); @@ -206,7 +201,7 @@ const char *OCIO_configGetDefaultDisplay(ConstConfigRcPtr *config) return NULL; } -int OCIO_configGetNumDisplays(ConstConfigRcPtr* config) +int OCIOImpl::configGetNumDisplays(ConstConfigRcPtr* config) { try { return (*config)->getNumDisplays(); @@ -218,7 +213,7 @@ int OCIO_configGetNumDisplays(ConstConfigRcPtr* config) return 0; } -const char *OCIO_configGetDisplay(ConstConfigRcPtr *config, int index) +const char *OCIOImpl::configGetDisplay(ConstConfigRcPtr *config, int index) { try { return (*config)->getDisplay(index); @@ -230,7 +225,7 @@ const char *OCIO_configGetDisplay(ConstConfigRcPtr *config, int index) return NULL; } -const char *OCIO_configGetDefaultView(ConstConfigRcPtr *config, const char *display) +const char *OCIOImpl::configGetDefaultView(ConstConfigRcPtr *config, const char *display) { try { return (*config)->getDefaultView(display); @@ -242,7 +237,7 @@ const char *OCIO_configGetDefaultView(ConstConfigRcPtr *config, const char *disp return NULL; } -int OCIO_configGetNumViews(ConstConfigRcPtr *config, const char *display) +int OCIOImpl::configGetNumViews(ConstConfigRcPtr *config, const char *display) { try { return (*config)->getNumViews(display); @@ -254,7 +249,7 @@ int OCIO_configGetNumViews(ConstConfigRcPtr *config, const char *display) return 0; } -const char *OCIO_configGetView(ConstConfigRcPtr *config, const char *display, int index) +const char *OCIOImpl::configGetView(ConstConfigRcPtr *config, const char *display, int index) { try { return (*config)->getView(display, index); @@ -266,7 +261,7 @@ const char *OCIO_configGetView(ConstConfigRcPtr *config, const char *display, in return NULL; } -const char *OCIO_configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view) +const char *OCIOImpl::configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view) { try { return (*config)->getDisplayColorSpaceName(display, view); @@ -278,7 +273,7 @@ const char *OCIO_configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const return NULL; } -int OCIO_colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) +int OCIOImpl::colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) { const char *family = (*cs)->getFamily(); @@ -302,17 +297,17 @@ int OCIO_colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) return true; } -int OCIO_colorSpaceIsData(ConstColorSpaceRcPtr *cs) +int OCIOImpl::colorSpaceIsData(ConstColorSpaceRcPtr *cs) { return ((*cs)->isData()); } -void OCIO_colorSpaceRelease(ConstColorSpaceRcPtr *cs) +void OCIOImpl::colorSpaceRelease(ConstColorSpaceRcPtr *cs) { MEM_DELETE(cs, ConstColorSpaceRcPtr); } -ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName) +ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName) { ConstProcessorRcPtr *p = MEM_NEW(ConstProcessorRcPtr); @@ -331,7 +326,7 @@ ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, return 0; } -ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform) +ConstProcessorRcPtr *OCIOImpl::configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform) { ConstProcessorRcPtr *p = MEM_NEW(ConstProcessorRcPtr); @@ -350,7 +345,7 @@ ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *config, ConstTran return NULL; } -void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) +void OCIOImpl::processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) { try { (*processor)->apply(*img); @@ -360,7 +355,7 @@ void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) } } -void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img) +void OCIOImpl::processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img) { try { int channels = img->getNumChannels(); @@ -375,7 +370,7 @@ void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDe for (int x = 0; x < width; x++) { float *pixel = pixels + 4 * (y * width + x); - OCIO_processorApplyRGBA_predivide(processor, pixel); + processorApplyRGBA_predivide(processor, pixel); } } } @@ -388,17 +383,17 @@ void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDe } } -void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) +void OCIOImpl::processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) { (*processor)->applyRGB(pixel); } -void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) +void OCIOImpl::processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) { (*processor)->applyRGBA(pixel); } -void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel) +void OCIOImpl::processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel) { if (pixel[3] == 1.0f || pixel[3] == 0.0f) { (*processor)->applyRGBA(pixel); @@ -421,28 +416,28 @@ void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pi } } -void OCIO_processorRelease(ConstProcessorRcPtr *p) +void OCIOImpl::processorRelease(ConstProcessorRcPtr *p) { p->~ConstProcessorRcPtr(); MEM_freeN(p); } -const char *OCIO_colorSpaceGetName(ConstColorSpaceRcPtr *cs) +const char *OCIOImpl::colorSpaceGetName(ConstColorSpaceRcPtr *cs) { return (*cs)->getName(); } -const char *OCIO_colorSpaceGetDescription(ConstColorSpaceRcPtr *cs) +const char *OCIOImpl::colorSpaceGetDescription(ConstColorSpaceRcPtr *cs) { return (*cs)->getDescription(); } -const char *OCIO_colorSpaceGetFamily(ConstColorSpaceRcPtr *cs) +const char *OCIOImpl::colorSpaceGetFamily(ConstColorSpaceRcPtr *cs) { return (*cs)->getFamily(); } -DisplayTransformRcPtr *OCIO_createDisplayTransform(void) +DisplayTransformRcPtr *OCIOImpl::createDisplayTransform(void) { DisplayTransformRcPtr *dt = MEM_NEW(DisplayTransformRcPtr); @@ -451,38 +446,38 @@ DisplayTransformRcPtr *OCIO_createDisplayTransform(void) return dt; } -void OCIO_displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name) +void OCIOImpl::displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name) { (*dt)->setInputColorSpaceName(name); } -void OCIO_displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name) +void OCIOImpl::displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name) { (*dt)->setDisplay(name); } -void OCIO_displayTransformSetView(DisplayTransformRcPtr *dt, const char *name) +void OCIOImpl::displayTransformSetView(DisplayTransformRcPtr *dt, const char *name) { (*dt)->setView(name); } -void OCIO_displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t) +void OCIOImpl::displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t) { (*dt)->setDisplayCC(*t); } -void OCIO_displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t) +void OCIOImpl::displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t) { (*dt)->setLinearCC(*t); } -void OCIO_displayTransformRelease(DisplayTransformRcPtr *dt) +void OCIOImpl::displayTransformRelease(DisplayTransformRcPtr *dt) { MEM_DELETE(dt, DisplayTransformRcPtr); } -PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height, long numChannels, - long chanStrideBytes, long xStrideBytes, long yStrideBytes) +PackedImageDesc *OCIOImpl::createPackedImageDesc(float *data, long width, long height, long numChannels, + long chanStrideBytes, long xStrideBytes, long yStrideBytes) { try { void *mem = MEM_mallocN(sizeof(PackedImageDesc), __func__); @@ -497,12 +492,12 @@ PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height return NULL; } -void OCIO_packedImageDescRelease(PackedImageDesc* id) +void OCIOImpl::packedImageDescRelease(PackedImageDesc* id) { MEM_DELETE(id, PackedImageDesc); } -ExponentTransformRcPtr *OCIO_createExponentTransform(void) +ExponentTransformRcPtr *OCIOImpl::createExponentTransform(void) { ExponentTransformRcPtr *et = MEM_NEW(ExponentTransformRcPtr); @@ -511,17 +506,17 @@ ExponentTransformRcPtr *OCIO_createExponentTransform(void) return et; } -void OCIO_exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent) +void OCIOImpl::exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent) { (*et)->setValue(exponent); } -void OCIO_exponentTransformRelease(ExponentTransformRcPtr *et) +void OCIOImpl::exponentTransformRelease(ExponentTransformRcPtr *et) { MEM_DELETE(et, ExponentTransformRcPtr); } -MatrixTransformRcPtr *OCIO_createMatrixTransform(void) +MatrixTransformRcPtr *OCIOImpl::createMatrixTransform(void) { MatrixTransformRcPtr *mt = MEM_NEW(MatrixTransformRcPtr); @@ -530,17 +525,17 @@ MatrixTransformRcPtr *OCIO_createMatrixTransform(void) return mt; } -void OCIO_matrixTransformSetValue(MatrixTransformRcPtr *mt, const float *m44, const float *offset4) +void OCIOImpl::matrixTransformSetValue(MatrixTransformRcPtr *mt, const float *m44, const float *offset4) { (*mt)->setValue(m44, offset4); } -void OCIO_matrixTransformRelease(MatrixTransformRcPtr *mt) +void OCIOImpl::matrixTransformRelease(MatrixTransformRcPtr *mt) { MEM_DELETE(mt, MatrixTransformRcPtr); } -void OCIO_matrixTransformScale(float * m44, float * offset4, const float *scale4f) +void OCIOImpl::matrixTransformScale(float * m44, float * offset4, const float *scale4f) { MatrixTransform::Scale(m44, offset4, scale4f); } diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h new file mode 100644 index 00000000000..e05b35648b9 --- /dev/null +++ b/intern/opencolorio/ocio_impl.h @@ -0,0 +1,240 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2012 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __OCIO_IMPL_H__ +#define __OCIO_IMPL_H__ + +#include "ocio_capi.h" + +class IOCIOImpl { +public: + virtual ~IOCIOImpl() {}; + + virtual ConstConfigRcPtr *getCurrentConfig(void) = 0; + virtual void setCurrentConfig(const ConstConfigRcPtr *config) = 0; + + virtual ConstConfigRcPtr *configCreateFromEnv(void) = 0; + virtual ConstConfigRcPtr *configCreateFromFile(const char* filename) = 0; + + virtual void configRelease(ConstConfigRcPtr *config) = 0; + + virtual int configGetNumColorSpaces(ConstConfigRcPtr *config) = 0; + virtual const char *configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index) = 0; + virtual ConstColorSpaceRcPtr *configGetColorSpace(ConstConfigRcPtr *config, const char *name) = 0; + virtual int configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) = 0; + + virtual int colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) = 0; + virtual int colorSpaceIsData(ConstColorSpaceRcPtr *cs) = 0; + + virtual void colorSpaceRelease(ConstColorSpaceRcPtr *cs) = 0; + + virtual const char *configGetDefaultDisplay(ConstConfigRcPtr *config) = 0; + virtual int configGetNumDisplays(ConstConfigRcPtr *config) = 0; + virtual const char *configGetDisplay(ConstConfigRcPtr *config, int index) = 0; + virtual const char *configGetDefaultView(ConstConfigRcPtr *config, const char *display) = 0; + virtual int configGetNumViews(ConstConfigRcPtr *config, const char *display) = 0; + virtual const char *configGetView(ConstConfigRcPtr *config, const char *display, int index) = 0; + virtual const char *configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view) = 0; + + virtual ConstProcessorRcPtr *configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName) = 0; + virtual ConstProcessorRcPtr *configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform) = 0; + + virtual void processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) = 0; + virtual void processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img) = 0; + virtual void processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) = 0; + virtual void processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) = 0; + virtual void processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel) = 0; + + virtual void processorRelease(ConstProcessorRcPtr *p) = 0; + + virtual const char *colorSpaceGetName(ConstColorSpaceRcPtr *cs) = 0; + virtual const char *colorSpaceGetDescription(ConstColorSpaceRcPtr *cs) = 0; + virtual const char *colorSpaceGetFamily(ConstColorSpaceRcPtr *cs) = 0; + + virtual DisplayTransformRcPtr *createDisplayTransform(void) = 0; + virtual void displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name) = 0; + virtual void displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name) = 0; + virtual void displayTransformSetView(DisplayTransformRcPtr *dt, const char *name) = 0; + virtual void displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et) = 0; + virtual void displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et) = 0; + virtual void displayTransformRelease(DisplayTransformRcPtr *dt) = 0; + + virtual PackedImageDesc *createPackedImageDesc(float *data, long width, long height, long numChannels, + long chanStrideBytes, long xStrideBytes, long yStrideBytes) = 0; + + virtual void packedImageDescRelease(PackedImageDesc *p) = 0; + + virtual ExponentTransformRcPtr *createExponentTransform(void) = 0; + virtual void exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent) = 0; + virtual void exponentTransformRelease(ExponentTransformRcPtr *et) = 0; + + virtual MatrixTransformRcPtr *createMatrixTransform(void) = 0; + virtual void matrixTransformSetValue(MatrixTransformRcPtr *et, const float *m44, const float *offset4) = 0; + virtual void matrixTransformRelease(MatrixTransformRcPtr *mt) = 0; + + virtual void matrixTransformScale(float * m44, float * offset4, const float * scale4) = 0; +}; + +class FallbackImpl : public IOCIOImpl { +public: + FallbackImpl() {}; + + ConstConfigRcPtr *getCurrentConfig(void); + void setCurrentConfig(const ConstConfigRcPtr *config); + + ConstConfigRcPtr *configCreateFromEnv(void); + ConstConfigRcPtr *configCreateFromFile(const char* filename); + + void configRelease(ConstConfigRcPtr *config); + + int configGetNumColorSpaces(ConstConfigRcPtr *config); + const char *configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index); + ConstColorSpaceRcPtr *configGetColorSpace(ConstConfigRcPtr *config, const char *name); + int configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name); + + int colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs); + int colorSpaceIsData(ConstColorSpaceRcPtr *cs); + + void colorSpaceRelease(ConstColorSpaceRcPtr *cs); + + const char *configGetDefaultDisplay(ConstConfigRcPtr *config); + int configGetNumDisplays(ConstConfigRcPtr *config); + const char *configGetDisplay(ConstConfigRcPtr *config, int index); + const char *configGetDefaultView(ConstConfigRcPtr *config, const char *display); + int configGetNumViews(ConstConfigRcPtr *config, const char *display); + const char *configGetView(ConstConfigRcPtr *config, const char *display, int index); + const char *configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view); + + ConstProcessorRcPtr *configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName); + ConstProcessorRcPtr *configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform); + + void processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img); + void processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img); + void processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel); + void processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel); + void processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel); + + void processorRelease(ConstProcessorRcPtr *p); + + const char *colorSpaceGetName(ConstColorSpaceRcPtr *cs); + const char *colorSpaceGetDescription(ConstColorSpaceRcPtr *cs); + const char *colorSpaceGetFamily(ConstColorSpaceRcPtr *cs); + + DisplayTransformRcPtr *createDisplayTransform(void); + void displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetView(DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et); + void displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et); + void displayTransformRelease(DisplayTransformRcPtr *dt); + + PackedImageDesc *createPackedImageDesc(float *data, long width, long height, long numChannels, + long chanStrideBytes, long xStrideBytes, long yStrideBytes); + + void packedImageDescRelease(PackedImageDesc *p); + + ExponentTransformRcPtr *createExponentTransform(void); + void exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent); + void exponentTransformRelease(ExponentTransformRcPtr *et); + + MatrixTransformRcPtr *createMatrixTransform(void); + void matrixTransformSetValue(MatrixTransformRcPtr *et, const float *m44, const float *offset4); + void matrixTransformRelease(MatrixTransformRcPtr *mt); + + void matrixTransformScale(float * m44, float * offset4, const float * scale4); +}; + +#ifdef WITH_OCIO +class OCIOImpl : public IOCIOImpl { +public: + OCIOImpl() {}; + + ConstConfigRcPtr *getCurrentConfig(void); + void setCurrentConfig(const ConstConfigRcPtr *config); + + ConstConfigRcPtr *configCreateFromEnv(void); + ConstConfigRcPtr *configCreateFromFile(const char* filename); + + void configRelease(ConstConfigRcPtr *config); + + int configGetNumColorSpaces(ConstConfigRcPtr *config); + const char *configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index); + ConstColorSpaceRcPtr *configGetColorSpace(ConstConfigRcPtr *config, const char *name); + int configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name); + + int colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs); + int colorSpaceIsData(ConstColorSpaceRcPtr *cs); + + void colorSpaceRelease(ConstColorSpaceRcPtr *cs); + + const char *configGetDefaultDisplay(ConstConfigRcPtr *config); + int configGetNumDisplays(ConstConfigRcPtr *config); + const char *configGetDisplay(ConstConfigRcPtr *config, int index); + const char *configGetDefaultView(ConstConfigRcPtr *config, const char *display); + int configGetNumViews(ConstConfigRcPtr *config, const char *display); + const char *configGetView(ConstConfigRcPtr *config, const char *display, int index); + const char *configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view); + + ConstProcessorRcPtr *configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName); + ConstProcessorRcPtr *configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform); + + void processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img); + void processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img); + void processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel); + void processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel); + void processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel); + + void processorRelease(ConstProcessorRcPtr *p); + + const char *colorSpaceGetName(ConstColorSpaceRcPtr *cs); + const char *colorSpaceGetDescription(ConstColorSpaceRcPtr *cs); + const char *colorSpaceGetFamily(ConstColorSpaceRcPtr *cs); + + DisplayTransformRcPtr *createDisplayTransform(void); + void displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetView(DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et); + void displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et); + void displayTransformRelease(DisplayTransformRcPtr *dt); + + PackedImageDesc *createPackedImageDesc(float *data, long width, long height, long numChannels, + long chanStrideBytes, long xStrideBytes, long yStrideBytes); + + void packedImageDescRelease(PackedImageDesc *p); + + ExponentTransformRcPtr *createExponentTransform(void); + void exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent); + void exponentTransformRelease(ExponentTransformRcPtr *et); + + MatrixTransformRcPtr *createMatrixTransform(void); + void matrixTransformSetValue(MatrixTransformRcPtr *et, const float *m44, const float *offset4); + void matrixTransformRelease(MatrixTransformRcPtr *mt); + + void matrixTransformScale(float * m44, float * offset4, const float * scale4); +}; +#endif + +#endif /* OCIO_IMPL_H */ diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 1a86932b0a9..bb1449060dd 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -546,6 +546,8 @@ static void colormanage_free_config(void) /* free views */ BLI_freelistN(&global_views); + + OCIO_exit(); } void colormanagement_init(void) @@ -555,6 +557,8 @@ void colormanagement_init(void) char configfile[FILE_MAX]; ConstConfigRcPtr *config = NULL; + OCIO_init(); + ocio_env = getenv("OCIO"); if (ocio_env && ocio_env[0] != '\0') @@ -571,7 +575,9 @@ void colormanagement_init(void) } if (config == NULL) { - config = OCIO_getDefaultConfig(); + printf("Color management: using fallback mode for management\n"); + + config = OCIO_configCreateFallback(); } if (config) { @@ -638,19 +644,15 @@ static const char *display_transform_get_colorspace_name(const ColorManagedViewS { ConstConfigRcPtr *config = OCIO_getCurrentConfig(); - if (config) { - const char *display = display_settings->display_device; - const char *view = view_settings->view_transform; - const char *colorspace_name; + const char *display = display_settings->display_device; + const char *view = view_settings->view_transform; + const char *colorspace_name; - colorspace_name = OCIO_configGetDisplayColorSpaceName(config, display, view); + colorspace_name = OCIO_configGetDisplayColorSpaceName(config, display, view); - OCIO_configRelease(config); + OCIO_configRelease(config); - return colorspace_name; - } - - return NULL; + return colorspace_name; } static ColorSpace *display_transform_get_colorspace(const ColorManagedViewSettings *view_settings, @@ -671,12 +673,6 @@ static ConstProcessorRcPtr *create_display_buffer_processor(const char *view_tra DisplayTransformRcPtr *dt; ConstProcessorRcPtr *processor; - if (!config) { - /* there's no valid OCIO configuration, can't create processor */ - - return NULL; - } - dt = OCIO_createDisplayTransform(); /* assuming handling buffer was already converted to scene linear space */ @@ -726,12 +722,6 @@ static ConstProcessorRcPtr *create_colorspace_transform_processor(const char *fr ConstConfigRcPtr *config = OCIO_getCurrentConfig(); ConstProcessorRcPtr *processor; - if (!config) { - /* there's no valid OCIO configuration, can't create processor */ - - return NULL; - } - processor = OCIO_configGetProcessorWithNames(config, from_colorspace, to_colorspace); OCIO_configRelease(config); @@ -881,7 +871,7 @@ void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace) { ColorSpace *colorspace = colormanage_colorspace_get_named(from_colorspace); - if (colorspace && colorspace->is_data) { + if (colorspace->is_data) { ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; return; } @@ -1074,7 +1064,7 @@ void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name) { ColorSpace *colorspace = colormanage_colorspace_get_named(name); - if (colorspace && colorspace->is_data) + if (colorspace->is_data) ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; else ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA; @@ -1086,7 +1076,7 @@ void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name) ibuf->float_colorspace = colorspace; - if (colorspace && colorspace->is_data) + if (colorspace->is_data) ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; else ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA; @@ -1098,7 +1088,7 @@ void IMB_colormanagement_assign_rect_colorspace(ImBuf *ibuf, const char *name) ibuf->rect_colorspace = colorspace; - if (colorspace && colorspace->is_data) + if (colorspace->is_data) ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; else ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA; @@ -1898,12 +1888,6 @@ const char *colormanage_display_get_default_name(void) ConstConfigRcPtr *config = OCIO_getCurrentConfig(); const char *display_name; - if (!config) { - /* no valid OCIO configuration, can't get default display */ - - return NULL; - } - display_name = OCIO_configGetDefaultDisplay(config); OCIO_configRelease(config); @@ -2015,12 +1999,6 @@ const char *colormanage_view_get_default_name(const ColorManagedDisplay *display ConstConfigRcPtr *config = OCIO_getCurrentConfig(); const char *name; - if (!config) { - /* no valid OCIO configuration, can't get default view */ - - return NULL; - } - name = OCIO_configGetDefaultView(config, display->name); OCIO_configRelease(config); From 6527e8a1a85d9bfa92a27912c686b3d7ae56e739 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 4 Oct 2012 13:49:39 +0000 Subject: [PATCH 073/143] Fix for rtl processing of menu strings... --- .../modules/bl_i18n_utils/rtl_preprocess.py | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/release/scripts/modules/bl_i18n_utils/rtl_preprocess.py b/release/scripts/modules/bl_i18n_utils/rtl_preprocess.py index 5ee5c71be8b..d28f87cf042 100755 --- a/release/scripts/modules/bl_i18n_utils/rtl_preprocess.py +++ b/release/scripts/modules/bl_i18n_utils/rtl_preprocess.py @@ -34,6 +34,7 @@ import sys import ctypes +import re try: import settings @@ -87,44 +88,64 @@ FRIBIDI_FLAGS_ARABIC = FRIBIDI_FLAG_SHAPE_ARAB_PRES | \ FRIBIDI_FLAG_SHAPE_ARAB_LIGA +MENU_DETECT_REGEX = re.compile("%x\\d+\\|") + + ##### Kernel processing funcs. ##### def protect_format_seq(msg): """ Find some specific escaping/formating sequences (like \", %s, etc., and protect them from any modification! """ +# LRM = "\u200E" +# RLM = "\u200F" LRE = "\u202A" + RLE = "\u202B" PDF = "\u202C" + LRO = "\u202D" + RLO = "\u202E" + uctrl = {LRE, RLE, PDF, LRO, RLO} # Most likely incomplete, but seems to cover current needs. format_codes = set("tslfd") digits = set(".0123456789") + if not msg: + return msg + elif MENU_DETECT_REGEX.search(msg): + # An ugly "menu" message, just force it whole LRE if not yet done. + if msg[0] not in {LRE, LRO}: + msg = LRE + msg + idx = 0 ret = [] ln = len(msg) while idx < ln: dlt = 1 +# # If we find a control char, skip any additional protection! +# if msg[idx] in uctrl: +# ret.append(msg[idx:]) +# break # \" or \' if idx < (ln - 1) and msg[idx] == '\\' and msg[idx + 1] in "\"\'": dlt = 2 - # %x12 - elif idx < (ln - 2) and msg[idx] == '%' and msg[idx + 1] in "x" and \ - msg[idx + 2] in digits: + # %x12| + elif idx < (ln - 2) and msg[idx] == '%' and msg[idx + 1] in "x" and msg[idx + 2] in digits: dlt = 2 - while (idx + dlt + 1) < ln and msg[idx + dlt + 1] in digits: + while (idx + dlt) < ln and msg[idx + dlt] in digits: + dlt += 1 + if (idx + dlt) < ln and msg[idx + dlt] is '|': dlt += 1 # %.4f elif idx < (ln - 3) and msg[idx] == '%' and msg[idx + 1] in digits: dlt = 2 - while (idx + dlt + 1) < ln and msg[idx + dlt + 1] in digits: + while (idx + dlt) < ln and msg[idx + dlt] in digits: dlt += 1 - if (idx + dlt + 1) < ln and msg[idx + dlt + 1] in format_codes: + if (idx + dlt) < ln and msg[idx + dlt] in format_codes: dlt += 1 else: dlt = 1 # %s - elif idx < (ln - 1) and msg[idx] == '%' and \ - msg[idx + 1] in format_codes: + elif idx < (ln - 1) and msg[idx] == '%' and msg[idx + 1] in format_codes: dlt = 2 if dlt > 1: From 872cc0c4c0be1ceefc91b666276cd075f6b1ac3a Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 4 Oct 2012 13:59:14 +0000 Subject: [PATCH 074/143] Kind of cleanup of "menu strings": always have a space between the entry's label and value (these strings are a nightmare to handle in RTL languages like arabic or persian, but a bit less of a nightmare this way ;) ). --- .../editors/armature/editarmature_sketch.c | 10 +++--- source/blender/editors/armature/poseobject.c | 8 ++--- source/blender/editors/mesh/editface.c | 2 +- source/blender/editors/mesh/editmesh_tools.c | 13 +++---- source/blender/editors/object/object_edit.c | 36 +++++++++---------- .../blender/editors/physics/physics_fluid.c | 10 +++--- source/blender/editors/screen/area.c | 22 ++++++------ .../transform/transform_orientations.c | 6 ++-- 8 files changed, 55 insertions(+), 52 deletions(-) diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index f3f985fa97d..8d8fa730360 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -41,6 +41,8 @@ #include "BLI_graph.h" #include "BLI_ghash.h" +#include "BLF_translation.h" + #include "BKE_context.h" #include "BKE_sketch.h" @@ -175,7 +177,7 @@ void BIF_makeListTemplates(const bContext *C) const char *BIF_listTemplates(const bContext *UNUSED(C)) { GHashIterator ghi; - char menu_header[] = "Template%t|None%x0|"; + const char *menu_header = IFACE_("Template %t|None %x0|"); char *p; if (TEMPLATES_MENU != NULL) { @@ -194,7 +196,7 @@ const char *BIF_listTemplates(const bContext *UNUSED(C)) Object *ob = BLI_ghashIterator_getValue(&ghi); int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi)); - p += sprintf(p, "|%s%%x%i", ob->id.name + 2, key); + p += sprintf(p, "|%s %%x%i", ob->id.name + 2, key); BLI_ghashIterator_step(&ghi); } @@ -1717,8 +1719,8 @@ void sk_applyCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UN SK_Intersection *isect; int command = 1; -// XXX -// command = pupmenu("Action %t|Flatten %x1|Straighten %x2|Polygonize %x3"); +/* XXX */ +/* command = pupmenu("Action %t|Flatten %x1|Straighten %x2|Polygonize %x3"); */ if (command < 1) return; for (isect = gest->intersections.first; isect; isect = isect->next) { diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index 2f5eaabc12b..dc049e51062 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -888,16 +888,16 @@ static void pose_copy_menu(Scene *scene) if (pose_has_protected_selected(ob, 0)) { i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */ if (i < 25) - nr = pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5"); + nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5"); else - nr = pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4"); + nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4"); } else { i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */ if (i < 25) - nr = pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8"); + nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8"); else - nr = pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8"); + nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8"); } if (nr <= 0) diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index a677f1272a3..5fd848ccb13 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -426,7 +426,7 @@ void seam_mark_clear_tface(Scene *scene, short mode) if (me == 0 || me->totpoly == 0) return; if (mode == 0) - mode = pupmenu("Seams%t|Mark Border Seam %x1|Clear Seam %x2"); + mode = pupmenu("Seams %t|Mark Border Seam %x1|Clear Seam %x2"); if (mode != 1 && mode != 2) return; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 48ffb352247..1d96a3a958d 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -439,16 +439,17 @@ static int edbm_extrude_mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOpe zero_v3(nor); + /* XXX If those popup menus were to be enabled again, please get rid of this "menu string" syntax! */ if (em->selectmode & SCE_SELECT_VERTEX) { if (em->bm->totvertsel == 0) nr = 0; else if (em->bm->totvertsel == 1) nr = 4; else if (em->bm->totedgesel == 0) nr = 4; else if (em->bm->totfacesel == 0) - nr = 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4"); + nr = 3; /* pupmenu("Extrude %t|Only Edges %x3|Only Vertices %x4"); */ else if (em->bm->totfacesel == 1) - nr = 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4"); + nr = 1; /* pupmenu("Extrude %t|Region %x1|Only Edges% x3|Only Vertices %x4"); */ else - nr = 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4"); + nr = 1; /* pupmenu("Extrude %t|Region %x1|Individual Faces %x2|Only Edges %x3|Only Vertices %x4"); */ } else if (em->selectmode & SCE_SELECT_EDGE) { if (em->bm->totedgesel == 0) nr = 0; @@ -458,16 +459,16 @@ static int edbm_extrude_mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOpe else if (em->totedgesel == 1) nr = 3; else if (em->totfacesel == 0) nr = 3; else if (em->totfacesel == 1) - nr = 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3"); + nr = 1; /* pupmenu("Extrude %t|Region %x1|Only Edges %x3"); */ else - nr = 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3"); + nr = 1; /* pupmenu("Extrude %t|Region %x1|Individual Faces %x2|Only Edges %x3"); */ #endif } else { if (em->bm->totfacesel == 0) nr = 0; else if (em->bm->totfacesel == 1) nr = 1; else - nr = 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2"); + nr = 1; /* pupmenu("Extrude %t|Region %x1|Individual Faces %x2"); */ } if (nr < 1) return 'g'; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index bdc7699ee96..43c6c332791 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1017,9 +1017,9 @@ static void UNUSED_FUNCTION(copy_attr_menu) (Main * bmain, Scene * scene, View3D if (!(ob = OBACT)) return; - if (scene->obedit) { // XXX get from context -// if (ob->type == OB_MESH) -// XXX mesh_copy_menu(); + if (scene->obedit) { /* XXX get from context */ +/* if (ob->type == OB_MESH) */ +/* XXX mesh_copy_menu(); */ return; } @@ -1030,34 +1030,34 @@ static void UNUSED_FUNCTION(copy_attr_menu) (Main * bmain, Scene * scene, View3D */ strcpy(str, - "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|" - "Time Offset%x5|Dupli%x6|Object Color%x31|%l|Mass%x7|Damping%x8|All Physical Attributes%x11|Properties%x9|" - "Logic Bricks%x10|Protected Transform%x29|%l"); + "Copy Attributes %t|Location %x1|Rotation %x2|Size %x3|Draw Options %x4|" + "Time Offset %x5|Dupli %x6|Object Color %x31|%l|Mass %x7|Damping %x8|All Physical Attributes %x11|Properties %x9|" + "Logic Bricks %x10|Protected Transform %x29|%l"); - strcat(str, "|Object Constraints%x22"); - strcat(str, "|NLA Strips%x26"); + strcat(str, "|Object Constraints %x22"); + strcat(str, "|NLA Strips %x26"); -// XXX if (OB_TYPE_SUPPORT_MATERIAL(ob->type)) { -// strcat(str, "|Texture Space%x17"); -// } +/* XXX if (OB_TYPE_SUPPORT_MATERIAL(ob->type)) { */ +/* strcat(str, "|Texture Space %x17"); */ +/* } */ - if (ob->type == OB_FONT) strcat(str, "|Font Settings%x18|Bevel Settings%x19"); - if (ob->type == OB_CURVE) strcat(str, "|Bevel Settings%x19|UV Orco%x28"); + if (ob->type == OB_FONT) strcat(str, "|Font Settings %x18|Bevel Settings %x19"); + if (ob->type == OB_CURVE) strcat(str, "|Bevel Settings %x19|UV Orco %x28"); if ((ob->type == OB_FONT) || (ob->type == OB_CURVE)) { - strcat(str, "|Curve Resolution%x25"); + strcat(str, "|Curve Resolution %x25"); } if (ob->type == OB_MESH) { - strcat(str, "|Subsurf Settings%x21|AutoSmooth%x27"); + strcat(str, "|Subsurf Settings %x21|AutoSmooth %x27"); } - if (ob->soft) strcat(str, "|Soft Body Settings%x23"); + if (ob->soft) strcat(str, "|Soft Body Settings %x23"); - strcat(str, "|Pass Index%x30"); + strcat(str, "|Pass Index %x30"); if (ob->type == OB_MESH || ob->type == OB_CURVE || ob->type == OB_LATTICE || ob->type == OB_SURF) { - strcat(str, "|Modifiers ...%x24"); + strcat(str, "|Modifiers ... %x24"); } event = pupmenu(str); diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 099d868a0ad..315386a947e 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -695,21 +695,21 @@ static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetF outStringsChanged=1; } - // check if modified output dir is ok + /* check if modified output dir is ok */ #if 0 if (outStringsChanged) { char dispmsg[FILE_MAX+256]; int selection=0; BLI_strncpy(dispmsg, "Output settings set to: '", sizeof(dispmsg)); strcat(dispmsg, newSurfdataPath); - strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0"); + strcat(dispmsg, "'%t|Continue with changed settings %x1|Discard and abort %x0"); - // ask user if thats what he/she wants... + /* ask user if thats what he/she wants... */ selection = pupmenu(dispmsg); - if (selection < 1) return 0; // 0 from menu, or -1 aborted + if (selection < 1) return 0; /* 0 from menu, or -1 aborted */ BLI_strncpy(targetDir, newSurfdataPath, sizeof(targetDir)); strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR); - BLI_path_abs(targetDir, G.main->name); // fixed #frame-no + BLI_path_abs(targetDir, G.main->name); /* fixed #frame-no */ } #endif return outStringsChanged; diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index d14514546f5..01a5304451a 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1459,39 +1459,39 @@ void ED_area_prevspace(bContext *C, ScrArea *sa) static const char *editortype_pup(void) { const char *types = N_( - "Editor type:%t" + "Editor type: %t" "|3D View %x1" "|%l" - + "|Timeline %x15" "|Graph Editor %x2" "|DopeSheet %x12" "|NLA Editor %x13" - + "|%l" - + "|UV/Image Editor %x6" - + "|Video Sequence Editor %x8" "|Movie Clip Editor %x20" "|Text Editor %x9" "|Node Editor %x16" "|Logic Editor %x17" - + "|%l" - + "|Properties %x4" "|Outliner %x3" "|User Preferences %x19" - "|Info%x7" + "|Info %x7" "|%l" "|File Browser %x5" - + "|%l" - + "|Python Console %x18" ); @@ -1517,7 +1517,7 @@ int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco) but = uiDefIconTextButC(block, ICONTEXTROW, 0, ICON_VIEW3D, editortype_pup(), xco, yco, UI_UNIT_X + 10, UI_UNIT_Y, &(sa->butspacetype), 1.0, SPACEICONMAX, 0, 0, - TIP_("Displays current editor type. Click for menu of available types")); + TIP_("Display current editor type (click for menu of available types)")); uiButSetFunc(but, spacefunc, NULL, NULL); uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index a155ff7786a..0e25739c34a 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -402,7 +402,7 @@ EnumPropertyItem *BIF_enumTransformOrientation(bContext *C) const char *BIF_menustringTransformOrientation(const bContext *C, const char *title) { - const char *menu = IFACE_("%t|Global%x0|Local%x1|Gimbal%x4|Normal%x2|View%x3"); + const char *menu = IFACE_("%t|Global %x0|Local %x1|Gimbal %x4|Normal %x2|View %x3"); ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces; TransformOrientation *ts; int i = V3D_MANIP_CUSTOM; @@ -411,14 +411,14 @@ const char *BIF_menustringTransformOrientation(const bContext *C, const char *ti title = IFACE_(title); - str_menu = MEM_callocN(strlen(menu) + strlen(title) + 1 + elem_size * BIF_countTransformOrientation(C), TIP_("UserTransSpace from matrix")); + str_menu = MEM_callocN(strlen(menu) + strlen(title) + 1 + elem_size * BIF_countTransformOrientation(C), "UserTransSpace from matrix"); p = str_menu; p += sprintf(str_menu, "%s", title); p += sprintf(p, "%s", menu); for (ts = transform_spaces->first; ts; ts = ts->next) { - p += sprintf(p, "|%s%%x%d", ts->name, i++); + p += sprintf(p, "|%s %%x%d", ts->name, i++); } return str_menu; From 794520a86a83a9eea230563e805480016c0479f0 Mon Sep 17 00:00:00 2001 From: Dan Eicher Date: Thu, 4 Oct 2012 15:14:15 +0000 Subject: [PATCH 075/143] Have CPack rpm builder install the colorspace folder too --- build_files/package_spec/rpm/blender.spec.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build_files/package_spec/rpm/blender.spec.in b/build_files/package_spec/rpm/blender.spec.in index 85a689031a3..a95fce80103 100644 --- a/build_files/package_spec/rpm/blender.spec.in +++ b/build_files/package_spec/rpm/blender.spec.in @@ -76,6 +76,7 @@ fi || : %defattr(-,root,root,-) %{_bindir}/%{name} %{_datadir}/%{name}/%{blender_api}/datafiles/fonts +%{_datadir}/%{name}/%{blender_api}/datafiles/colormanagement %{_datadir}/%{name}/%{blender_api}/scripts %{_datadir}/icons/hicolor/*/apps/%{name}.* %{_datadir}/applications/%{name}.desktop From 709903c6bba4dca12a6f367000f99a83da2af034 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 4 Oct 2012 16:46:15 +0000 Subject: [PATCH 076/143] refactor ED_view3d_project_short & ED_view3d_project_short_noclip, This is apart of a code cleanup to make ED_view3d_project_short/ED_view3d_project_int/ED_view3d_project_float interchangeable. Currently they work very differently in a way thats quite confusing (and cause of bugs in blender that remain uncorrected) - fixes coming. There are also cases where ED_view3d_project_short is used, then the values are converted from shorts into int's after because ED_view3d_project_int() behaves differently, will unify behavior of these functions after this commit. - rather then clip/noclip versions, pass flags (for bound-box clip, window clip). - rather then store the invalid clip-value, return success (or error value clip_near, clip_bb, clip_win, overflow). - remove local copies of project functions from drawobject.c: view3d_project_short_clip, view3d_project_short_noclip, view3d_project_short_clip_persmat. add functions: - ED_view3d_project_short_global() global space projection - ED_view3d_project_short_object() object space projection. - ED_view3d_project_short_ex() take perspective matrix and local space option as args. - ED_view3d_project_base() - special function to set the Object 'Base' screen coords (sx, sy), since this is a common enough operation. --- .../editors/armature/editarmature_sketch.c | 103 +++++---- source/blender/editors/include/ED_view3d.h | 30 ++- .../blender/editors/physics/particle_edit.c | 7 +- .../blender/editors/space_view3d/drawobject.c | 212 +++++------------- .../editors/space_view3d/view3d_select.c | 46 ++-- .../editors/space_view3d/view3d_view.c | 134 ++++++----- 6 files changed, 261 insertions(+), 271 deletions(-) diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 8d8fa730360..b72fad08d1f 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -646,16 +646,17 @@ static SK_Point *sk_snapPointStroke(bContext *C, SK_Stroke *stk, int mval[2], in short pval[2]; int pdist; - ED_view3d_project_short_noclip(ar, stk->points[i].p, pval); + if (ED_view3d_project_short_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { - pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); + pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); - if (pdist < *dist) { - *dist = pdist; - pt = stk->points + i; + if (pdist < *dist) { + *dist = pdist; + pt = stk->points + i; - if (index != NULL) { - *index = i; + if (index != NULL) { + *index = i; + } } } } @@ -681,7 +682,24 @@ static SK_Point *sk_snapPointArmature(bContext *C, Object *ob, ListBase *ebones, { copy_v3_v3(vec, bone->head); mul_m4_v3(ob->obmat, vec); - ED_view3d_project_short_noclip(ar, vec, pval); + if (ED_view3d_project_short_noclip(ar, vec, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + + pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); + + if (pdist < *dist) + { + *dist = pdist; + pt = &boneSnap; + copy_v3_v3(pt->p, vec); + pt->type = PT_EXACT; + } + } + } + + + copy_v3_v3(vec, bone->tail); + mul_m4_v3(ob->obmat, vec); + if (ED_view3d_project_short_noclip(ar, vec, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); @@ -693,21 +711,6 @@ static SK_Point *sk_snapPointArmature(bContext *C, Object *ob, ListBase *ebones, pt->type = PT_EXACT; } } - - - copy_v3_v3(vec, bone->tail); - mul_m4_v3(ob->obmat, vec); - ED_view3d_project_short_noclip(ar, vec, pval); - - pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); - - if (pdist < *dist) - { - *dist = pdist; - pt = &boneSnap; - copy_v3_v3(pt->p, vec); - pt->type = PT_EXACT; - } } return pt; @@ -936,10 +939,14 @@ static void sk_projectDrawPoint(bContext *C, float vec[3], SK_Stroke *stk, SK_Dr initgrabz(ar->regiondata, fp[0], fp[1], fp[2]); /* method taken from editview.c - mouse_cursor() */ - ED_view3d_project_short_noclip(ar, fp, cval); - VECSUB2D(mval_f, cval, dd->mval); - ED_view3d_win_to_delta(ar, mval_f, dvec); - sub_v3_v3v3(vec, fp, dvec); + if (ED_view3d_project_short_global(ar, fp, cval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + VECSUB2D(mval_f, cval, dd->mval); + ED_view3d_win_to_delta(ar, mval_f, dvec); + sub_v3_v3v3(vec, fp, dvec); + } + else { + zero_v3(vec); + } } static int sk_getStrokeDrawPoint(bContext *C, SK_Point *pt, SK_Sketch *UNUSED(sketch), SK_Stroke *stk, SK_DrawData *dd) @@ -1786,33 +1793,35 @@ int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *UNUSED(sketc short start_val[2], end_val[2]; short dist; - ED_view3d_project_short_noclip(ar, gest->stk->points[0].p, start_val); - ED_view3d_project_short_noclip(ar, sk_lastStrokePoint(gest->stk)->p, end_val); + if ((ED_view3d_project_short_global(ar, gest->stk->points[0].p, start_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) && + (ED_view3d_project_short_global(ar, sk_lastStrokePoint(gest->stk)->p, end_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS)) + { - dist = MAX2(ABS(start_val[0] - end_val[0]), ABS(start_val[1] - end_val[1])); + dist = MAX2(ABS(start_val[0] - end_val[0]), ABS(start_val[1] - end_val[1])); - /* if gesture is a circle */ - if (dist <= 20) { - SK_Intersection *isect; + /* if gesture is a circle */ + if (dist <= 20) { + SK_Intersection *isect; - /* check if it circled around an exact point */ - for (isect = gest->intersections.first; isect; isect = isect->next) { - /* only delete strokes that are crossed twice */ - if (isect->next && isect->next->stroke == isect->stroke) { - int start_index, end_index; - int i; + /* check if it circled around an exact point */ + for (isect = gest->intersections.first; isect; isect = isect->next) { + /* only delete strokes that are crossed twice */ + if (isect->next && isect->next->stroke == isect->stroke) { + int start_index, end_index; + int i; - start_index = MIN2(isect->after, isect->next->after); - end_index = MAX2(isect->before, isect->next->before); + start_index = MIN2(isect->after, isect->next->after); + end_index = MAX2(isect->before, isect->next->before); - for (i = start_index; i <= end_index; i++) { - if (isect->stroke->points[i].type == PT_EXACT) { - return 1; /* at least one exact point found, stop detect here */ + for (i = start_index; i <= end_index; i++) { + if (isect->stroke->points[i].type == PT_EXACT) { + return 1; /* at least one exact point found, stop detect here */ + } } - } - /* skip next */ - isect = isect->next; + /* skip next */ + isect = isect->next; + } } } } diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 9536dd76581..ca5d8691df7 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -113,8 +113,31 @@ void ED_view3d_depth_tag_update(struct RegionView3D *rv3d); /* TODO, these functions work quite differently, we should make them behave in a uniform way * otherwise we can't be sure bugs are not added when we need to move from short->float types for eg * - Campbell */ -void ED_view3d_project_short(struct ARegion *ar, const float co[3], short r_co[2]); -void ED_view3d_project_short_noclip(struct ARegion *ar, const float vec[3], short r_co[2]); + + +/* return values for ED_view3d_project_...() */ +typedef enum { + V3D_PROJ_RET_SUCCESS = 0, + V3D_PROJ_RET_CLIP_NEAR = 1, /* can't avoid this when in perspective mode, (can't avoid) */ + V3D_PROJ_RET_CLIP_BB = 2, /* bounding box clip - RV3D_CLIPPING */ + V3D_PROJ_RET_CLIP_WIN = 3, /* outside window bounds */ + V3D_PROJ_RET_OVERFLOW = 4 /* outside range (mainly for short), (can't avoid) */ +} eV3DProjStatus; + +/* some clipping tests are optional */ +typedef enum { + V3D_PROJ_TEST_NOP = 0, + V3D_PROJ_TEST_CLIP_BB = (1 << 0), + V3D_PROJ_TEST_CLIP_WIN = (1 << 1), +} eV3DProjTest; + + +eV3DProjStatus ED_view3d_project_short_ex(struct ARegion *ar, float perspmat[4][4], const int is_local, + const float co[3], short r_co[2], eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_short_global(struct ARegion *ar, const float co[3], short r_co[2], eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_short_object(struct ARegion *ar, const float co[3], short r_co[2], eV3DProjTest flag); +void _ED_view3d_project_short(struct ARegion *ar, const float co[3], short r_co[2]); // V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN +void _ED_view3d_project_short_noclip(struct ARegion *ar, const float vec[3], short r_co[2]); // void ED_view3d_project_int(struct ARegion *ar, const float co[3], int r_co[2]); void ED_view3d_project_int_noclip(struct ARegion *ar, const float co[3], int r_co[2]); void ED_view3d_project_float(struct ARegion *ar, const float co[3], float r_co[2]); @@ -122,6 +145,9 @@ void ED_view3d_project_float_noclip(struct ARegion *ar, const float co[3], float void ED_view3d_project_float_v2_m4(const struct ARegion *a, const float co[3], float r_co[2], float mat[4][4]); void ED_view3d_project_float_v3_m4(struct ARegion *a, const float co[3], float r_co[3], float mat[4][4]); +/* Base's get their own function since its a common operation */ +eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base); + void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, const float y, const float z); int ED_view3d_clip_range_get(struct View3D *v3d, struct RegionView3D *rv3d, float *clipsta, float *clipend); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index ea6f9d4cebb..6d3f4b38583 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -408,11 +408,12 @@ static int key_test_depth(PEData *data, const float co[3]) /* nothing to do */ if ((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0) return 1; - - ED_view3d_project_short(data->vc.ar, co, wco); - if (wco[0] == IS_CLIPPED) + if (ED_view3d_project_short_global(data->vc.ar, co, wco, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_SUCCESS) + { return 0; + } gluProject(co[0], co[1], co[2], data->mats.modelview, data->mats.projection, (GLint *)data->mats.viewport, &ux, &uy, &uz); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 7badca304c4..e368f06a35f 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -239,107 +239,6 @@ static int check_ob_drawface_dot(Scene *sce, View3D *vd, char dt) return 1; } -/* ************* only use while object drawing ************** - * or after running ED_view3d_init_mats_rv3d - * */ -static void view3d_project_short_clip(ARegion *ar, const float vec[3], short adr[2], int is_local) -{ - RegionView3D *rv3d = ar->regiondata; - float fx, fy, vec4[4]; - - adr[0] = IS_CLIPPED; - - /* clipplanes in eye space */ - if (rv3d->rflag & RV3D_CLIPPING) { - if (ED_view3d_clipping_test(rv3d, vec, is_local)) - return; - } - - copy_v3_v3(vec4, vec); - vec4[3] = 1.0; - - mul_m4_v4(rv3d->persmatob, vec4); - - /* clipplanes in window space */ - if (vec4[3] > (float)BL_NEAR_CLIP) { /* is the NEAR clipping cutoff for picking */ - fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]); - - if (fx > 0 && fx < ar->winx) { - - fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]); - - if (fy > 0.0f && fy < (float)ar->winy) { - adr[0] = (short)floorf(fx); - adr[1] = (short)floorf(fy); - } - } - } -} - -/* BMESH NOTE: this function is unused in bmesh only */ - -/* only use while object drawing */ -static void UNUSED_FUNCTION(view3d_project_short_noclip) (ARegion * ar, const float vec[3], short adr[2]) -{ - RegionView3D *rv3d = ar->regiondata; - float fx, fy, vec4[4]; - - adr[0] = IS_CLIPPED; - - copy_v3_v3(vec4, vec); - vec4[3] = 1.0; - - mul_m4_v4(rv3d->persmatob, vec4); - - if (vec4[3] > (float)BL_NEAR_CLIP) { /* is the NEAR clipping cutoff for picking */ - fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]); - - if (fx > -32700 && fx < 32700) { - - fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]); - - if (fy > -32700.0f && fy < 32700.0f) { - adr[0] = (short)floorf(fx); - adr[1] = (short)floorf(fy); - } - } - } -} - -/* same as view3d_project_short_clip but use persmat instead of persmatob for projection */ -static void view3d_project_short_clip_persmat(ARegion *ar, const float vec[3], short adr[2], int is_local) -{ - RegionView3D *rv3d = ar->regiondata; - float fx, fy, vec4[4]; - - adr[0] = IS_CLIPPED; - - /* clipplanes in eye space */ - if (rv3d->rflag & RV3D_CLIPPING) { - if (ED_view3d_clipping_test(rv3d, vec, is_local)) - return; - } - - copy_v3_v3(vec4, vec); - vec4[3] = 1.0; - - mul_m4_v4(rv3d->persmat, vec4); - - /* clipplanes in window space */ - if (vec4[3] > (float)BL_NEAR_CLIP) { /* is the NEAR clipping cutoff for picking */ - fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]); - - if (fx > 0 && fx < ar->winx) { - - fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]); - - if (fy > 0.0f && fy < (float)ar->winy) { - adr[0] = (short)floorf(fx); - adr[1] = (short)floorf(fy); - } - } - } -} /* ************************ */ /* check for glsl drawing */ @@ -883,13 +782,17 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, floa if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE)) mul_m4_v3(mat, vos->vec); - if (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) - view3d_project_short_clip_persmat(ar, vos->vec, vos->sco, (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0); - else - view3d_project_short_clip(ar, vos->vec, vos->sco, (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0); - - if (vos->sco[0] != IS_CLIPPED) + if (ED_view3d_project_short_ex(ar, + (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob, + (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0, + vos->vec, vos->sco, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { tot++; + } + else { + vos->sco[0] = IS_CLIPPED; + } } if (tot) { @@ -1974,15 +1877,17 @@ void lattice_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BPo DispList *dl = BKE_displist_find(&obedit->disp, DL_VERTS); float *co = dl ? dl->verts : NULL; int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw; - short s[2] = {IS_CLIPPED, 0}; + short s[2]; ED_view3d_clipping_local(vc->rv3d, obedit->obmat); /* for local clipping lookups */ for (i = 0; i < N; i++, bp++, co += 3) { if (bp->hide == 0) { - view3d_project_short_clip(vc->ar, dl ? co : bp->vec, s, TRUE); - if (s[0] != IS_CLIPPED) + if (ED_view3d_project_short_object(vc->ar, dl ? co : bp->vec, s, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { func(userData, bp, s[0], s[1]); + } } } } @@ -2084,19 +1989,16 @@ static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const flo BMVert *eve = EDBM_vert_at_index(data->vc.em, index); if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - short s[2] = {IS_CLIPPED, 0}; + const eV3DProjTest flag = (data->clipVerts == V3D_CLIP_TEST_OFF) ? + V3D_PROJ_TEST_NOP : + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN; + short s[2]; - if (data->clipVerts != V3D_CLIP_TEST_OFF) { - view3d_project_short_clip(data->vc.ar, co, s, TRUE); - } - else { - float co2[2]; - mul_v3_m4v3(co2, data->vc.obedit->obmat, co); - ED_view3d_project_short_noclip(data->vc.ar, co2, s); + if (ED_view3d_project_short_object(data->vc.ar, co, s, flag) != V3D_PROJ_RET_SUCCESS) { + return; } - if (s[0] != IS_CLIPPED) - data->func(data->userData, eve, s[0], s[1], index); + data->func(data->userData, eve, s[0], s[1], index); } } @@ -2159,25 +2061,21 @@ static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, const flo if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { short s[2][2]; - if (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) { - view3d_project_short_clip(data->vc.ar, v0co, s[0], TRUE); - view3d_project_short_clip(data->vc.ar, v1co, s[1], TRUE); + const eV3DProjTest flag = (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) ? + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN : + V3D_PROJ_TEST_NOP; - if (s[0][0] == IS_CLIPPED || s[1][0] == IS_CLIPPED) { - return; - } + if (ED_view3d_project_short_object(data->vc.ar, v0co, s[0], flag) != V3D_PROJ_RET_SUCCESS) { + return; + } + if (ED_view3d_project_short_object(data->vc.ar, v1co, s[1], flag) != V3D_PROJ_RET_SUCCESS) { + return; + } + + if (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) { + /* pass */ } else { - float v1_co[3], v2_co[3]; - - mul_v3_m4v3(v1_co, data->vc.obedit->obmat, v0co); - mul_v3_m4v3(v2_co, data->vc.obedit->obmat, v1co); - - /* XXX, todo, use ED_view3d_project_int_noclip(...), however these functions work differently - * and need to be cleaned up, Campbell */ - ED_view3d_project_short_noclip(data->vc.ar, v1_co, s[0]); - ED_view3d_project_short_noclip(data->vc.ar, v2_co, s[1]); - if (data->clipVerts == V3D_CLIP_TEST_REGION) { /* make an int copy */ int s_int[2][2] = {{s[0][0], s[0][1]}, @@ -2230,10 +2128,12 @@ static void mesh_foreachScreenFace__mapFunc(void *userData, int index, const flo float cent2[3]; short s[2]; - mul_v3_m4v3(cent2, data->vc.obedit->obmat, cent); - ED_view3d_project_short(data->vc.ar, cent2, s); + /* TODO, use ED_view3d_project_short_object */ - if (s[0] != IS_CLIPPED) { + mul_v3_m4v3(cent2, data->vc.obedit->obmat, cent); + if (ED_view3d_project_short_global(data->vc.ar, cent2, s, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { data->func(data->userData, efa, s[0], s[1], index); } } @@ -2267,7 +2167,7 @@ void nurbs_foreachScreenVert( void *userData) { Curve *cu = vc->obedit->data; - short s[2] = {IS_CLIPPED, 0}; + short s[2]; Nurb *nu; int i; ListBase *nurbs = BKE_curve_editNurbs_get(cu); @@ -2282,20 +2182,28 @@ void nurbs_foreachScreenVert( if (bezt->hide == 0) { if (cu->drawflag & CU_HIDE_HANDLES) { - view3d_project_short_clip(vc->ar, bezt->vec[1], s, TRUE); - if (s[0] != IS_CLIPPED) + if (ED_view3d_project_short_object(vc->ar, bezt->vec[1], s, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { func(userData, nu, NULL, bezt, 1, s[0], s[1]); + } } else { - view3d_project_short_clip(vc->ar, bezt->vec[0], s, TRUE); - if (s[0] != IS_CLIPPED) + if (ED_view3d_project_short_object(vc->ar, bezt->vec[0], s, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { func(userData, nu, NULL, bezt, 0, s[0], s[1]); - view3d_project_short_clip(vc->ar, bezt->vec[1], s, TRUE); - if (s[0] != IS_CLIPPED) + } + if (ED_view3d_project_short_object(vc->ar, bezt->vec[1], s, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { func(userData, nu, NULL, bezt, 1, s[0], s[1]); - view3d_project_short_clip(vc->ar, bezt->vec[2], s, TRUE); - if (s[0] != IS_CLIPPED) + } + if (ED_view3d_project_short_object(vc->ar, bezt->vec[2], s, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { func(userData, nu, NULL, bezt, 2, s[0], s[1]); + } } } } @@ -2305,9 +2213,11 @@ void nurbs_foreachScreenVert( BPoint *bp = &nu->bp[i]; if (bp->hide == 0) { - view3d_project_short_clip(vc->ar, bp->vec, s, TRUE); - if (s[0] != IS_CLIPPED) + if (ED_view3d_project_short_object(vc->ar, bp->vec, s, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { func(userData, nu, bp, NULL, -1, s[0], s[1]); + } } } } @@ -6622,7 +6532,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* which wire color */ if ((dflag & DRAW_CONSTCOLOR) == 0) { - ED_view3d_project_short(ar, ob->obmat[3], &base->sx); + ED_view3d_project_base(ar, base); draw_object_wire_color(scene, base, _ob_wire_col, warning_recursive); ob_wire_col = _ob_wire_col; diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index a2ad54cb92e..b31b932d71f 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -371,7 +371,7 @@ static void do_lasso_select_objects(ViewContext *vc, int mcords[][2], short move for (base = vc->scene->base.first; base; base = base->next) { if (BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */ - ED_view3d_project_short(vc->ar, base->object->obmat[3], &base->sx); + ED_view3d_project_base(vc->ar, base); if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) { if (select) ED_base_object_select(base, BA_SELECT); @@ -577,10 +577,14 @@ static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short mov for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE) == 0) { + + /* XXX, TODO, use ED_view3d_project_short_object here */ + sco1[0] = sco2[0] = IS_CLIPPED; + mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head); - ED_view3d_project_short(vc->ar, vec, sco1); + ED_view3d_project_short_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); - ED_view3d_project_short(vc->ar, vec, sco2); + ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); didpoint = 0; if (BLI_lasso_is_point_inside(mcords, moves, sco1[0], sco1[1], IS_CLIPPED)) { @@ -631,12 +635,16 @@ static void do_lasso_select_meta(ViewContext *vc, int mcords[][2], short moves, for (ml = mb->editelems->first; ml; ml = ml->next) { - mul_v3_m4v3(vec, vc->obedit->obmat, &ml->x); - ED_view3d_project_short(vc->ar, vec, sco); + /* TODO, use ED_view3d_project_short_object */ - if (BLI_lasso_is_point_inside(mcords, moves, sco[0], sco[1], IS_CLIPPED)) { - if (select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; + mul_v3_m4v3(vec, vc->obedit->obmat, &ml->x); + if (ED_view3d_project_short_global(vc->ar, vec, sco, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + if (BLI_lasso_is_point_inside(mcords, moves, sco[0], sco[1], INT_MAX)) { + if (select) ml->flag |= SELECT; + else ml->flag &= ~SELECT; + } } } } @@ -1059,8 +1067,7 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int } else { int temp, dist = 15; - - ED_view3d_project_short(vc->ar, base->object->obmat[3], &base->sx); + ED_view3d_project_base(vc->ar, base); temp = abs(base->sx - mval[0]) + abs(base->sy - mval[1]); if (temp < dist) @@ -1341,8 +1348,7 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese base = startbase; while (base) { if (BASE_SELECTABLE(v3d, base)) { - ED_view3d_project_short(ar, base->object->obmat[3], &base->sx); - + ED_view3d_project_base(ar, base); temp = abs(base->sx - mval[0]) + abs(base->sy - mval[1]); if (base == BASACT) temp += 10; if (temp < dist) { @@ -2375,14 +2381,17 @@ static void pose_circle_select(ViewContext *vc, int select, const int mval[2], f /* skip invisible bones */ if (PBONE_VISIBLE(arm, pchan->bone) == 0) continue; + + /* XXX, TODO, center check does not check for clipping! */ + /* XXX, TODO, use ED_view3d_project_short_object here */ /* project head location to screenspace */ mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_head); - ED_view3d_project_short(vc->ar, vec, sco1); + ED_view3d_project_short_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); /* project tail location to screenspace */ mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_tail); - ED_view3d_project_short(vc->ar, vec, sco2); + ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); /* check if the head and/or tail is in the circle * - the call to check also does the selection already @@ -2444,13 +2453,16 @@ static void armature_circle_select(ViewContext *vc, int select, const int mval[2 short sco1[2], sco2[2], didpoint = 0; float vec[3]; + /* XXX, TODO, center check does not check for clipping! */ + /* XXX, TODO, use ED_view3d_project_short_object here */ + /* project head location to screenspace */ mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head); - ED_view3d_project_short(vc->ar, vec, sco1); + ED_view3d_project_short_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); /* project tail location to screenspace */ mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); - ED_view3d_project_short(vc->ar, vec, sco2); + ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); /* check if the head and/or tail is in the circle * - the call to check also does the selection already @@ -2556,7 +2568,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) select = select ? BA_SELECT : BA_DESELECT; for (base = FIRSTBASE; base; base = base->next) { if (BASE_SELECTABLE(v3d, base)) { - ED_view3d_project_short(ar, base->object->obmat[3], &base->sx); + ED_view3d_project_base(ar, base); if (base->sx != IS_CLIPPED) { int dx = base->sx - x; int dy = base->sy - y; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index ff518e6ce5b..2ed8048fee4 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -858,6 +858,19 @@ void ED_view3d_project_float_v3_m4(ARegion *ar, const float vec[3], float r_co[3 } } +eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base) +{ + eV3DProjStatus ret = ED_view3d_project_short_global(ar, base->object->obmat[3], &base->sx, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); + + if (ret != V3D_PROJ_RET_SUCCESS) { + base->sx = IS_CLIPPED; + base->sy = 0; + } + + return ret; +} + int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb) { /* return 1: draw */ @@ -893,36 +906,81 @@ int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb) return 0; } -void ED_view3d_project_short(ARegion *ar, const float co[3], short r_co[2]) /* clips */ +/* perspmat is typically... + * - 'rv3d->perspmat', is_local == FALSE + * - 'rv3d->perspmatob', is_local == TRUE + */ +static eV3DProjStatus ed_view3d_project__internal(ARegion *ar, + float perspmat[4][4], const int is_local, /* normally hidden */ + const float co[3], float r_co[2], eV3DProjTest flag) { - RegionView3D *rv3d = ar->regiondata; float fx, fy, vec4[4]; - - r_co[0] = IS_CLIPPED; - - if (rv3d->rflag & RV3D_CLIPPING) { - if (ED_view3d_clipping_test(rv3d, co, FALSE)) { - return; - } - } - - copy_v3_v3(vec4, co); - vec4[3] = 1.0; - mul_m4_v4(rv3d->persmat, vec4); - - if (vec4[3] > (float)BL_NEAR_CLIP) { - fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]); - - if (fx > 0 && fx < ar->winx) { - - fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]); - - if (fy > 0.0f && fy < (float)ar->winy) { - r_co[0] = (short)floor(fx); - r_co[1] = (short)floor(fy); + + if (flag & V3D_PROJ_TEST_CLIP_BB) { + RegionView3D *rv3d = ar->regiondata; + if (rv3d->rflag & RV3D_CLIPPING) { + if (ED_view3d_clipping_test(rv3d, co, is_local)) { + return V3D_PROJ_RET_CLIP_BB; } } } + + copy_v3_v3(vec4, co); + vec4[3] = 1.0; + mul_m4_v4(perspmat, vec4); + + if (vec4[3] > (float)BL_NEAR_CLIP) { + fx = ((float)ar->winx / 2.0f) * (1.0f + vec4[0] / vec4[3]); + if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0 && fx < ar->winx)) { + fy = ((float)ar->winy / 2.0f) * (1.0f + vec4[1] / vec4[3]); + if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)ar->winy)) { + r_co[0] = (short)floor(fx); + r_co[1] = (short)floor(fy); + } + else { + return V3D_PROJ_RET_CLIP_WIN; + } + } + else { + return V3D_PROJ_RET_CLIP_WIN; + } + } + else { + return V3D_PROJ_RET_CLIP_NEAR; + } + + return V3D_PROJ_RET_SUCCESS; +} + +eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], const int is_local, + const float co[3], short r_co[2], eV3DProjTest flag) +{ + float tvec[2]; + eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag); + if (ret == V3D_PROJ_RET_SUCCESS) { + if ((tvec[0] > -32700.0 && tvec[0] < 32700.0f) && + (tvec[1] > -32700.0 && tvec[1] < 32700.0f)) + { + r_co[0] = (short)floor(tvec[0]); + r_co[1] = (short)floor(tvec[1]); + } + else { + return V3D_PROJ_RET_OVERFLOW; + } + } + return ret; +} + +eV3DProjStatus ED_view3d_project_short_global(ARegion *ar, const float co[3], short r_co[2], eV3DProjTest flag) +{ + RegionView3D *rv3d = ar->regiondata; + return ED_view3d_project_short_ex(ar, rv3d->persmat, FALSE, co, r_co, flag); +} +/* object space, use ED_view3d_init_mats_rv3d before calling */ +eV3DProjStatus ED_view3d_project_short_object(ARegion *ar, const float co[3], short r_co[2], eV3DProjTest flag) +{ + RegionView3D *rv3d = ar->regiondata; + return ED_view3d_project_short_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); } void ED_view3d_project_int(ARegion *ar, const float co[3], int r_co[2]) @@ -973,32 +1031,6 @@ void ED_view3d_project_int_noclip(ARegion *ar, const float co[3], int r_co[2]) } } -void ED_view3d_project_short_noclip(ARegion *ar, const float co[3], short r_co[2]) -{ - RegionView3D *rv3d = ar->regiondata; - float fx, fy, vec4[4]; - - copy_v3_v3(vec4, co); - vec4[3] = 1.0; - r_co[0] = IS_CLIPPED; - - mul_m4_v4(rv3d->persmat, vec4); - - if (vec4[3] > (float)BL_NEAR_CLIP) { - fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]); - - if (fx > -32700 && fx < 32700) { - - fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]); - - if (fy > -32700.0f && fy < 32700.0f) { - r_co[0] = (short)floor(fx); - r_co[1] = (short)floor(fy); - } - } - } -} - void ED_view3d_project_float(ARegion *ar, const float co[3], float r_co[2]) { RegionView3D *rv3d = ar->regiondata; From e77004157e483c610a6478b733a42554ab21c365 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 4 Oct 2012 17:52:12 +0000 Subject: [PATCH 077/143] make ED_view3d_project_int equivalent to ED_view3d_project_short functions. --- .../blender/editors/gpencil/gpencil_paint.c | 48 ++++++++----- source/blender/editors/include/ED_view3d.h | 12 ++-- .../blender/editors/physics/particle_edit.c | 32 +++++---- .../editors/space_view3d/view3d_draw.c | 27 +++----- .../editors/space_view3d/view3d_edit.c | 7 +- .../editors/space_view3d/view3d_select.c | 13 ++-- .../editors/space_view3d/view3d_view.c | 67 +++++++------------ source/blender/editors/transform/transform.c | 8 ++- .../editors/transform/transform_snap.c | 21 ++++-- 9 files changed, 130 insertions(+), 105 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 5909c4fc270..0595f4e18bd 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -278,11 +278,15 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] gp_get_3d_reference(p, rvec); /* method taken from editview.c - mouse_cursor() */ - ED_view3d_project_int_noclip(p->ar, rvec, mval_prj); - - VECSUB2D(mval_f, mval_prj, mval); - ED_view3d_win_to_delta(p->ar, mval_f, dvec); - sub_v3_v3v3(out, rvec, dvec); + /* TODO, use ED_view3d_project_float_global */ + if (ED_view3d_project_int_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + VECSUB2D(mval_f, mval_prj, mval); + ED_view3d_win_to_delta(p->ar, mval_f, dvec); + sub_v3_v3v3(out, rvec, dvec); + } + else { + zero_v3(out); + } } } @@ -808,9 +812,14 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, else if (gps->totpoints == 1) { /* get coordinates */ if (gps->flag & GP_STROKE_3DSPACE) { - ED_view3d_project_int(p->ar, &gps->points->x, xyval); - x0 = xyval[0]; - y0 = xyval[1]; + if (ED_view3d_project_int_global(p->ar, &gps->points->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + x0 = xyval[0]; + y0 = xyval[1]; + } + else { + x0 = V2D_IS_CLIPPED; + y0 = V2D_IS_CLIPPED; + } } else if (gps->flag & GP_STROKE_2DSPACE) { UI_view2d_view_to_region(p->v2d, gps->points->x, gps->points->y, &x0, &y0); @@ -847,13 +856,22 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, /* get coordinates */ if (gps->flag & GP_STROKE_3DSPACE) { - ED_view3d_project_int(p->ar, &pt1->x, xyval); - x0 = xyval[0]; - y0 = xyval[1]; - - ED_view3d_project_int(p->ar, &pt2->x, xyval); - x1 = xyval[0]; - y1 = xyval[1]; + if (ED_view3d_project_int_global(p->ar, &pt1->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + x0 = xyval[0]; + y0 = xyval[1]; + } + else { + x0 = V2D_IS_CLIPPED; + y0 = V2D_IS_CLIPPED; + } + if (ED_view3d_project_int_global(p->ar, &pt2->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + x1 = xyval[0]; + y1 = xyval[1]; + } + else { + x1 = V2D_IS_CLIPPED; + y1 = V2D_IS_CLIPPED; + } } else if (gps->flag & GP_STROKE_2DSPACE) { UI_view2d_view_to_region(p->v2d, pt1->x, pt1->y, &x0, &y0); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index ca5d8691df7..30eb38a14bb 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -132,14 +132,18 @@ typedef enum { } eV3DProjTest; +/* *** short *** */ eV3DProjStatus ED_view3d_project_short_ex(struct ARegion *ar, float perspmat[4][4], const int is_local, const float co[3], short r_co[2], eV3DProjTest flag); eV3DProjStatus ED_view3d_project_short_global(struct ARegion *ar, const float co[3], short r_co[2], eV3DProjTest flag); eV3DProjStatus ED_view3d_project_short_object(struct ARegion *ar, const float co[3], short r_co[2], eV3DProjTest flag); -void _ED_view3d_project_short(struct ARegion *ar, const float co[3], short r_co[2]); // V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN -void _ED_view3d_project_short_noclip(struct ARegion *ar, const float vec[3], short r_co[2]); // -void ED_view3d_project_int(struct ARegion *ar, const float co[3], int r_co[2]); -void ED_view3d_project_int_noclip(struct ARegion *ar, const float co[3], int r_co[2]); + +/* *** int *** */ +eV3DProjStatus ED_view3d_project_int_ex(struct ARegion *ar, float perspmat[4][4], const int is_local, + const float co[3], int r_co[2], eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_int_global(struct ARegion *ar, const float co[3], int r_co[2], eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_int_object(struct ARegion *ar, const float co[3], int r_co[2], eV3DProjTest flag); + void ED_view3d_project_float(struct ARegion *ar, const float co[3], float r_co[2]); void ED_view3d_project_float_noclip(struct ARegion *ar, const float co[3], float r_co[2]); void ED_view3d_project_float_v2_m4(const struct ARegion *a, const float co[3], float r_co[2], float mat[4][4]); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 6d3f4b38583..6c1d2e651cb 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -398,6 +398,8 @@ static void PE_set_view3d_data(bContext *C, PEData *data) /*************************** selection utilities *******************************/ +/* TODO, many of the callers to this function already have a 2d projection that + * could be passed as an arg, save calling ED_view3d_project_short_global again. */ static int key_test_depth(PEData *data, const float co[3]) { View3D *v3d= data->vc.v3d; @@ -448,11 +450,11 @@ static int key_inside_circle(PEData *data, float rad, const float co[3], float * float dx, dy, dist; int sco[2]; - ED_view3d_project_int(data->vc.ar, co, sco); - - if (sco[0] == IS_CLIPPED) + /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */ + if (ED_view3d_project_int_global(data->vc.ar, co, sco, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_SUCCESS) { return 0; - + } + dx= data->mval[0] - sco[0]; dy= data->mval[1] - sco[1]; dist= sqrt(dx*dx + dy*dy); @@ -474,10 +476,9 @@ static int key_inside_rect(PEData *data, const float co[3]) { int sco[2]; - ED_view3d_project_int(data->vc.ar, co, sco); - - if (sco[0] == IS_CLIPPED) + if (ED_view3d_project_int_global(data->vc.ar, co, sco, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_SUCCESS) { return 0; + } if (sco[0] > data->rect->xmin && sco[0] < data->rect->xmax && sco[1] > data->rect->ymin && sco[1] < data->rect->ymax) @@ -1667,8 +1668,8 @@ int PE_lasso_select(bContext *C, int mcords[][2], short moves, short extend, sho LOOP_KEYS { copy_v3_v3(co, key->co); mul_m4_v3(mat, co); - ED_view3d_project_int(ar, co, vertco); - if (BLI_lasso_is_point_inside(mcords, moves, vertco[0], vertco[1], IS_CLIPPED) && + if ((ED_view3d_project_int_global(ar, co, vertco, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) && + BLI_lasso_is_point_inside(mcords, moves, vertco[0], vertco[1], IS_CLIPPED) && key_test_depth(&data, co)) { if (select && !(key->flag & PEK_SELECT)) { @@ -1687,8 +1688,8 @@ int PE_lasso_select(bContext *C, int mcords[][2], short moves, short extend, sho copy_v3_v3(co, key->co); mul_m4_v3(mat, co); - ED_view3d_project_int(ar, co, vertco); - if (BLI_lasso_is_point_inside(mcords, moves, vertco[0], vertco[1], IS_CLIPPED) && + if ((ED_view3d_project_int_global(ar, co, vertco, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) && + BLI_lasso_is_point_inside(mcords, moves, vertco[0], vertco[1], IS_CLIPPED) && key_test_depth(&data, co)) { if (select && !(key->flag & PEK_SELECT)) { @@ -2799,11 +2800,13 @@ static void brush_cut(PEData *data, int pa_index) if (edit->points[pa_index].flag & PEP_HIDE) return; + if (ED_view3d_project_int_global(ar, key->co, vertco, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) + return; + rad2= data->rad * data->rad; cut=0; - ED_view3d_project_int_noclip(ar, key->co, vertco); x0= (float)vertco[0]; x1= (float)vertco[1]; @@ -2821,9 +2824,10 @@ static void brush_cut(PEData *data, int pa_index) else { /* calculate path time closest to root that was inside the circle */ for (k=1, key++; k<=keys; k++, key++) { - ED_view3d_project_int_noclip(ar, key->co, vertco); - if (key_test_depth(data, key->co) == 0) { + if ((ED_view3d_project_int_global(ar, key->co, vertco, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) || + key_test_depth(data, key->co) == 0) + { x0= (float)vertco[0]; x1= (float)vertco[1]; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 25ad85d3db8..cb197ab93b0 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -553,32 +553,23 @@ static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit) static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d) { - int mx, my, co[2]; - int flag; - + int co[2]; + /* we don't want the clipping for cursor */ - flag = v3d->flag; - v3d->flag = 0; - ED_view3d_project_int(ar, give_cursor(scene, v3d), co); - v3d->flag = flag; - - mx = co[0]; - my = co[1]; - - if (mx != IS_CLIPPED) { + if (ED_view3d_project_int_global(ar, give_cursor(scene, v3d), co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { setlinestyle(0); cpack(0xFF); - circ((float)mx, (float)my, 10.0); + circ((float)co[0], (float)co[1], 10.0); setlinestyle(4); cpack(0xFFFFFF); - circ((float)mx, (float)my, 10.0); + circ((float)co[0], (float)co[1], 10.0); setlinestyle(0); cpack(0x0); - sdrawline(mx - 20, my, mx - 5, my); - sdrawline(mx + 5, my, mx + 20, my); - sdrawline(mx, my - 20, mx, my - 5); - sdrawline(mx, my + 5, mx, my + 20); + sdrawline(co[0] - 20, co[1], co[0] - 5, co[1]); + sdrawline(co[0] + 5, co[1], co[0] + 20, co[1]); + sdrawline(co[0], co[1] - 20, co[0], co[1] - 5); + sdrawline(co[0], co[1] + 5, co[0], co[1] + 20); } } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index d3ff64c9f40..800b4ac53c8 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3524,12 +3524,14 @@ static int set_3dcursor_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *eve int mval[2]; // short ctrl= 0; // XXX int flip; + eV3DProjStatus ret; fp = give_cursor(scene, v3d); // if (obedit && ctrl) lr_click= 1; copy_v3_v3(oldcurs, fp); - ED_view3d_project_int_noclip(ar, fp, mval); + mval[0] = IS_CLIPPED; + ret = ED_view3d_project_int_global(ar, fp, mval, V3D_PROJ_TEST_NOP); flip = initgrabz(rv3d, fp[0], fp[1], fp[2]); /* reset the depth based on the view offset */ @@ -3537,7 +3539,8 @@ static int set_3dcursor_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *eve negate_v3_v3(fp, rv3d->ofs); /* re initialize */ - ED_view3d_project_int_noclip(ar, fp, mval); + mval[0] = IS_CLIPPED; + ED_view3d_project_int_global(ar, fp, mval, V3D_PROJ_TEST_NOP); flip = initgrabz(rv3d, fp[0], fp[1], fp[2]); (void)flip; } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index b31b932d71f..2332ca98a66 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -110,15 +110,16 @@ int view3d_get_view_aligned_coordinate(ViewContext *vc, float fp[3], const int m { float dvec[3]; int mval_cpy[2]; + eV3DProjStatus ret; mval_cpy[0] = mval[0]; mval_cpy[1] = mval[1]; - ED_view3d_project_int_noclip(vc->ar, fp, mval_cpy); + ret = ED_view3d_project_int_global(vc->ar, fp, mval_cpy, V3D_PROJ_TEST_NOP); initgrabz(vc->rv3d, fp[0], fp[1], fp[2]); - if (mval_cpy[0] != IS_CLIPPED) { + if (ret == V3D_PROJ_RET_SUCCESS) { const float mval_f[2] = {(float)(mval_cpy[0] - mval[0]), (float)(mval_cpy[1] - mval[1])}; ED_view3d_win_to_delta(vc->ar, mval_f, dvec); @@ -333,10 +334,14 @@ static void do_lasso_select_pose(ViewContext *vc, Object *ob, int mcords[][2], s for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (PBONE_VISIBLE(arm, pchan->bone) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) { + + /* XXX, todo, use ED_view3d_project_int_object */ + sco1[0] = sco2[0] = IS_CLIPPED; + mul_v3_m4v3(vec, ob->obmat, pchan->pose_head); - ED_view3d_project_int(vc->ar, vec, sco1); + ED_view3d_project_int_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); mul_v3_m4v3(vec, ob->obmat, pchan->pose_tail); - ED_view3d_project_int(vc->ar, vec, sco2); + ED_view3d_project_int_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); if (BLI_lasso_is_edge_inside(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1], IS_CLIPPED)) { if (select) pchan->bone->flag |= BONE_SELECTED; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 2ed8048fee4..b3dd54c6261 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -971,6 +971,26 @@ eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], con return ret; } +eV3DProjStatus ED_view3d_project_int_ex(ARegion *ar, float perspmat[4][4], const int is_local, + const float co[3], int r_co[2], eV3DProjTest flag) +{ + float tvec[2]; + eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag); + if (ret == V3D_PROJ_RET_SUCCESS) { + if ((tvec[0] > -2140000000.0 && tvec[0] < 2140000000.0f) && + (tvec[1] > -2140000000.0 && tvec[1] < 2140000000.0f)) + { + r_co[0] = (int)floor(tvec[0]); + r_co[1] = (int)floor(tvec[1]); + } + else { + return V3D_PROJ_RET_OVERFLOW; + } + } + return ret; +} + +/* --- short --- */ eV3DProjStatus ED_view3d_project_short_global(ARegion *ar, const float co[3], short r_co[2], eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; @@ -983,52 +1003,17 @@ eV3DProjStatus ED_view3d_project_short_object(ARegion *ar, const float co[3], sh return ED_view3d_project_short_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); } -void ED_view3d_project_int(ARegion *ar, const float co[3], int r_co[2]) +/* --- int --- */ +eV3DProjStatus ED_view3d_project_int_global(ARegion *ar, const float co[3], int r_co[2], eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; - float fx, fy, vec4[4]; - - copy_v3_v3(vec4, co); - vec4[3] = 1.0; - r_co[0] = (int)2140000000.0f; - - mul_m4_v4(rv3d->persmat, vec4); - - if (vec4[3] > (float)BL_NEAR_CLIP) { - fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]); - - if (fx > -2140000000.0f && fx < 2140000000.0f) { - fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]); - - if (fy > -2140000000.0f && fy < 2140000000.0f) { - r_co[0] = (int)floor(fx); - r_co[1] = (int)floor(fy); - } - } - } + return ED_view3d_project_int_ex(ar, rv3d->persmat, FALSE, co, r_co, flag); } - -void ED_view3d_project_int_noclip(ARegion *ar, const float co[3], int r_co[2]) +/* object space, use ED_view3d_init_mats_rv3d before calling */ +eV3DProjStatus ED_view3d_project_int_object(ARegion *ar, const float co[3], int r_co[2], eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; - float fx, fy, vec4[4]; - - copy_v3_v3(vec4, co); - vec4[3] = 1.0; - - mul_m4_v4(rv3d->persmat, vec4); - - if (fabs(vec4[3]) > BL_NEAR_CLIP) { - fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]); - fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]); - - r_co[0] = (int)floor(fx); - r_co[1] = (int)floor(fy); - } - else { - r_co[0] = ar->winx / 2; - r_co[1] = ar->winy / 2; - } + return ED_view3d_project_int_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); } void ED_view3d_project_float(ARegion *ar, const float co[3], float r_co[2]) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 343fa6681f3..32392b2fd66 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -225,8 +225,12 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy) void projectIntView(TransInfo *t, const float vec[3], int adr[2]) { if (t->spacetype == SPACE_VIEW3D) { - if (t->ar->regiontype == RGN_TYPE_WINDOW) - ED_view3d_project_int_noclip(t->ar, vec, adr); + if (t->ar->regiontype == RGN_TYPE_WINDOW) { + if (ED_view3d_project_int_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) { + adr[0] = (int)2140000000.0f; /* this is what was done in 2.64, perhaps we can be smarter? */ + adr[1] = (int)2140000000.0f; + } + } } else if (t->spacetype == SPACE_IMAGE) { SpaceImage *sima = t->sa->spacedata.first; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 1d75be05534..cee1c91abe7 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -601,7 +601,9 @@ int updateSelectedSnapPoint(TransInfo *t) int dx, dy; int dist; - ED_view3d_project_int(t->ar, p->co, screen_loc); + if (ED_view3d_project_int_global(t->ar, p->co, screen_loc, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) { + continue; + } dx = t->mval[0] - screen_loc[0]; dy = t->mval[1] - screen_loc[1]; @@ -1232,8 +1234,12 @@ static int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], sh new_depth = len_v3v3(location, ray_start); - ED_view3d_project_int(ar, location, screen_loc); - new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]); + if (ED_view3d_project_int_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]); + } + else { + new_dist = 1000; + } /* 10% threshold if edge is closer but a bit further * this takes care of series of connected edges a bit slanted w.r.t the viewport @@ -1289,8 +1295,13 @@ static int snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[][4], new_depth = len_v3v3(location, ray_start); - ED_view3d_project_int(ar, location, screen_loc); - new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]); + if (ED_view3d_project_int_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]); + } + else { + new_dist = 1000; + } + if (new_dist <= *r_dist && new_depth < *r_depth) { *r_depth = new_depth; From ab2a9de4b485362725660db840cba40837114c89 Mon Sep 17 00:00:00 2001 From: "Sv. Lockal" Date: Thu, 4 Oct 2012 18:21:34 +0000 Subject: [PATCH 078/143] Add translation context for volume (Audio), pitch (Rotation) and rename tip->tooltip for custom properties Tracked in [#31062] [2.6x] Context Ambiguity List & Discussion (keep updating) --- release/scripts/startup/bl_operators/wm.py | 2 +- source/blender/makesrna/intern/rna_actuator.c | 1 + source/blender/makesrna/intern/rna_boid.c | 1 + source/blender/makesrna/intern/rna_scene.c | 2 ++ source/blender/makesrna/intern/rna_sequencer.c | 1 + source/blender/makesrna/intern/rna_speaker.c | 1 + 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 07d4096632f..21843d80742 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -1028,7 +1028,7 @@ class WM_OT_properties_edit(Operator): min = rna_min max = rna_max description = StringProperty( - name="Tip", + name="Tooltip", ) def execute(self, context): diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 12a41f213b7..59e6c367bf6 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -971,6 +971,7 @@ static void rna_def_sound_actuator(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 2); RNA_def_property_range(prop, 0.0, 2.0); RNA_def_property_ui_text(prop, "Volume", "Initial volume of the sound"); + RNA_def_property_translation_context(prop, "Audio"); RNA_def_property_update(prop, NC_LOGIC, NULL); prop = RNA_def_property(srna, "pitch", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c index 2a6ea2994fa..94ab4497e54 100644 --- a/source/blender/makesrna/intern/rna_boid.c +++ b/source/blender/makesrna/intern/rna_boid.c @@ -521,6 +521,7 @@ static void rna_def_boid_settings(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "pitch"); RNA_def_property_range(prop, 0.0, 2.0); RNA_def_property_ui_text(prop, "Pitch", "Amount of rotation around side vector"); + RNA_def_property_translation_context(prop, "Rotation"); RNA_def_property_update(prop, 0, "rna_Boids_reset"); prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index c11051d2a2e..fc497642855 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3106,6 +3106,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Volume", "Audio volume"); + RNA_def_property_translation_context(prop, "Audio"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); #endif @@ -4517,6 +4518,7 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "audio.volume"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Volume", "Audio volume"); + RNA_def_property_translation_context(prop, "Audio"); RNA_def_property_update(prop, NC_SCENE, NULL); RNA_def_property_float_funcs(prop, NULL, "rna_Scene_volume_set", NULL); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 432e3841ad8..5c6d05dc9a2 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1858,6 +1858,7 @@ static void rna_def_sound(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "volume"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text(prop, "Volume", "Playback volume of the sound"); + RNA_def_property_translation_context(prop, "Audio"); RNA_def_property_float_funcs(prop, NULL, "rna_Sequence_volume_set", NULL); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); diff --git a/source/blender/makesrna/intern/rna_speaker.c b/source/blender/makesrna/intern/rna_speaker.c index 1e3c8df9273..6c226489ad7 100644 --- a/source/blender/makesrna/intern/rna_speaker.c +++ b/source/blender/makesrna/intern/rna_speaker.c @@ -151,6 +151,7 @@ static void rna_def_speaker(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "volume"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Volume", "How loud the sound is"); + RNA_def_property_translation_context(prop, "Audio"); /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_set", NULL); */ /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ From 63840fd5058293e7bc9f16cea16507a410748b50 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 4 Oct 2012 18:30:28 +0000 Subject: [PATCH 079/143] Fix #32755: Stripes in Metastrip can not be moved on other channel with mouse (grab tool) The issue was caused by SEQ_BEGIN macro modifying sequence's depth which ruined transformation routines. Used own DFS instead which doesn't modify sequences. Also corrected some typos in api and comments. --- source/blender/blenkernel/BKE_sequencer.h | 22 ++++---- source/blender/blenkernel/intern/image.c | 2 +- source/blender/blenkernel/intern/sequencer.c | 53 +++++++++++-------- .../blenloader/intern/versioning_250.c | 2 +- .../editors/space_sequencer/sequencer_add.c | 8 +-- .../editors/space_sequencer/sequencer_draw.c | 2 +- .../editors/space_sequencer/sequencer_edit.c | 12 ++--- .../space_sequencer/sequencer_select.c | 8 +-- .../editors/transform/transform_generics.c | 18 ++++--- .../blender/makesrna/intern/rna_sequencer.c | 2 +- .../makesrna/intern/rna_sequencer_api.c | 2 +- 11 files changed, 73 insertions(+), 58 deletions(-) diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 0c571f62f0e..cecff2d9516 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -64,29 +64,29 @@ typedef struct SeqIterator { int valid; } SeqIterator; -void BKE_seqence_iterator_begin(struct Editing *ed, SeqIterator *iter, int use_pointer); -void BKE_seqence_iterator_next(SeqIterator *iter); -void BKE_seqence_iterator_end(SeqIterator *iter); +void BKE_sequence_iterator_begin(struct Editing *ed, SeqIterator *iter, int use_pointer); +void BKE_sequence_iterator_next(SeqIterator *iter); +void BKE_sequence_iterator_end(SeqIterator *iter); #define SEQP_BEGIN(ed, _seq) \ { \ SeqIterator iter; \ - for (BKE_seqence_iterator_begin(ed, &iter, 1); \ + for (BKE_sequence_iterator_begin(ed, &iter, 1); \ iter.valid; \ - BKE_seqence_iterator_next(&iter)) { \ + BKE_sequence_iterator_next(&iter)) { \ _seq = iter.seq; #define SEQ_BEGIN(ed, _seq) \ { \ SeqIterator iter; \ - for (BKE_seqence_iterator_begin(ed, &iter, 0); \ + for (BKE_sequence_iterator_begin(ed, &iter, 0); \ iter.valid; \ - BKE_seqence_iterator_next(&iter)) { \ + BKE_sequence_iterator_next(&iter)) { \ _seq = iter.seq; #define SEQ_END \ } \ - BKE_seqence_iterator_end(&iter); \ + BKE_sequence_iterator_end(&iter); \ } typedef struct SeqRenderData { @@ -307,7 +307,7 @@ int BKE_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char int BKE_sequence_check_depend(struct Sequence *seq, struct Sequence *cur); void BKE_sequence_invalidate_cache(struct Scene *scene, struct Sequence *seq); -void BKE_sequence_invalidate_deendent(struct Scene *scene, struct Sequence *seq); +void BKE_sequence_invalidate_dependent(struct Scene *scene, struct Sequence *seq); void BKE_sequence_invalidate_cache_for_modifier(struct Scene *scene, struct Sequence *seq); void BKE_sequencer_update_sound_bounds_all(struct Scene *scene); @@ -315,9 +315,9 @@ void BKE_sequencer_update_sound_bounds(struct Scene *scene, struct Sequence *seq void BKE_sequencer_update_muting(struct Editing *ed); void BKE_sequencer_update_sound(struct Scene *scene, struct bSound *sound); -void BKE_seqence_base_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq); +void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq); void BKE_sequence_base_dupli_recursive(struct Scene *scene, struct Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, int dupe_flag); -int BKE_seqence_is_valid_check(struct Sequence *seq); +int BKE_sequence_is_valid_check(struct Sequence *seq); void BKE_sequencer_clear_scene_in_allseqs(struct Main *bmain, struct Scene *sce); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 3d3afa7c4b3..c003a86a0b7 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2563,7 +2563,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ *lock_r = re; } - /* this gives active layer, composite or seqence result */ + /* this gives active layer, composite or sequence result */ rect = (unsigned int *)rres.rect32; rectf = rres.rectf; rectz = rres.rectz; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 37f32a12111..90c3347a1df 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -461,7 +461,7 @@ static void seq_array(Editing *ed, Sequence ***seqarray, int *tot, int use_point seq_build_array(&ed->seqbase, &array, 0); } -void BKE_seqence_iterator_begin(Editing *ed, SeqIterator *iter, int use_pointer) +void BKE_sequence_iterator_begin(Editing *ed, SeqIterator *iter, int use_pointer) { memset(iter, 0, sizeof(*iter)); seq_array(ed, &iter->array, &iter->tot, use_pointer); @@ -473,7 +473,7 @@ void BKE_seqence_iterator_begin(Editing *ed, SeqIterator *iter, int use_pointer) } } -void BKE_seqence_iterator_next(SeqIterator *iter) +void BKE_sequence_iterator_next(SeqIterator *iter) { if (++iter->cur < iter->tot) iter->seq = iter->array[iter->cur]; @@ -481,7 +481,7 @@ void BKE_seqence_iterator_next(SeqIterator *iter) iter->valid = 0; } -void BKE_seqence_iterator_end(SeqIterator *iter) +void BKE_sequence_iterator_end(SeqIterator *iter) { if (iter->array) MEM_freeN(iter->array); @@ -843,7 +843,7 @@ static int seqbase_unique_name_recursive_cb(Sequence *seq, void *arg_pt) return 1; } -void BKE_seqence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq) +void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq) { SeqUniqueInfo sui; char *dot; @@ -3032,10 +3032,27 @@ int BKE_sequence_check_depend(Sequence *seq, Sequence *cur) return TRUE; } +static void sequence_do_invalidate_dependent(Sequence *seq, ListBase *seqbase) +{ + Sequence *cur; + + for (cur = seqbase->first; cur; cur = cur->next) { + if (cur == seq) + continue; + + if (BKE_sequence_check_depend(seq, cur)) { + BKE_sequencer_cache_cleanup_sequence(cur); + BKE_sequencer_preprocessed_cache_cleanup_sequence(cur); + } + + if (cur->seqbase.first) + sequence_do_invalidate_dependent(seq, &cur->seqbase); + } +} + static void sequence_invalidate_cache(Scene *scene, Sequence *seq, int invalidate_self, int invalidate_preprocess) { Editing *ed = scene->ed; - Sequence *cur; /* invalidate cache for current sequence */ if (invalidate_self) @@ -3049,17 +3066,11 @@ static void sequence_invalidate_cache(Scene *scene, Sequence *seq, int invalidat BKE_sequencer_preprocessed_cache_cleanup_sequence(seq); /* invalidate cache for all dependent sequences */ - SEQ_BEGIN (ed, cur) - { - if (cur == seq) - continue; - if (BKE_sequence_check_depend(seq, cur)) { - BKE_sequencer_cache_cleanup_sequence(cur); - BKE_sequencer_preprocessed_cache_cleanup_sequence(cur); - } - } - SEQ_END + /* NOTE: can not use SEQ_BEGIN/SEQ_END here because that macro will change sequence's depth, + * which makes transformation routines work incorrect + */ + sequence_do_invalidate_dependent(seq, &ed->seqbase); } void BKE_sequence_invalidate_cache(Scene *scene, Sequence *seq) @@ -3067,7 +3078,7 @@ void BKE_sequence_invalidate_cache(Scene *scene, Sequence *seq) sequence_invalidate_cache(scene, seq, TRUE, TRUE); } -void BKE_sequence_invalidate_deendent(Scene *scene, Sequence *seq) +void BKE_sequence_invalidate_dependent(Scene *scene, Sequence *seq) { sequence_invalidate_cache(scene, seq, FALSE, TRUE); } @@ -3872,7 +3883,7 @@ static void seq_load_apply(Scene *scene, Sequence *seq, SeqLoadInfo *seq_load) { if (seq) { BLI_strncpy(seq->name + 2, seq_load->name, sizeof(seq->name) - 2); - BKE_seqence_base_unique_name_recursive(&scene->ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); if (seq_load->flag & SEQ_LOAD_FRAME_ADVANCE) { seq_load->start_frame += (seq->enddisp - seq->startdisp); @@ -3983,7 +3994,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad seq->type = SEQ_TYPE_SOUND_RAM; seq->sound = sound; BLI_strncpy(seq->name + 2, "Sound", SEQ_NAME_MAXSTR - 2); - BKE_seqence_base_unique_name_recursive(&scene->ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); /* basic defaults */ seq->strip = strip = MEM_callocN(sizeof(Strip), "strip"); @@ -4043,7 +4054,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad seq->anim = an; seq->anim_preseek = IMB_anim_get_preseek(an); BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2); - BKE_seqence_base_unique_name_recursive(&scene->ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); /* basic defaults */ seq->strip = strip = MEM_callocN(sizeof(Strip), "strip"); @@ -4155,7 +4166,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup } if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) - BKE_seqence_base_unique_name_recursive(&scene->ed->seqbase, seqn); + BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqn); if (dupe_flag & SEQ_DUPE_ANIM) BKE_sequencer_dupe_animdata(scene, seq->name + 2, seqn->name + 2); @@ -4210,7 +4221,7 @@ void BKE_sequence_base_dupli_recursive(Scene *scene, Scene *scene_to, ListBase * /* called on draw, needs to be fast, * we could cache and use a flag if we want to make checks for file paths resolving for eg. */ -int BKE_seqence_is_valid_check(Sequence *seq) +int BKE_sequence_is_valid_check(Sequence *seq) { switch (seq->type) { case SEQ_TYPE_MASK: diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index a4f190c8167..a3cfa4413a8 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -652,7 +652,7 @@ static void do_versions_seq_unique_name_all_strips(Scene * sce, ListBase *seqbas Sequence * seq = seqbasep->first; while (seq) { - BKE_seqence_base_unique_name_recursive(&sce->ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&sce->ed->seqbase, seq); if (seq->seqbase.first) { do_versions_seq_unique_name_all_strips(sce, &seq->seqbase); } diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 7b7170d99e0..ff895c06d57 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -242,7 +242,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) strip->us = 1; BLI_strncpy(seq->name + 2, sce_seq->id.name + 2, sizeof(seq->name) - 2); - BKE_seqence_base_unique_name_recursive(&ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); seq->scene_sound = sound_scene_add_scene_sound(scene, seq, start_frame, start_frame + seq->len, 0); @@ -343,7 +343,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op) strip->us = 1; BLI_strncpy(seq->name + 2, clip->id.name + 2, sizeof(seq->name) - 2); - BKE_seqence_base_unique_name_recursive(&ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); BKE_sequence_calc_disp(scene, seq); BKE_sequencer_sort(scene); @@ -439,7 +439,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op) strip->us = 1; BLI_strncpy(seq->name + 2, mask->id.name + 2, sizeof(seq->name) - 2); - BKE_seqence_base_unique_name_recursive(&ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); BKE_sequence_calc_disp(scene, seq); BKE_sequencer_sort(scene); @@ -820,7 +820,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) seq->type = type; BLI_strncpy(seq->name + 2, BKE_sequence_give_name(seq), sizeof(seq->name) - 2); - BKE_seqence_base_unique_name_recursive(&ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); sh = BKE_sequence_get_effect(seq); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index c72bff12056..7bec530fae9 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -747,7 +747,7 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline glDisable(GL_BLEND); } - if (!BKE_seqence_is_valid_check(seq)) { + if (!BKE_sequence_is_valid_check(seq)) { glEnable(GL_POLYGON_STIPPLE); /* panic! */ diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index e7d964ba715..204930e82a6 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1143,13 +1143,13 @@ static int sequencer_mute_exec(bContext *C, wmOperator *op) if (selected) { /* mute unselected */ if (seq->flag & SELECT) { seq->flag |= SEQ_MUTE; - BKE_sequence_invalidate_deendent(scene, seq); + BKE_sequence_invalidate_dependent(scene, seq); } } else { if ((seq->flag & SELECT) == 0) { seq->flag |= SEQ_MUTE; - BKE_sequence_invalidate_deendent(scene, seq); + BKE_sequence_invalidate_dependent(scene, seq); } } } @@ -1194,13 +1194,13 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op) if (selected) { /* unmute unselected */ if (seq->flag & SELECT) { seq->flag &= ~SEQ_MUTE; - BKE_sequence_invalidate_deendent(scene, seq); + BKE_sequence_invalidate_dependent(scene, seq); } } else { if ((seq->flag & SELECT) == 0) { seq->flag &= ~SEQ_MUTE; - BKE_sequence_invalidate_deendent(scene, seq); + BKE_sequence_invalidate_dependent(scene, seq); } } } @@ -1573,7 +1573,7 @@ static int apply_unique_name_cb(Sequence *seq, void *arg_pt) char name[sizeof(seq->name) - 2]; strcpy(name, seq->name + 2); - BKE_seqence_base_unique_name_recursive(&scene->ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); BKE_sequencer_dupe_animdata(scene, name, seq->name + 2); return 1; @@ -1968,7 +1968,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) BKE_sequencer_update_muting(ed); - BKE_seqence_base_unique_name_recursive(&scene->ed->seqbase, seqm); + BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqm); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 3d57f2f88ed..be33b782fdf 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -1109,7 +1109,7 @@ static short select_grouped_effect_link(Editing *ed, Sequence *actseq) actseq->tmp = SET_INT_IN_POINTER(TRUE); - for (BKE_seqence_iterator_begin(ed, &iter, TRUE); iter.valid; BKE_seqence_iterator_next(&iter)) { + for (BKE_sequence_iterator_begin(ed, &iter, TRUE); iter.valid; BKE_sequence_iterator_next(&iter)) { seq = iter.seq; /* Ignore all seqs already selected! */ @@ -1137,8 +1137,8 @@ static short select_grouped_effect_link(Editing *ed, Sequence *actseq) changed = TRUE; /* Unfortunately, we must restart checks from the beginning. */ - BKE_seqence_iterator_end(&iter); - BKE_seqence_iterator_begin(ed, &iter, TRUE); + BKE_sequence_iterator_end(&iter); + BKE_sequence_iterator_begin(ed, &iter, TRUE); } /* Video strips bellow active one, or any strip for audio (order do no matters here!). */ @@ -1147,7 +1147,7 @@ static short select_grouped_effect_link(Editing *ed, Sequence *actseq) changed = TRUE; } } - BKE_seqence_iterator_end(&iter); + BKE_sequence_iterator_end(&iter); return changed; } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index b8db0b575cf..a9d9ec7b010 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -895,16 +895,20 @@ static void recalcData_view3d(TransInfo *t) /* helper for recalcData() - for sequencer transforms */ static void recalcData_sequencer(TransInfo *t) { - Editing *ed = BKE_sequencer_editing_get(t->scene, FALSE); - Sequence *seq; + TransData *td; + int a; + Sequence *seq_prev = NULL; - SEQ_BEGIN(ed, seq) - { - if (seq->flag & SELECT) { - BKE_sequence_invalidate_deendent(t->scene, seq); + for (a = 0, td = t->data; a < t->total; a++, td++) { + TransDataSeq *tdsq = (TransDataSeq *) td->extra; + Sequence *seq = tdsq->seq; + + if (seq != seq_prev) { + BKE_sequence_invalidate_dependent(t->scene, seq); } + + seq_prev = seq; } - SEQ_END BKE_sequencer_preprocessed_cache_cleanup(); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 5c6d05dc9a2..e3ef2621745 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -405,7 +405,7 @@ static void rna_Sequence_name_set(PointerRNA *ptr, const char *value) BLI_strncpy_utf8(seq->name + 2, value, sizeof(seq->name) - 2); /* make sure the name is unique */ - BKE_seqence_base_unique_name_recursive(&scene->ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); /* fix all the animation data which may link to this */ diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index c7c4b0817f6..f63ef6c8d76 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -81,7 +81,7 @@ static Sequence *alloc_generic_sequence(Editing *ed, const char *name, int start seq->type = type; BLI_strncpy(seq->name + 2, name, sizeof(seq->name) - 2); - BKE_seqence_base_unique_name_recursive(&ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); seq->strip = strip = MEM_callocN(sizeof(Strip), "strip"); seq->strip->us = 1; From 592f80625bec2d31b22e3e309df9bb693eb967f3 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 4 Oct 2012 18:53:17 +0000 Subject: [PATCH 080/143] Fix for commit r51049: no need to create two contexts when one if enough. Also please define and use constants in BLF_translation.h rather than directly typing contexts' names, it's safer (typo would break at compile time, instead of generating more contexts!). --- source/blender/blenfont/BLF_translation.h | 2 ++ source/blender/makesrna/intern/rna_actuator.c | 5 ++++- source/blender/makesrna/intern/rna_boid.c | 1 - source/blender/makesrna/intern/rna_scene.c | 2 +- source/blender/makesrna/intern/rna_sequencer.c | 5 ++++- source/blender/makesrna/intern/rna_speaker.c | 6 ++++-- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/source/blender/blenfont/BLF_translation.h b/source/blender/blenfont/BLF_translation.h index 56eabf4bb43..278c45dac52 100644 --- a/source/blender/blenfont/BLF_translation.h +++ b/source/blender/blenfont/BLF_translation.h @@ -97,6 +97,8 @@ const char *BLF_translate_do_tooltip(const char *contex, const char *msgid); /* Default context for operator names/labels. */ #define BLF_I18NCONTEXT_OPERATOR_DEFAULT "Operator" +/* Audio disambiguation context. */ +#define BLF_I18NCONTEXT_AUDIO "Audio" #endif /* __BLF_TRANSLATION_H__ */ diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 59e6c367bf6..b1fdfccd0be 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -41,6 +41,8 @@ #include "BLI_utildefines.h" +#include "BLF_translation.h" + /* Always keep in alphabetical order */ EnumPropertyItem actuator_type_items[] = { {ACT_ACTION, "ACTION", 0, "Action", ""}, @@ -971,12 +973,13 @@ static void rna_def_sound_actuator(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 2); RNA_def_property_range(prop, 0.0, 2.0); RNA_def_property_ui_text(prop, "Volume", "Initial volume of the sound"); - RNA_def_property_translation_context(prop, "Audio"); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_AUDIO); RNA_def_property_update(prop, NC_LOGIC, NULL); prop = RNA_def_property(srna, "pitch", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_range(prop, -12.0, 12.0, 1, 2); RNA_def_property_ui_text(prop, "Pitch", "Pitch of the sound"); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_AUDIO); RNA_def_property_update(prop, NC_LOGIC, NULL); /* floats - 3D Parameters */ diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c index 94ab4497e54..2a6ea2994fa 100644 --- a/source/blender/makesrna/intern/rna_boid.c +++ b/source/blender/makesrna/intern/rna_boid.c @@ -521,7 +521,6 @@ static void rna_def_boid_settings(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "pitch"); RNA_def_property_range(prop, 0.0, 2.0); RNA_def_property_ui_text(prop, "Pitch", "Amount of rotation around side vector"); - RNA_def_property_translation_context(prop, "Rotation"); RNA_def_property_update(prop, 0, "rna_Boids_reset"); prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index fc497642855..a3616e0845a 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4518,7 +4518,7 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "audio.volume"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Volume", "Audio volume"); - RNA_def_property_translation_context(prop, "Audio"); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_AUDIO); RNA_def_property_update(prop, NC_SCENE, NULL); RNA_def_property_float_funcs(prop, NULL, "rna_Scene_volume_set", NULL); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index e3ef2621745..d8ca1aea5dd 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -50,6 +50,8 @@ #include "WM_types.h" #include "BLI_math.h" +#include "BLF_translation.h" + typedef struct EffectInfo { const char *struct_name; const char *ui_name; @@ -1858,7 +1860,7 @@ static void rna_def_sound(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "volume"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text(prop, "Volume", "Playback volume of the sound"); - RNA_def_property_translation_context(prop, "Audio"); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_AUDIO); RNA_def_property_float_funcs(prop, NULL, "rna_Sequence_volume_set", NULL); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); @@ -1866,6 +1868,7 @@ static void rna_def_sound(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "pitch"); RNA_def_property_range(prop, 0.1f, 10.0f); RNA_def_property_ui_text(prop, "Pitch", "Playback pitch of the sound"); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_AUDIO); RNA_def_property_float_funcs(prop, NULL, "rna_Sequence_pitch_set", NULL); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); diff --git a/source/blender/makesrna/intern/rna_speaker.c b/source/blender/makesrna/intern/rna_speaker.c index 6c226489ad7..a160aaf94e2 100644 --- a/source/blender/makesrna/intern/rna_speaker.c +++ b/source/blender/makesrna/intern/rna_speaker.c @@ -35,6 +35,8 @@ #include "DNA_speaker_types.h" #include "DNA_sound_types.h" +#include "BLF_translation.h" + #ifdef RNA_RUNTIME #include "MEM_guardedalloc.h" @@ -45,7 +47,6 @@ #include "WM_api.h" #include "WM_types.h" - #else static void rna_def_speaker(BlenderRNA *brna) @@ -151,7 +152,7 @@ static void rna_def_speaker(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "volume"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Volume", "How loud the sound is"); - RNA_def_property_translation_context(prop, "Audio"); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_AUDIO); /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_set", NULL); */ /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ @@ -159,6 +160,7 @@ static void rna_def_speaker(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "pitch"); RNA_def_property_range(prop, 0.1f, 10.0f); RNA_def_property_ui_text(prop, "Pitch", "Playback pitch of the sound"); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_AUDIO); /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_pitch_set", NULL); */ /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ From 2a08c0dc5620dd126da54f36a48402d34f83a00c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 4 Oct 2012 20:11:54 +0000 Subject: [PATCH 081/143] Code cleanup: fix some clang checker warnings. --- intern/opennl/intern/opennl.c | 15 +++--- intern/opennl/superlu/get_perm_c.c | 52 ++++++++++--------- .../blender/editors/space_image/image_edit.c | 2 + 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/intern/opennl/intern/opennl.c b/intern/opennl/intern/opennl.c index 71809cc7480..f9c63e9ecf6 100644 --- a/intern/opennl/intern/opennl.c +++ b/intern/opennl/intern/opennl.c @@ -137,14 +137,14 @@ static void __nl_should_not_have_reached(char* file, int line) { /************************************************************************************/ /* memory management */ -#define __NL_NEW(T) (T*)(calloc(1, sizeof(T))) -#define __NL_NEW_ARRAY(T,NB) (T*)(calloc((NB),sizeof(T))) +#define __NL_NEW(T) (T*)(calloc(1, sizeof(T))) +#define __NL_NEW_ARRAY(T,NB) (T*)(calloc(MAX(NB, 1),sizeof(T))) #define __NL_RENEW_ARRAY(T,x,NB) (T*)(realloc(x,(NB)*sizeof(T))) -#define __NL_DELETE(x) free(x); x = NULL -#define __NL_DELETE_ARRAY(x) free(x); x = NULL +#define __NL_DELETE(x) if(x) free(x); x = NULL +#define __NL_DELETE_ARRAY(x) if(x) free(x); x = NULL -#define __NL_CLEAR(T, x) memset(x, 0, sizeof(T)) -#define __NL_CLEAR_ARRAY(T,x,NB) memset(x, 0, (NB)*sizeof(T)) +#define __NL_CLEAR(T, x) memset(x, 0, sizeof(T)) +#define __NL_CLEAR_ARRAY(T,x,NB) if(NB) memset(x, 0, (NB)*sizeof(T)) /************************************************************************************/ /* Dynamic arrays for sparse row/columns */ @@ -1042,6 +1042,9 @@ static NLboolean __nlFactorize_SUPERLU(__NLContext *context, NLint *permutation) NLuint n = context->n; NLuint nnz = __nlSparseMatrixNNZ(M); /* number of non-zero coeffs */ + /*if(n > 10) + n = 10;*/ + /* Compressed Row Storage matrix representation */ NLint *xa = __NL_NEW_ARRAY(NLint, n+1); NLfloat *rhs = __NL_NEW_ARRAY(NLfloat, n); diff --git a/intern/opennl/superlu/get_perm_c.c b/intern/opennl/superlu/get_perm_c.c index 320fe3471f4..59889645988 100644 --- a/intern/opennl/superlu/get_perm_c.c +++ b/intern/opennl/superlu/get_perm_c.c @@ -173,17 +173,19 @@ getata( /* Flag the diagonal so it's not included in the B matrix */ marker[j] = j; - for (i = colptr[j]; i < colptr[j+1]; ++i) { - /* A_kj is nonzero, add pattern of column T_*k to B_*j */ - k = rowind[i]; - for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) { - trow = t_rowind[ti]; - if ( marker[trow] != j ) { - marker[trow] = j; - b_rowind[num_nz++] = trow; + if ( *atanz ) { + for (i = colptr[j]; i < colptr[j+1]; ++i) { + /* A_kj is nonzero, add pattern of column T_*k to B_*j */ + k = rowind[i]; + for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) { + trow = t_rowind[ti]; + if ( marker[trow] != j ) { + marker[trow] = j; + b_rowind[num_nz++] = trow; + } + } + } } - } - } } b_colptr[n] = num_nz; @@ -305,21 +307,23 @@ at_plus_a( marker[j] = j; /* Add pattern of column A_*k to B_*j */ - for (i = colptr[j]; i < colptr[j+1]; ++i) { - k = rowind[i]; - if ( marker[k] != j ) { - marker[k] = j; - (*b_rowind)[num_nz++] = k; - } - } + if (*bnz) { + for (i = colptr[j]; i < colptr[j+1]; ++i) { + k = rowind[i]; + if ( marker[k] != j ) { + marker[k] = j; + (*b_rowind)[num_nz++] = k; + } + } - /* Add pattern of column T_*k to B_*j */ - for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) { - k = t_rowind[i]; - if ( marker[k] != j ) { - marker[k] = j; - (*b_rowind)[num_nz++] = k; - } + /* Add pattern of column T_*k to B_*j */ + for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) { + k = t_rowind[i]; + if ( marker[k] != j ) { + marker[k] = j; + (*b_rowind)[num_nz++] = k; + } + } } } (*b_colptr)[n] = num_nz; diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index 0d40a6ae007..2f01483d23f 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -120,6 +120,8 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r) if (ibuf && (ibuf->rect || ibuf->rect_float)) return ibuf; } + else + *lock_r = NULL; return NULL; } From 79b4c0e600c2f2fe539a0602bf752b62210815d6 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 4 Oct 2012 20:12:05 +0000 Subject: [PATCH 082/143] UI: buttons that open menus now align to the menu rather than looking disconnected. Also fixed some cases where the menu was offset 1 or 2 pixels wrong, though not quite all of them, still off by 1 pixel sometimes. http://www.pasteall.org/pic/show.php?id=38478 --- source/blender/editors/include/UI_interface.h | 1 - source/blender/editors/interface/interface.c | 33 ++++------- .../editors/interface/interface_handlers.c | 10 ++++ .../editors/interface/interface_intern.h | 5 +- .../editors/interface/interface_regions.c | 15 +++-- .../editors/interface/interface_widgets.c | 58 ++++++++++++++----- 6 files changed, 76 insertions(+), 46 deletions(-) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 32132f497a8..5d2709f0488 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -421,7 +421,6 @@ void uiBlockSetDirection(uiBlock *block, int direction); void uiBlockFlipOrder(uiBlock *block); void uiBlockSetFlag(uiBlock *block, int flag); void uiBlockClearFlag(uiBlock *block, int flag); -void uiBlockSetXOfs(uiBlock *block, int xofs); int uiButGetRetVal(uiBut *but); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 810cbc25862..2c00e39766c 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -996,24 +996,20 @@ void ui_fontscale(short *points, float aspect) /* project button or block (but==NULL) to pixels in regionspace */ static void ui_but_to_pixelrect(rcti *rect, const ARegion *ar, uiBlock *block, uiBut *but) { - float gx, gy; - float getsizex, getsizey; + rctf rectf = (but)? but->rect: block->rect; - getsizex = ar->winx; - getsizey = ar->winy; + ui_block_to_window_fl(ar, block, &rectf.xmin, &rectf.ymin); + ui_block_to_window_fl(ar, block, &rectf.xmax, &rectf.ymax); - gx = (but ? but->rect.xmin : block->rect.xmin) + (block->panel ? block->panel->ofsx : 0.0f); - gy = (but ? but->rect.ymin : block->rect.ymin) + (block->panel ? block->panel->ofsy : 0.0f); - - rect->xmin = floorf(getsizex * (0.5f + 0.5f * (gx * block->winmat[0][0] + gy * block->winmat[1][0] + block->winmat[3][0]))); - rect->ymin = floorf(getsizey * (0.5f + 0.5f * (gx * block->winmat[0][1] + gy * block->winmat[1][1] + block->winmat[3][1]))); - - gx = (but ? but->rect.xmax : block->rect.xmax) + (block->panel ? block->panel->ofsx : 0.0f); - gy = (but ? but->rect.ymax : block->rect.ymax) + (block->panel ? block->panel->ofsy : 0.0f); - - rect->xmax = floorf(getsizex * (0.5f + 0.5f * (gx * block->winmat[0][0] + gy * block->winmat[1][0] + block->winmat[3][0]))); - rect->ymax = floorf(getsizey * (0.5f + 0.5f * (gx * block->winmat[0][1] + gy * block->winmat[1][1] + block->winmat[3][1]))); + rectf.xmin -= ar->winrct.xmin; + rectf.ymin -= ar->winrct.ymin; + rectf.xmax -= ar->winrct.xmin; + rectf.ymax -= ar->winrct.ymin; + rect->xmin = floorf(rectf.xmin); + rect->ymin = floorf(rectf.ymin); + rect->xmax = floorf(rectf.xmax); + rect->ymax = floorf(rectf.ymax); } /* uses local copy of style, to scale things down, and allow widgets to change stuff */ @@ -2160,8 +2156,6 @@ uiBlock *uiBeginBlock(const bContext *C, ARegion *region, const char *name, shor wm_subwindow_getmatrix(window, region->swinid, block->winmat); wm_subwindow_getsize(window, region->swinid, &getsizex, &getsizey); - /* TODO - investigate why block->winmat[0][0] is negative - * in the image view when viewRedrawForce is called */ block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]); } else { @@ -3423,11 +3417,6 @@ void uiBlockClearFlag(uiBlock *block, int flag) block->flag &= ~flag; } -void uiBlockSetXOfs(uiBlock *block, int xofs) -{ - block->xofs = xofs; -} - void uiButSetFlag(uiBut *but, int flag) { but->flag |= flag; diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index bfa9cc2727c..60e4c2aa90f 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2167,6 +2167,16 @@ static void ui_blockopen_end(bContext *C, uiBut *but, uiHandleButtonData *data) } } +int ui_button_open_menu_direction(uiBut *but) +{ + uiHandleButtonData *data = but->active; + + if (data && data->menu) + return data->menu->direction; + + return 0; +} + /* ***************** events for different button types *************** */ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event) diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index e345296b69f..b4b0686d6fc 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -315,7 +315,6 @@ struct uiBlock { char tooltipdisabled; /* to avoid tooltip after click */ char endblock; /* uiEndBlock done? */ - float xofs, yofs; /* offset to parent button */ eBlockBoundsCalc bounds_type; /* for doing delayed */ int mx, my; int bounds, minbounds; /* for doing delayed */ @@ -419,6 +418,9 @@ struct uiPopupBlockHandle { int menuretval; float retvalue; float retvec[4]; + + /* menu direction */ + int direction; }; uiBlock *ui_block_func_COLOR(struct bContext *C, uiPopupBlockHandle *handle, void *arg_but); @@ -481,6 +483,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, struct uiWidgetColors *wc extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, uiBut *but); extern void ui_button_active_free(const struct bContext *C, uiBut *but); extern int ui_button_is_active(struct ARegion *ar); +extern int ui_button_open_menu_direction(uiBut *but); /* interface_widgets.c */ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 605233cd96f..4dafb4b2d4b 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -1341,6 +1341,14 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, ui_block_to_window_fl(butregion, but->block, &butrct.xmin, &butrct.ymin); ui_block_to_window_fl(butregion, but->block, &butrct.xmax, &butrct.ymax); + /* widget_roundbox_set has this correction too, keep in sync */ + if (but->type != PULLDOWN) { + if (but->flag & UI_BUT_ALIGN_TOP) + butrct.ymax += 1.0f; + if (but->flag & UI_BUT_ALIGN_LEFT) + butrct.xmin -= 1.0f; + } + /* calc block rect */ if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) { if (block->buttons.first) { @@ -1467,9 +1475,6 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, } } - /* apply requested offset in the block */ - xof += block->xofs / block->aspect; - yof += block->yofs / block->aspect; #if 0 /* clamp to window bounds, could be made into an option if its ever annoying */ if ( (offscreen = (block->rect.ymin + yof)) < 0) yof -= offscreen; /* bottom */ @@ -1659,12 +1664,10 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut /* if this is being created from a button */ if (but) { - if (ELEM(but->type, BLOCK, PULLDOWN)) - block->xofs = -2; /* for proper alignment */ - block->aspect = but->block->aspect; ui_block_position(window, butregion, but, block); + handle->direction = block->direction; } else { /* keep a list of these, needed for pulldown menus */ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 06d47156598..3fc20309264 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -2702,16 +2702,16 @@ static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(stat *wcol = wcol_backup; } -static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign)) +static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign) { if (state & UI_ACTIVE) { uiWidgetBase wtb; - float rad = 0.5f * BLI_rcti_size_y(rect); /* 4.0f */ - + float rad = 0.25f * BLI_rcti_size_y(rect); /* 4.0f */ + widget_init(&wtb); - + /* half rounded */ - round_box_edges(&wtb, UI_CNR_ALL, rect, rad); + round_box_edges(&wtb, roundboxalign, rect, rad); widgetbase_draw(&wtb, wcol); } @@ -3048,9 +3048,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) static int widget_roundbox_set(uiBut *but, rcti *rect) { + int roundbox = UI_CNR_ALL; + /* alignment */ - if (but->flag & UI_BUT_ALIGN) { + if ((but->flag & UI_BUT_ALIGN) && but->type != PULLDOWN) { + /* ui_block_position has this correction too, keep in sync */ if (but->flag & UI_BUT_ALIGN_TOP) rect->ymax += 1; if (but->flag & UI_BUT_ALIGN_LEFT) @@ -3058,27 +3061,50 @@ static int widget_roundbox_set(uiBut *but, rcti *rect) switch (but->flag & UI_BUT_ALIGN) { case UI_BUT_ALIGN_TOP: - return UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT; + roundbox = UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT; + break; case UI_BUT_ALIGN_DOWN: - return UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT; + roundbox = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT; + break; case UI_BUT_ALIGN_LEFT: - return UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT; + roundbox = UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT; + break; case UI_BUT_ALIGN_RIGHT: - return UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT; + roundbox = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT; + break; case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT: - return UI_CNR_TOP_LEFT; + roundbox = UI_CNR_TOP_LEFT; + break; case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT: - return UI_CNR_TOP_RIGHT; + roundbox = UI_CNR_TOP_RIGHT; + break; case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT: - return UI_CNR_BOTTOM_LEFT; + roundbox = UI_CNR_BOTTOM_LEFT; + break; case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT: - return UI_CNR_BOTTOM_RIGHT; + roundbox = UI_CNR_BOTTOM_RIGHT; + break; default: - return 0; + roundbox = 0; + break; } } - return UI_CNR_ALL; + /* align with open menu */ + if (but->active) { + int direction = ui_button_open_menu_direction(but); + + if (direction == UI_TOP) + roundbox &= ~(UI_CNR_TOP_RIGHT|UI_CNR_TOP_LEFT); + else if (direction == UI_DOWN) + roundbox &= ~(UI_CNR_BOTTOM_RIGHT|UI_CNR_BOTTOM_LEFT); + else if (direction == UI_LEFT) + roundbox &= ~(UI_CNR_TOP_LEFT|UI_CNR_BOTTOM_LEFT); + else if (direction == UI_RIGHT) + roundbox &= ~(UI_CNR_TOP_RIGHT|UI_CNR_BOTTOM_RIGHT); + } + + return roundbox; } /* conversion from old to new buttons, so still messy */ From 282f98a84dc7d454a36918b9b8b279aa127c4d3b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 4 Oct 2012 20:12:16 +0000 Subject: [PATCH 083/143] Fix #31806: cycles crash rendering a particular node setup with multiple mix/add shader nodes. --- intern/cycles/render/graph.cpp | 6 +++--- intern/cycles/render/svm.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 20fbfa0cf27..62758128a73 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -181,14 +181,14 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) assert(from && to); if(to->link) { - fprintf(stderr, "ShaderGraph connect: input already connected.\n"); + fprintf(stderr, "Cycles shader graph connect: input already connected.\n"); return; } if(from->type != to->type) { /* for closures we can't do automatic conversion */ if(from->type == SHADER_SOCKET_CLOSURE || to->type == SHADER_SOCKET_CLOSURE) { - fprintf(stderr, "ShaderGraph connect: can only connect closure to closure " + fprintf(stderr, "Cycles shader graph connect: can only connect closure to closure " "(ShaderNode:%s, ShaderOutput:%s , type:%d -> to ShaderNode:%s, ShaderInput:%s, type:%d).\n", from->parent->name.c_str(), from->name, (int)from->type, to->parent->name.c_str(), to->name, (int)to->type); @@ -363,7 +363,7 @@ void ShaderGraph::break_cycles(ShaderNode *node, vector& visited, vectorid]) { /* break cycle */ disconnect(input); - fprintf(stderr, "ShaderGraph: detected cycle in graph, connection removed.\n"); + fprintf(stderr, "Cycles shader graph: detected cycle in graph, connection removed.\n"); } else if(!visited[depnode->id]) { /* visit dependencies */ diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 844ce01569f..da287a10199 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -274,6 +274,17 @@ void SVMCompiler::stack_clear_users(ShaderNode *node, set& done) foreach(ShaderInput *in, output->links) in->stack_offset = SVM_STACK_INVALID; + + /* unmark any nodes that have no more valid outputs, see [#31806] */ + if(done.find(output->parent) != done.end()) { + all_done = true; + foreach(ShaderOutput *pout, output->parent->outputs) + if(pout->stack_offset != SVM_STACK_INVALID) + all_done = false; + + if(all_done) + done.erase(output->parent); + } } } } From 41202e25e781543eaabfa5be90e2de0f1b7f94a8 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 4 Oct 2012 20:31:08 +0000 Subject: [PATCH 084/143] Fix #32763: Image flickering appears if Movie Clip Editor and compositor opened The issue was caused by compositor was allocating float buffer for image and then this buffer was filled with data converted from byte buffer. If display happens at time between float was allocated and it was filled black areas were appearing on the screen. Made it so IMB_float_from_rect locks color management thread so display transform wouldn't use uninitialized buffer anymore. --- source/blender/imbuf/intern/colormanagement.c | 25 ++++++++++++------- source/blender/imbuf/intern/divers.c | 15 ++++++++++- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index bb1449060dd..50000b9eeea 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -88,6 +88,13 @@ static int global_tot_colorspace = 0; static int global_tot_display = 0; static int global_tot_view = 0; +/* lock used by pre-cached processors getters, so processor wouldn't + * be created several times + * LOCK_COLORMANAGE can not be used since this mutex could be needed to + * be locked before pre-cached processor are creating + */ +static pthread_mutex_t processor_lock = BLI_MUTEX_INITIALIZER; + typedef struct ColormanageProcessor { ConstProcessorRcPtr *processor; CurveMapping *curve_mapping; @@ -732,7 +739,7 @@ static ConstProcessorRcPtr *create_colorspace_transform_processor(const char *fr static ConstProcessorRcPtr *colorspace_to_scene_linear_processor(ColorSpace *colorspace) { if (colorspace->to_scene_linear == NULL) { - BLI_lock_thread(LOCK_COLORMANAGE); + BLI_mutex_lock(&processor_lock); if (colorspace->to_scene_linear == NULL) { ConstProcessorRcPtr *to_scene_linear; @@ -740,7 +747,7 @@ static ConstProcessorRcPtr *colorspace_to_scene_linear_processor(ColorSpace *col colorspace->to_scene_linear = (struct ConstProcessorRcPtr *) to_scene_linear; } - BLI_unlock_thread(LOCK_COLORMANAGE); + BLI_mutex_unlock(&processor_lock); } return (ConstProcessorRcPtr *) colorspace->to_scene_linear; @@ -749,7 +756,7 @@ static ConstProcessorRcPtr *colorspace_to_scene_linear_processor(ColorSpace *col static ConstProcessorRcPtr *colorspace_from_scene_linear_processor(ColorSpace *colorspace) { if (colorspace->from_scene_linear == NULL) { - BLI_lock_thread(LOCK_COLORMANAGE); + BLI_mutex_lock(&processor_lock); if (colorspace->from_scene_linear == NULL) { ConstProcessorRcPtr *from_scene_linear; @@ -757,7 +764,7 @@ static ConstProcessorRcPtr *colorspace_from_scene_linear_processor(ColorSpace *c colorspace->from_scene_linear = (struct ConstProcessorRcPtr *) from_scene_linear; } - BLI_unlock_thread(LOCK_COLORMANAGE); + BLI_mutex_unlock(&processor_lock); } return (ConstProcessorRcPtr *) colorspace->from_scene_linear; @@ -766,7 +773,7 @@ static ConstProcessorRcPtr *colorspace_from_scene_linear_processor(ColorSpace *c static ConstProcessorRcPtr *display_from_scene_linear_processor(ColorManagedDisplay *display) { if (display->from_scene_linear == NULL) { - BLI_lock_thread(LOCK_COLORMANAGE); + BLI_mutex_lock(&processor_lock); if (display->from_scene_linear == NULL) { const char *view_name = colormanage_view_get_default_name(display); @@ -783,7 +790,7 @@ static ConstProcessorRcPtr *display_from_scene_linear_processor(ColorManagedDisp display->from_scene_linear = (struct ConstProcessorRcPtr *) processor; } - BLI_unlock_thread(LOCK_COLORMANAGE); + BLI_mutex_unlock(&processor_lock); } return (ConstProcessorRcPtr *) display->from_scene_linear; @@ -792,7 +799,7 @@ static ConstProcessorRcPtr *display_from_scene_linear_processor(ColorManagedDisp static ConstProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDisplay *display) { if (display->to_scene_linear == NULL) { - BLI_lock_thread(LOCK_COLORMANAGE); + BLI_mutex_lock(&processor_lock); if (display->to_scene_linear == NULL) { const char *view_name = colormanage_view_get_default_name(display); @@ -809,7 +816,7 @@ static ConstProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDispla display->to_scene_linear = (struct ConstProcessorRcPtr *) processor; } - BLI_unlock_thread(LOCK_COLORMANAGE); + BLI_mutex_unlock(&processor_lock); } return (ConstProcessorRcPtr *) display->to_scene_linear; @@ -1263,7 +1270,7 @@ static void *do_display_buffer_apply_thread(void *handle_v) if (cm_processor == NULL) { if (display_buffer_byte) { IMB_buffer_byte_from_byte(display_buffer_byte, handle->byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB, - FALSE, width, height, width, width); + FALSE, width, height, width, width); } if (display_buffer) { diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 9ce5d0e30da..aa236af3507 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -43,6 +43,8 @@ #include "IMB_colormanagement.h" #include "IMB_colormanagement_intern.h" +#include "BLI_threads.h" + #include "MEM_guardedalloc.h" /**************************** Interlace/Deinterlace **************************/ @@ -599,9 +601,18 @@ void IMB_float_from_rect(ImBuf *ibuf) if (ibuf->rect == NULL) return; + /* lock the color management thread + * need this because allocated but not filled float buffer will confuse + * display transform which lead to black areas across the frame + */ + BLI_lock_thread(LOCK_COLORMANAGE); + if (ibuf->rect_float == NULL) { - if (imb_addrectfloatImBuf(ibuf) == 0) + if (imb_addrectfloatImBuf(ibuf) == 0) { + BLI_unlock_thread(LOCK_COLORMANAGE); + return; + } } /* first, create float buffer in non-linear space */ @@ -611,6 +622,8 @@ void IMB_float_from_rect(ImBuf *ibuf) /* then make float be in linear space */ IMB_colormanagement_colorspace_to_scene_linear(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, ibuf->rect_colorspace, predivide); + + BLI_unlock_thread(LOCK_COLORMANAGE); } /* no profile conversion */ From e5ec9f9f953dcc6a4ab0f937cd55199b0cf4f4fb Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 4 Oct 2012 20:59:47 +0000 Subject: [PATCH 085/143] Quick fix for [#32764] Some new object types are added at the origin instead of the 3D cursor Own fault (r50994). Those "add object" ops really need a cleanup to make them more consistent! Will try to see this tomorrow. --- release/scripts/startup/bl_ui/space_info.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index a67c30e2b85..de58b5d1aaf 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -289,8 +289,11 @@ class INFO_MT_add(Menu): layout.separator() layout.menu("INFO_MT_armature_add", icon='OUTLINER_OB_ARMATURE') + # XXX Quick fix for [#32764]. + layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE' layout.operator("object.add", text="Empty", icon='OUTLINER_OB_EMPTY').type = 'EMPTY' + layout.operator_context = 'EXEC_REGION_WIN' layout.separator() layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER') From 984e9f9cc8eee131c6602b326e588d2903eda90a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 4 Oct 2012 21:40:10 +0000 Subject: [PATCH 086/143] Mesh Deform Modifier: binding is now accelerated with a BVH tree, can make it much faster for complex meshes. Patch by Joe Eager. --- .../blender/editors/armature/meshlaplacian.c | 100 +++++++++--------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 346ed0002bd..5ca06c62c46 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -1113,6 +1113,9 @@ typedef struct MeshDeformBind { /* direct solver */ int *varidx; + + BVHTree *bvhtree; + BVHTreeFromMesh bvhdata; } MeshDeformBind; typedef struct MeshDeformIsect { @@ -1188,61 +1191,53 @@ static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3], return 1; } -static int meshdeform_intersect(MeshDeformBind *mdb, MeshDeformIsect *isec) -{ - MFace *mface; - float face[4][3], co[3], uvw[3], len, nor[3], end[3]; - int f, hit, is = 0, totface; - - isec->labda = 1e10; - - mface = mdb->cagedm->getTessFaceArray(mdb->cagedm); - totface = mdb->cagedm->getNumTessFaces(mdb->cagedm); - - add_v3_v3v3(end, isec->start, isec->vec); - - for (f = 0; f < totface; f++, mface++) { - copy_v3_v3(face[0], mdb->cagecos[mface->v1]); - copy_v3_v3(face[1], mdb->cagecos[mface->v2]); - copy_v3_v3(face[2], mdb->cagecos[mface->v3]); - - if (mface->v4) { - copy_v3_v3(face[3], mdb->cagecos[mface->v4]); - hit = meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw); - - if (hit) { - normal_tri_v3(nor, face[0], face[1], face[2]); - } - else { - hit = meshdeform_tri_intersect(isec->start, end, face[0], face[2], face[3], co, uvw); - normal_tri_v3(nor, face[0], face[2], face[3]); - } - } - else { - hit = meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw); - normal_tri_v3(nor, face[0], face[1], face[2]); - } - - if (hit) { - len = len_v3v3(isec->start, co) / len_v3v3(isec->start, end); - if (len < isec->labda) { - isec->labda = len; - isec->face = mface; - isec->isect = (dot_v3v3(isec->vec, nor) <= 0.0f); - is = 1; - } - } +void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) + { + void **data = userdata; + MeshDeformBind *mdb = data[1]; + MFace *mface = data[0], *mf; + MeshDeformIsect *isec = data[2]; + float no[3], co[3], end[3], uvw[3], dist, face[4][3]; + + mf = mface + index; + + copy_v3_v3(face[0], mdb->cagecos[mf->v1]); + copy_v3_v3(face[1], mdb->cagecos[mf->v2]); + copy_v3_v3(face[2], mdb->cagecos[mf->v3]); + if (mf->v4) + copy_v3_v3(face[3], mdb->cagecos[mf->v4]); + + add_v3_v3v3(end, isec->start, isec->vec); + + if (!meshdeform_tri_intersect(ray->origin, end, face[0], face[1], face[2], co, uvw)) + if (!mf->v4 || !meshdeform_tri_intersect(ray->origin, end, face[0], face[2], face[3], co, uvw)) + return; + + if (!mf->v4) + normal_tri_v3(no, face[0], face[1], face[2]); + else + normal_quad_v3(no, face[0], face[1], face[2], face[3]); + + dist = len_v3v3(ray->origin, co)/len_v3(isec->vec); + if (dist < hit->dist) { + hit->index = index; + hit->dist = dist; + copy_v3_v3(hit->co, co); + + isec->isect = INPR(no, ray->direction) <= 0.0; + isec->labda = dist; + isec->face = mf; } - - return is; } static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float *co1, float *co2) { MDefBoundIsect *isect; + BVHTreeRayHit hit; MeshDeformIsect isec; float (*cagecos)[3]; - MFace *mface; + void *data[3] = {mdb->cagedm->getTessFaceArray(mdb->cagedm), mdb, &isec}; + MFace *mface1 = data[0], *mface; float vert[4][3], len, end[3]; static float epsilon[3] = {0, 0, 0}; //1e-4, 1e-4, 1e-4}; @@ -1254,9 +1249,11 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float add_v3_v3v3(end, co2, epsilon); sub_v3_v3v3(isec.vec, end, isec.start); - if (meshdeform_intersect(mdb, &isec)) { - len = isec.labda; - mface = (MFace *)isec.face; + hit.index = -1; + hit.dist = FLT_MAX; + if (BLI_bvhtree_ray_cast(mdb->bvhtree, isec.start, isec.vec, 0.0, &hit, harmonic_ray_callback, data) != -1) { + len= isec.labda; + isec.face = mface = mface1 + hit.index; /* create MDefBoundIsect */ isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect)); @@ -1766,7 +1763,7 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa mdb->totalphi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindTotalPhi"); mdb->boundisect = MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect"); mdb->semibound = MEM_callocN(sizeof(int) * mdb->size3, "MDefSemiBound"); - + mdb->bvhtree = bvhtree_from_mesh_faces(&mdb->bvhdata, mdb->cagedm, FLT_EPSILON*100, 4, 6); mdb->inside = MEM_callocN(sizeof(int) * mdb->totvert, "MDefInside"); if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) @@ -1882,6 +1879,7 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa MEM_freeN(mdb->boundisect); MEM_freeN(mdb->semibound); BLI_memarena_free(mdb->memarena); + free_bvhtree_from_mesh(&mdb->bvhdata); } #if 0 From fedc8e17223cc5490d465788cac211328a712e5f Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 4 Oct 2012 21:40:39 +0000 Subject: [PATCH 087/143] Cycles: add "From Dupli" option for texture coordinate node. This gets the Generated and UV coordinates from the duplicator of instance instead of the object itself. This was used in e.g. Big Buck Bunny for texturing instanced feathers with a UV map on the bird. Many files changed, mainly to do some refactoring to get rid of G.rendering global in duplilist code. --- intern/cycles/blender/blender_object.cpp | 17 +++- intern/cycles/blender/blender_shader.cpp | 5 +- intern/cycles/blender/blender_sync.h | 2 +- intern/cycles/blender/blender_util.h | 4 +- intern/cycles/kernel/kernel_object.h | 24 ++++- intern/cycles/kernel/kernel_types.h | 2 +- intern/cycles/kernel/svm/svm_tex_coord.h | 24 +++++ intern/cycles/kernel/svm/svm_types.h | 5 +- intern/cycles/render/nodes.cpp | 24 +++-- intern/cycles/render/nodes.h | 2 + intern/cycles/render/object.cpp | 4 + intern/cycles/render/object.h | 3 + source/blender/blenkernel/BKE_anim.h | 4 +- source/blender/blenkernel/BKE_blender.h | 2 +- source/blender/blenkernel/intern/anim.c | 93 ++++++++++--------- source/blender/blenkernel/intern/object.c | 4 +- source/blender/blenkernel/intern/pointcache.c | 2 +- source/blender/blenkernel/intern/scene.c | 2 +- source/blender/blenloader/intern/readfile.c | 21 +++++ source/blender/editors/object/object_add.c | 2 +- source/blender/editors/space_node/drawnode.c | 8 ++ .../editors/space_view3d/view3d_draw.c | 4 +- .../editors/space_view3d/view3d_view.c | 2 +- .../editors/transform/transform_snap.c | 4 +- source/blender/gpu/intern/gpu_material.c | 2 +- source/blender/makesrna/intern/rna_internal.h | 2 +- source/blender/makesrna/intern/rna_nodetree.c | 10 ++ .../makesrna/intern/rna_nodetree_types.h | 2 +- source/blender/makesrna/intern/rna_object.c | 11 ++- .../blender/makesrna/intern/rna_object_api.c | 7 +- .../shader/nodes/node_shader_tex_coord.c | 2 +- .../render/intern/source/convertblender.c | 2 +- 32 files changed, 222 insertions(+), 80 deletions(-) diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 8fbb223cbc5..27301026d35 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -194,8 +194,10 @@ void BlenderSync::sync_background_light() /* Object */ -void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint layer_flag, int motion, int particle_id) +void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion, int particle_id) { + BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent); + /* light is handled separately */ if(object_is_light(b_ob)) { if(!motion) @@ -274,6 +276,15 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, object->visibility &= ~PATH_RAY_CAMERA; } + if (b_dupli_ob) { + object->dupli_generated = get_float3(b_dupli_ob.orco()); + object->dupli_uv = get_float2(b_dupli_ob.uv()); + } + else { + object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f); + object->dupli_uv = make_float2(0.0f, 0.0f); + } + object->particle_id = particle_id; object->tag_update(scene); @@ -328,7 +339,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) bool dup_hide = (b_v3d)? b_dup_ob.hide(): b_dup_ob.hide_render(); if(!(b_dup->hide() || dup_hide)) { - sync_object(*b_ob, b_index, b_dup_ob, tfm, ob_layer, motion, b_dup->particle_index() + particle_offset); + sync_object(*b_ob, b_index, *b_dup, tfm, ob_layer, motion, b_dup->particle_index() + particle_offset); } ++b_index; @@ -346,7 +357,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) if(!hide) { /* object itself */ Transform tfm = get_transform(b_ob->matrix_world()); - sync_object(*b_ob, 0, *b_ob, tfm, ob_layer, motion, 0); + sync_object(*b_ob, 0, PointerRNA_NULL, tfm, ob_layer, motion, 0); } particle_offset += num_particles; diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index ebf8bb45420..b6d5cc623bb 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -490,7 +490,10 @@ static ShaderNode *add_node(BL::BlendData b_data, BL::Scene b_scene, ShaderGraph break; } case BL::ShaderNode::type_TEX_COORD: { - node = new TextureCoordinateNode(); + BL::ShaderNodeTexCoord b_tex_coord_node(b_node); + TextureCoordinateNode *tex_coord = new TextureCoordinateNode(); + tex_coord->from_dupli = b_tex_coord_node.from_dupli(); + node = tex_coord; break; } case BL::ShaderNode::type_TEX_SKY: { diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 27f6b6ee4ee..ce563087b4a 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -81,7 +81,7 @@ private: void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree); Mesh *sync_mesh(BL::Object b_ob, bool object_updated); - void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint layer_flag, int motion, int particle_id); + void sync_object(BL::Object b_parent, int b_index, BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion, int particle_id); void sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm); void sync_background_light(); void sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion); diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 46fbead9bc1..da8f30ea169 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -36,7 +36,7 @@ struct RenderResult; ID *rna_Object_to_mesh(void *_self, void *reports, void *scene, int apply_modifiers, int settings); void rna_Main_meshes_remove(void *bmain, void *reports, void *mesh); -void rna_Object_create_duplilist(void *ob, void *reports, void *sce); +void rna_Object_create_duplilist(void *ob, void *reports, void *sce, int settings); void rna_Object_free_duplilist(void *ob); void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values); void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values); @@ -84,7 +84,7 @@ static inline void object_remove_mesh(BL::BlendData data, BL::Mesh mesh) static inline void object_create_duplilist(BL::Object self, BL::Scene scene) { - rna_Object_create_duplilist(self.ptr.data, NULL, scene.ptr.data); + rna_Object_create_duplilist(self.ptr.data, NULL, scene.ptr.data, 2); } static inline void object_free_duplilist(BL::Object self) diff --git a/intern/cycles/kernel/kernel_object.h b/intern/cycles/kernel/kernel_object.h index 222ade504cc..01da5050c8d 100644 --- a/intern/cycles/kernel/kernel_object.h +++ b/intern/cycles/kernel/kernel_object.h @@ -23,7 +23,8 @@ enum ObjectTransform { OBJECT_INVERSE_TRANSFORM = 3, OBJECT_PROPERTIES = 6, OBJECT_TRANSFORM_MOTION_PRE = 8, - OBJECT_TRANSFORM_MOTION_POST = 12 + OBJECT_TRANSFORM_MOTION_POST = 12, + OBJECT_DUPLI = 16 }; __device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, float time, enum ObjectTransform type) @@ -164,6 +165,27 @@ __device_inline uint object_particle_id(KernelGlobals *kg, int object) return __float_as_int(f.w); } +__device_inline float3 object_dupli_generated(KernelGlobals *kg, int object) +{ + if(object == ~0) + return make_float3(0.0f, 0.0f, 0.0f); + + int offset = object*OBJECT_SIZE + OBJECT_DUPLI; + float4 f = kernel_tex_fetch(__objects, offset); + return make_float3(f.x, f.y, f.z); +} + +__device_inline float3 object_dupli_uv(KernelGlobals *kg, int object) +{ + if(object == ~0) + return make_float3(0.0f, 0.0f, 0.0f); + + int offset = object*OBJECT_SIZE + OBJECT_DUPLI; + float4 f = kernel_tex_fetch(__objects, offset + 1); + return make_float3(f.x, f.y, 0.0f); +} + + __device int shader_pass_id(KernelGlobals *kg, ShaderData *sd) { return kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2 + 1); diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index ce21ab994f0..48e271a9f3f 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -29,7 +29,7 @@ CCL_NAMESPACE_BEGIN /* constants */ -#define OBJECT_SIZE 16 +#define OBJECT_SIZE 18 #define LIGHT_SIZE 4 #define FILTER_TABLE_SIZE 256 #define RAMP_TABLE_SIZE 256 diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index fbaf253177d..6bd8f2ac69c 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -92,6 +92,14 @@ __device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, float *stack data = sd->I; break; } + case NODE_TEXCO_DUPLI_GENERATED: { + data = object_dupli_generated(kg, sd->object); + break; + } + case NODE_TEXCO_DUPLI_UV: { + data = object_dupli_uv(kg, sd->object); + break; + } } stack_store_float3(stack, out_offset, data); @@ -141,6 +149,14 @@ __device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, floa data = sd->I; break; } + case NODE_TEXCO_DUPLI_GENERATED: { + data = object_dupli_generated(kg, sd->object); + break; + } + case NODE_TEXCO_DUPLI_UV: { + data = object_dupli_uv(kg, sd->object); + break; + } } stack_store_float3(stack, out_offset, data); @@ -193,6 +209,14 @@ __device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, floa data = sd->I; break; } + case NODE_TEXCO_DUPLI_GENERATED: { + data = object_dupli_generated(kg, sd->object); + break; + } + case NODE_TEXCO_DUPLI_UV: { + data = object_dupli_uv(kg, sd->object); + break; + } } stack_store_float3(stack, out_offset, data); diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index c82eafc790a..3cf44a3409a 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -43,6 +43,7 @@ typedef enum NodeType { NODE_TEX_IMAGE_BOX, NODE_TEX_SKY, NODE_GEOMETRY, + NODE_GEOMETRY_DUPLI, NODE_LIGHT_PATH, NODE_VALUE_F, NODE_VALUE_V, @@ -149,7 +150,9 @@ typedef enum NodeTexCoord { NODE_TEXCO_OBJECT, NODE_TEXCO_CAMERA, NODE_TEXCO_WINDOW, - NODE_TEXCO_REFLECTION + NODE_TEXCO_REFLECTION, + NODE_TEXCO_DUPLI_GENERATED, + NODE_TEXCO_DUPLI_UV } NodeTexCoord; typedef enum NodeMix { diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index eabb97e7238..b878bdee3c7 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1681,9 +1681,15 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler) compiler.add_node(geom_node, NODE_GEOM_P, out->stack_offset); } else { - int attr = compiler.attribute(ATTR_STD_GENERATED); - compiler.stack_assign(out); - compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3); + if(from_dupli) { + compiler.stack_assign(out); + compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, out->stack_offset); + } + else { + int attr = compiler.attribute(ATTR_STD_GENERATED); + compiler.stack_assign(out); + compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3); + } } } @@ -1695,9 +1701,15 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler) out = output("UV"); if(!out->links.empty()) { - int attr = compiler.attribute(ATTR_STD_UV); - compiler.stack_assign(out); - compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3); + if(from_dupli) { + int attr = compiler.attribute(ATTR_STD_UV); + compiler.stack_assign(out); + compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3); + } + else { + compiler.stack_assign(out); + compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, out->stack_offset); + } } out = output("Object"); diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 82bead7e41a..e8e584dd8ef 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -284,6 +284,8 @@ class TextureCoordinateNode : public ShaderNode { public: SHADER_NODE_CLASS(TextureCoordinateNode) void attributes(AttributeRequestSet *attributes); + + bool from_dupli; }; class LightPathNode : public ShaderNode { diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 7389b239627..d78a82d589a 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -235,6 +235,10 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene } } + /* dupli object coords */ + objects[offset+16] = make_float4(ob->dupli_generated[0], ob->dupli_generated[1], ob->dupli_generated[2], 0.0f); + objects[offset+17] = make_float4(ob->dupli_uv[0], ob->dupli_uv[1], 0.0f, 0.0f); + /* object flag */ if(ob->use_holdout) flag |= SD_HOLDOUT_MASK; diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 88677d79dff..e2c3ad4e071 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -49,6 +49,9 @@ public: bool use_motion; bool use_holdout; + float3 dupli_generated; + float2 dupli_uv; + int particle_id; Object(); diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h index f506c67a36c..11537964e32 100644 --- a/source/blender/blenkernel/BKE_anim.h +++ b/source/blender/blenkernel/BKE_anim.h @@ -65,8 +65,8 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl /* ---------------------------------------------------- */ /* Dupli-Geometry */ -struct ListBase *object_duplilist_ex(struct Scene *sce, struct Object *ob, int update); -struct ListBase *object_duplilist(struct Scene *sce, struct Object *ob); +struct ListBase *object_duplilist_ex(struct Scene *sce, struct Object *ob, int update, int for_render); +struct ListBase *object_duplilist(struct Scene *sce, struct Object *ob, int for_render); void free_object_duplilist(struct ListBase *lb); int count_duplilist(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 080eb7bc541..56dfdf404f8 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 264 -#define BLENDER_SUBVERSION 0 +#define BLENDER_SUBVERSION 1 /* 262 was the last editmesh release but its has compatibility code for bmesh data, * so set the minversion to 2.61 */ diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index ec15e2ea87f..58d20fff2bc 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -75,7 +75,7 @@ /* forward declarations */ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index, - int level, short animated, short update); + int level, short flag); /* ******************************************************************** */ /* Animation Visualization */ @@ -700,7 +700,11 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua /* ******************************************************************** */ /* Dupli-Geometry */ -static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int par_index, int type, short animated) +#define DUPLILIST_DO_UPDATE 1 +#define DUPLILIST_FOR_RENDER 2 +#define DUPLILIST_ANIMATED 4 + +static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int par_index, int type, short flag) { DupliObject *dob = MEM_callocN(sizeof(DupliObject), "dupliobject"); @@ -712,14 +716,14 @@ static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], i dob->index = index; dob->particle_index = par_index; dob->type = type; - dob->animated = (type == OB_DUPLIGROUP) && animated; + dob->animated = (type == OB_DUPLIGROUP) && (flag & DUPLILIST_ANIMATED); ob->lay = lay; return dob; } static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, - int level, short animated, short update) + int level, short flag) { DupliObject *dob; Group *group; @@ -735,13 +739,14 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_inde /* handles animated groups, and */ /* we need to check update for objects that are not in scene... */ - if (update) { + if (flag & DUPLILIST_DO_UPDATE) { /* note: update is optional because we don't always need object * transformations to be correct. Also fixes bug [#29616]. */ group_handle_recalc_and_update(scene, ob, group); } - animated = animated || group_is_animated(ob, group); + if (group_is_animated(ob, group)) + flag |= DUPLILIST_ANIMATED; for (go = group->gobject.first; go; go = go->next) { /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ @@ -757,7 +762,7 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_inde mult_m4_m4m4(mat, ob->obmat, go->ob->obmat); } - dob = new_dupli_object(lb, go->ob, mat, ob->lay, 0, par_index, OB_DUPLIGROUP, animated); + dob = new_dupli_object(lb, go->ob, mat, ob->lay, 0, par_index, OB_DUPLIGROUP, flag); /* check the group instance and object layers match, also that the object visible flags are ok. */ if ((dob->origlay & group->layer) == 0 || @@ -772,14 +777,14 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_inde if (go->ob->transflag & OB_DUPLI) { copy_m4_m4(dob->ob->obmat, dob->mat); - object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, par_index, level + 1, animated, update); + object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, par_index, level + 1, flag); copy_m4_m4(dob->ob->obmat, dob->omat); } } } } -static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, int level, short animated) +static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, int level, short flag) { extern int enable_cu_speed; /* object.c */ Object copyob; @@ -827,7 +832,7 @@ static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_ind BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra); - dob = new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, par_index, OB_DUPLIFRAMES, animated); + dob = new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, par_index, OB_DUPLIFRAMES, flag); copy_m4_m4(dob->omat, copyob.obmat); } } @@ -851,8 +856,7 @@ static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_ind typedef struct VertexDupliData { ID *id; /* scene or group, for recursive loops */ int level; - short animated; - short update; + short flag; ListBase *lb; float pmat[4][4]; float obmat[4][4]; /* Only used for dupliverts inside dupligroups, where the ob->obmat is modified */ @@ -896,7 +900,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], origlay = vdd->ob->lay; - dob = new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, vdd->par_index, OB_DUPLIVERTS, vdd->animated); + dob = new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, vdd->par_index, OB_DUPLIVERTS, vdd->flag); /* restore the original layer so that each dupli will have proper dob->origlay */ vdd->ob->lay = origlay; @@ -908,13 +912,13 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], float tmpmat[4][4]; copy_m4_m4(tmpmat, vdd->ob->obmat); copy_m4_m4(vdd->ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->par_index, vdd->level + 1, vdd->animated, vdd->update); + object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->par_index, vdd->level + 1, vdd->flag); copy_m4_m4(vdd->ob->obmat, tmpmat); } } static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index, - int level, short animated, short update) + int level, short flag) { Object *ob, *ob_iter; Mesh *me = par->data; @@ -942,7 +946,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl else dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH); - if (G.is_rendering) { + if (flag & DUPLILIST_FOR_RENDER) { vdd.orco = (float(*)[3])BKE_mesh_orco_verts_get(par); BKE_mesh_orco_verts_transform(me, vdd.orco, me->totvert, 0); } @@ -992,8 +996,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl vdd.id = id; vdd.level = level; - vdd.animated = animated; - vdd.update = update; + vdd.flag = flag; vdd.lb = lb; vdd.ob = ob; vdd.scene = scene; @@ -1039,7 +1042,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl } static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index, - int level, short animated, short update) + int level, short flag) { Object *ob, *ob_iter; Base *base = NULL; @@ -1076,8 +1079,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa mloop = dm->getLoopArray(dm); mvert = dm->getVertArray(dm); - if (G.is_rendering) { - + if (flag & DUPLILIST_FOR_RENDER) { orco = (float(*)[3])BKE_mesh_orco_verts_get(par); BKE_mesh_orco_verts_transform(me, orco, me->totvert, 0); mloopuv = me->mloopuv; @@ -1182,8 +1184,8 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa copy_m4_m4(tmat, obmat); mul_m4_m4m3(obmat, tmat, mat); - dob = new_dupli_object(lb, ob, obmat, par->lay, a, par_index, OB_DUPLIFACES, animated); - if (G.is_rendering) { + dob = new_dupli_object(lb, ob, obmat, par->lay, a, par_index, OB_DUPLIFACES, (flag & DUPLILIST_ANIMATED)); + if (flag & DUPLILIST_FOR_RENDER) { w = 1.0f / (float)mp->totloop; if (orco) { @@ -1205,7 +1207,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa float tmpmat[4][4]; copy_m4_m4(tmpmat, ob->obmat); copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, par_index, level + 1, animated, update); + object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, par_index, level + 1, flag); copy_m4_m4(ob->obmat, tmpmat); } } @@ -1226,7 +1228,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa } static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int UNUSED(par_index), ParticleSystem *psys, - int level, short animated, short update) + int level, short flag) { GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; @@ -1309,7 +1311,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { - if (update) { + if (flag & DUPLILIST_DO_UPDATE) { group_handle_recalc_and_update(scene, par, part->dup_group); } @@ -1452,9 +1454,9 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p else copy_m4_m4(mat, tmat); - dob = new_dupli_object(lb, go->ob, mat, par->lay, counter, index, OB_DUPLIPARTS, animated); + dob = new_dupli_object(lb, go->ob, mat, par->lay, counter, index, OB_DUPLIPARTS, (flag & DUPLILIST_ANIMATED)); copy_m4_m4(dob->omat, obcopylist[b].obmat); - if (G.is_rendering) + if (flag & DUPLILIST_FOR_RENDER) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } @@ -1512,9 +1514,9 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); - dob = new_dupli_object(lb, ob, mat, ob->lay, counter, index, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated); + dob = new_dupli_object(lb, ob, mat, ob->lay, counter, index, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, (flag & DUPLILIST_ANIMATED)); copy_m4_m4(dob->omat, oldobmat); - if (G.is_rendering) + if (flag & DUPLILIST_FOR_RENDER) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } @@ -1566,7 +1568,7 @@ static Object *find_family_object(Object **obar, char *family, char ch) } -static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_index, int level, short animated) +static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_index, int level, short flag) { Object *ob, *obar[256] = {NULL}; Curve *cu; @@ -1605,7 +1607,7 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_inde copy_m4_m4(obmat, par->obmat); copy_v3_v3(obmat[3], vec); - new_dupli_object(lb, ob, obmat, par->lay, a, par_index, OB_DUPLIVERTS, animated); + new_dupli_object(lb, ob, obmat, par->lay, a, par_index, OB_DUPLIVERTS, flag); } } @@ -1615,7 +1617,7 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_inde /* ------------- */ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index, - int level, short animated, short update) + int level, short flag) { if ((ob->transflag & OB_DUPLI) == 0) return; @@ -1635,31 +1637,31 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas if (ob->transflag & OB_DUPLIPARTS) { ParticleSystem *psys = ob->particlesystem.first; for (; psys; psys = psys->next) - new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, psys, level + 1, animated, update); + new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, psys, level + 1, flag); } else if (ob->transflag & OB_DUPLIVERTS) { if (ob->type == OB_MESH) { - vertex_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, animated, update); + vertex_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, flag); } else if (ob->type == OB_FONT) { if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ - font_duplilist(duplilist, scene, ob, par_index, level + 1, animated); + font_duplilist(duplilist, scene, ob, par_index, level + 1, flag); } } } else if (ob->transflag & OB_DUPLIFACES) { if (ob->type == OB_MESH) - face_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, animated, update); + face_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, flag); } else if (ob->transflag & OB_DUPLIFRAMES) { if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ - frames_duplilist(duplilist, scene, ob, par_index, level + 1, animated); + frames_duplilist(duplilist, scene, ob, par_index, level + 1, flag); } } else if (ob->transflag & OB_DUPLIGROUP) { DupliObject *dob; - group_duplilist(duplilist, scene, ob, par_index, level + 1, animated, update); /* now recursive */ + group_duplilist(duplilist, scene, ob, par_index, level + 1, flag); /* now recursive */ if (level == 0) { for (dob = duplilist->first; dob; dob = dob->next) @@ -1671,19 +1673,24 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas /* Returns a list of DupliObject * note; group dupli's already set transform matrix. see note in group_duplilist() */ -ListBase *object_duplilist_ex(Scene *sce, Object *ob, int update) +ListBase *object_duplilist_ex(Scene *sce, Object *ob, int update, int for_render) { ListBase *duplilist = MEM_mallocN(sizeof(ListBase), "duplilist"); + int flag = 0; + + if(update) flag |= DUPLILIST_DO_UPDATE; + if(for_render) flag |= DUPLILIST_FOR_RENDER; + duplilist->first = duplilist->last = NULL; - object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0, 0, update); + object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0, flag); return duplilist; } /* note: previously updating was always done, this is why it defaults to be on * but there are likely places it can be called without updating */ -ListBase *object_duplilist(Scene *sce, Object *ob) +ListBase *object_duplilist(Scene *sce, Object *ob, int for_render) { - return object_duplilist_ex(sce, ob, TRUE); + return object_duplilist_ex(sce, ob, TRUE, for_render); } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 72a43da94b6..65ab97e0dad 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2362,7 +2362,7 @@ int BKE_object_minmax_dupli(Scene *scene, Object *ob, float r_min[3], float r_ma ListBase *lb; DupliObject *dob; - lb = object_duplilist(scene, ob); + lb = object_duplilist(scene, ob, FALSE); for (dob = lb->first; dob; dob = dob->next) { if ((use_hidden == FALSE) && (dob->no_draw != 0)) { /* pass */ @@ -2439,7 +2439,7 @@ void BKE_scene_foreach_display_point( ListBase *lb; DupliObject *dob; - lb = object_duplilist(scene, ob); + lb = object_duplilist(scene, ob, FALSE); for (dob = lb->first; dob; dob = dob->next) { if (dob->no_draw == 0) { BKE_object_foreach_display_point(dob->ob, dob->mat, func_cb, user_data); diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 0d01bb33fc5..8c0d19ba1fd 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1030,7 +1030,7 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup ListBase *lb_dupli_ob; /* don't update the dupli groups, we only wan't their pid's */ - if ((lb_dupli_ob = object_duplilist_ex(scene, ob, FALSE))) { + if ((lb_dupli_ob = object_duplilist_ex(scene, ob, FALSE, FALSE))) { DupliObject *dob; for (dob= lb_dupli_ob->first; dob; dob= dob->next) { if (dob->ob != ob) { /* avoids recursive loops with dupliframes: bug 22988 */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 41d300a95de..f8777f87369 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -744,7 +744,7 @@ int BKE_scene_base_iter_next(Scene **scene, int val, Base **base, Object **ob) * this enters eternal loop because of * makeDispListMBall getting called inside of group_duplilist */ if ((*base)->object->dup_group == NULL) { - duplilist = object_duplilist((*scene), (*base)->object); + duplilist = object_duplilist((*scene), (*base)->object, FALSE); dupob = duplilist->first; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9aa7da3ca6e..26d9fb9e829 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7038,6 +7038,15 @@ static void do_version_ntree_keying_despill_balance(void *UNUSED(data), ID *UNUS } } +static void do_version_ntree_tex_coord_from_dupli_264(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree) +{ + bNode *node; + + for (node = ntree->nodes.first; node; node = node->next) + if (node->type == SH_NODE_TEX_COORD) + node->flag |= NODE_OPTIONS; +} + static void do_versions(FileData *fd, Library *lib, Main *main) { /* WATCH IT!!!: pointers from libdata have not been converted */ @@ -7995,6 +8004,18 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } + if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 1)) { + bNodeTreeType *ntreetype = ntreeGetType(NTREE_SHADER); + bNodeTree *ntree; + + if (ntreetype && ntreetype->foreach_nodetree) + ntreetype->foreach_nodetree(main, NULL, do_version_ntree_tex_coord_from_dupli_264); + + for (ntree=main->nodetree.first; ntree; ntree=ntree->id.next) + if (ntree->type==NTREE_SHADER) + do_version_ntree_tex_coord_from_dupli_264(NULL, NULL, ntree); + } + /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 4942b9e4390..c2e5f145ff7 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1086,7 +1086,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (!(base->object->transflag & OB_DUPLI)) return; - lb = object_duplilist(scene, base->object); + lb = object_duplilist(scene, base->object, FALSE); if (use_hierarchy || use_base_parent) { dupli_gh = BLI_ghash_ptr_new("make_object_duplilist_real dupli_gh"); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 1d04855666e..470f82195a4 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1389,6 +1389,11 @@ static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), uiItemR(layout, ptr, "coloring", 0, "", ICON_NONE); } +static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "from_dupli", 0, NULL, 0); +} + static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); @@ -1470,6 +1475,9 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_TEX_VORONOI: ntype->uifunc = node_shader_buts_tex_voronoi; break; + case SH_NODE_TEX_COORD: + ntype->uifunc = node_shader_buts_tex_coord; + break; case SH_NODE_BSDF_GLOSSY: case SH_NODE_BSDF_GLASS: ntype->uifunc = node_shader_buts_glossy; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index cb197ab93b0..ca768f2ef17 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1918,7 +1918,7 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas if (base->object->restrictflag & OB_RESTRICT_VIEW) return; tbase.flag = OB_FROMDUPLI | base->flag; - lb = object_duplilist(scene, base->object); + lb = object_duplilist(scene, base->object, FALSE); // BLI_sortlist(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */ dob = dupli_step(lb->first); @@ -2331,7 +2331,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d) if (ob->transflag & OB_DUPLI) { DupliObject *dob; - ListBase *lb = object_duplilist(scene, ob); + ListBase *lb = object_duplilist(scene, ob, FALSE); for (dob = lb->first; dob; dob = dob->next) if (dob->ob->type == OB_LAMP) diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index b3dd54c6261..cdb75cdfa74 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1326,7 +1326,7 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b Base tbase; tbase.flag = OB_FROMDUPLI; - lb = object_duplilist(scene, base->object); + lb = object_duplilist(scene, base->object, FALSE); for (dob = lb->first; dob; dob = dob->next) { tbase.object = dob->ob; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index cee1c91abe7..700869e10d5 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1708,7 +1708,7 @@ static int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, c if (ob->transflag & OB_DUPLI) { DupliObject *dupli_ob; - ListBase *lb = object_duplilist(scene, ob); + ListBase *lb = object_duplilist(scene, ob, FALSE); for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { Object *dob = dupli_ob->ob; @@ -1914,7 +1914,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L if (ob->transflag & OB_DUPLI) { DupliObject *dupli_ob; - ListBase *lb = object_duplilist(scene, ob); + ListBase *lb = object_duplilist(scene, ob, FALSE); for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { Object *dob = dupli_ob->ob; diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 4732586b912..e035f1c3f5a 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -841,7 +841,7 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr) if (ob->transflag & OB_DUPLI) { DupliObject *dob; - ListBase *lb = object_duplilist(shi->gpumat->scene, ob); + ListBase *lb = object_duplilist(shi->gpumat->scene, ob, FALSE); for (dob=lb->first; dob; dob=dob->next) { Object *ob_iter = dob->ob; diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 6e20375d9c6..ffc78ef8ca4 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -409,7 +409,7 @@ int rna_IDMaterials_assign_int(struct PointerRNA *ptr, int key, const struct Poi /* Internal functions that cycles uses so we need to declare (tsk tsk) */ struct Mesh *rna_Object_to_mesh(struct Object *ob, struct ReportList *reports, struct Scene *sce, int apply_modifiers, int settings); void rna_Main_meshes_remove(struct Main *bmain, struct ReportList *reports, struct Mesh *mesh); -void rna_Object_create_duplilist(struct Object *ob, struct ReportList *reports, struct Scene *sce); +void rna_Object_create_duplilist(struct Object *ob, struct ReportList *reports, struct Scene *sce, int settings); void rna_Object_free_duplilist(struct Object *ob); void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values); void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index b03d348b49d..d650c8dbf69 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1720,6 +1720,16 @@ static void def_sh_tex_wave(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_Node_update"); } +static void def_sh_tex_coord(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "from_dupli", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); + RNA_def_property_ui_text(prop, "From Dupli", "Use the parent of the dupli object if possible"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_glossy(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h index 0baa4cc0838..db1e1e16adf 100644 --- a/source/blender/makesrna/intern/rna_nodetree_types.h +++ b/source/blender/makesrna/intern/rna_nodetree_types.h @@ -92,7 +92,7 @@ DefNode( ShaderNode, SH_NODE_TEX_MUSGRAVE, def_sh_tex_musgrave, "TE DefNode( ShaderNode, SH_NODE_TEX_VORONOI, def_sh_tex_voronoi, "TEX_VORONOI", TexVoronoi, "Voronoi Texture", "" ) DefNode( ShaderNode, SH_NODE_TEX_CHECKER, def_sh_tex_checker, "TEX_CHECKER", TexChecker, "Checker Texture", "" ) DefNode( ShaderNode, SH_NODE_TEX_BRICK, def_sh_tex_brick, "TEX_BRICK", TexBrick, "Brick Texture", "" ) -DefNode( ShaderNode, SH_NODE_TEX_COORD, 0, "TEX_COORD", TexCoord, "Texture Coordinate","" ) +DefNode( ShaderNode, SH_NODE_TEX_COORD, def_sh_tex_coord, "TEX_COORD", TexCoord, "Texture Coordinate","" ) DefNode( CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" ) DefNode( CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" ) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index a10c153515a..758b433b1cb 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2572,7 +2572,16 @@ static void rna_def_dupli_object(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); RNA_def_property_ui_text(prop, "Particle Index", "Index in the lowest-level particle dupli list"); - /* TODO: DupliObject has more properties that can be wrapped */ + prop = RNA_def_property(srna, "orco", PROP_FLOAT, PROP_TRANSLATION); + RNA_def_property_float_sdna(prop, NULL, "orco"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Generated Coordinates", "Generated coordinates in parent object space"); + + prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "uv"); + RNA_def_property_array(prop, 2); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); + RNA_def_property_ui_text(prop, "UV Coordinates", "UV coordinates in parent object space"); } static void rna_def_object_base(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index a6f49d80b25..b0b76c9e38f 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -337,8 +337,10 @@ static void dupli_render_particle_set(Scene *scene, Object *ob, int level, int e dupli_render_particle_set(scene, go->ob, level + 1, enable); } /* When no longer needed, duplilist should be freed with Object.free_duplilist */ -void rna_Object_create_duplilist(Object *ob, ReportList *reports, Scene *sce) +void rna_Object_create_duplilist(Object *ob, ReportList *reports, Scene *sce, int settings) { + int for_render = settings == eModifierMode_Render; + if (!(ob->transflag & OB_DUPLI)) { BKE_report(reports, RPT_ERROR, "Object does not have duplis"); return; @@ -353,7 +355,7 @@ void rna_Object_create_duplilist(Object *ob, ReportList *reports, Scene *sce) } if (G.is_rendering) dupli_render_particle_set(sce, ob, 0, 1); - ob->duplilist = object_duplilist(sce, ob); + ob->duplilist = object_duplilist(sce, ob, for_render); if (G.is_rendering) dupli_render_particle_set(sce, ob, 0, 0); /* ob->duplilist should now be freed with Object.free_duplilist */ @@ -608,6 +610,7 @@ void RNA_api_object(StructRNA *srna) "objects real matrix and layers"); parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate duplis"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Generate texture coordinates for rendering"); RNA_def_function_flag(func, FUNC_USE_REPORTS); func = RNA_def_function(srna, "dupli_list_clear", "rna_Object_free_duplilist"); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c index 86f71f6f05b..62b1cabd491 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c @@ -57,7 +57,7 @@ void register_node_type_sh_tex_coord(bNodeTreeType *ttype) { static bNodeType ntype; - node_type_base(ttype, &ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT, 0); + node_type_base(ttype, &ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT, NODE_OPTIONS); node_type_compatibility(&ntype, NODE_NEW_SHADING); node_type_socket_templates(&ntype, NULL, sh_node_tex_coord_out); node_type_size(&ntype, 150, 60, 200); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 78b4c3b8787..b3948563a87 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -4895,7 +4895,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp /* create list of duplis generated by this object, particle * system need to have render settings set for dupli particles */ dupli_render_particle_set(re, ob, timeoffset, 0, 1); - lb= object_duplilist(re->scene, ob); + lb= object_duplilist(re->scene, ob, TRUE); dupli_render_particle_set(re, ob, timeoffset, 0, 0); for (dob= lb->first; dob; dob= dob->next) { From 3eba19881894c17d2645f9e9723eae1be822e55a Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Thu, 4 Oct 2012 23:44:03 +0000 Subject: [PATCH 088/143] * Fix Scons build when OCIO is disabled. Still fails when it's enabled though (unresolved symbols). --- intern/opencolorio/SConscript | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/opencolorio/SConscript b/intern/opencolorio/SConscript index 229087a568d..a4d21f3e440 100644 --- a/intern/opencolorio/SConscript +++ b/intern/opencolorio/SConscript @@ -8,12 +8,12 @@ incs = '. ../guardedalloc ../../source/blender/blenlib' defs = [] if env['WITH_BF_OCIO']: - incs += ' ' + env['BF_OCIO_INC'] defs.append('WITH_OCIO') + incs += ' ' + env['BF_OCIO_INC'] if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): incs += ' ' + env['BF_BOOST_INC'] else: - sources.remove('ocio_capi.cc') + sources.remove('ocio_impl.cc') env.BlenderLib( 'bf_intern_opencolorio', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185]) From 7339b09e7f2fa59cb672ce103036552fcbea0a72 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 01:27:28 +0000 Subject: [PATCH 089/143] add ED_view3d_project_float_global, ED_view3d_project_float_object, ED_view3d_project_float_ex function calls and cleanup cursor3d set function which had some odd logic. --- source/blender/editors/include/ED_view3d.h | 6 +++ .../editors/space_view3d/view3d_edit.c | 51 ++++++++----------- .../editors/space_view3d/view3d_view.c | 36 ++++++++++++- 3 files changed, 60 insertions(+), 33 deletions(-) diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 30eb38a14bb..7642ce565a0 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -144,6 +144,12 @@ eV3DProjStatus ED_view3d_project_int_ex(struct ARegion *ar, float perspmat[4][4] eV3DProjStatus ED_view3d_project_int_global(struct ARegion *ar, const float co[3], int r_co[2], eV3DProjTest flag); eV3DProjStatus ED_view3d_project_int_object(struct ARegion *ar, const float co[3], int r_co[2], eV3DProjTest flag); +/* *** float *** */ +eV3DProjStatus ED_view3d_project_float_ex(struct ARegion *ar, float perspmat[4][4], const int is_local, + const float co[3], float r_co[2], eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_float_global(struct ARegion *ar, const float co[3], float r_co[2], eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_float_object(struct ARegion *ar, const float co[3], float r_co[2], eV3DProjTest flag); + void ED_view3d_project_float(struct ARegion *ar, const float co[3], float r_co[2]); void ED_view3d_project_float_noclip(struct ARegion *ar, const float co[3], float r_co[2]); void ED_view3d_project_float_v2_m4(const struct ARegion *a, const float co[3], float r_co[2], float mat[4][4]); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 800b4ac53c8..735f7b5ea4a 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3514,60 +3514,49 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) /* ***************** 3d cursor cursor op ******************* */ /* mx my in region coords */ -static int set_3dcursor_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) { Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); - float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3]; - int mval[2]; -// short ctrl= 0; // XXX + float *fp = NULL; + float mval_fl[2]; int flip; - eV3DProjStatus ret; fp = give_cursor(scene, v3d); -// if (obedit && ctrl) lr_click= 1; - copy_v3_v3(oldcurs, fp); - - mval[0] = IS_CLIPPED; - ret = ED_view3d_project_int_global(ar, fp, mval, V3D_PROJ_TEST_NOP); flip = initgrabz(rv3d, fp[0], fp[1], fp[2]); - /* reset the depth based on the view offset */ + /* reset the depth based on the view offset (we _know_ the offset is infront of us) */ if (flip) { negate_v3_v3(fp, rv3d->ofs); - - /* re initialize */ - mval[0] = IS_CLIPPED; - ED_view3d_project_int_global(ar, fp, mval, V3D_PROJ_TEST_NOP); - flip = initgrabz(rv3d, fp[0], fp[1], fp[2]); - (void)flip; + /* re initialize, no need to check flip again */ + /* flip = */ initgrabz(rv3d, fp[0], fp[1], fp[2]); } - if (mval[0] != IS_CLIPPED) { - short depth_used = 0; + if (ED_view3d_project_float_global(ar, fp, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + short depth_used = FALSE; if (U.uiflag & USER_ZBUF_CURSOR) { /* maybe this should be accessed some other way */ view3d_operator_needs_opengl(C); if (ED_view3d_autodist(scene, ar, v3d, event->mval, fp)) - depth_used = 1; + depth_used = TRUE; } - if (depth_used == 0) { - float mval_f[2]; - VECSUB2D(mval_f, mval, event->mval); - ED_view3d_win_to_delta(ar, mval_f, dvec); + if (depth_used == FALSE) { + float dvec[3]; + VECSUB2D(mval_fl, mval_fl, event->mval); + ED_view3d_win_to_delta(ar, mval_fl, dvec); sub_v3_v3(fp, dvec); } } else { - - dx = ((float)(event->mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2); - dy = ((float)(event->mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2); - - fz = rv3d->persmat[0][3] * fp[0] + rv3d->persmat[1][3] * fp[1] + rv3d->persmat[2][3] * fp[2] + rv3d->persmat[3][3]; - fz = fz / rv3d->zfac; + const float dx = ((float)(event->mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2); + const float dy = ((float)(event->mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2); + const float fz = (rv3d->persmat[0][3] * fp[0] + + rv3d->persmat[1][3] * fp[1] + + rv3d->persmat[2][3] * fp[2] + + rv3d->persmat[3][3]) / rv3d->zfac; fp[0] = (rv3d->persinv[0][0] * dx + rv3d->persinv[1][0] * dy + rv3d->persinv[2][0] * fz) - rv3d->ofs[0]; fp[1] = (rv3d->persinv[0][1] * dx + rv3d->persinv[1][1] * dy + rv3d->persinv[2][1] * fz) - rv3d->ofs[1]; @@ -3591,7 +3580,7 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot) ot->idname = "VIEW3D_OT_cursor3d"; /* api callbacks */ - ot->invoke = set_3dcursor_invoke; + ot->invoke = view3d_cursor3d_invoke; ot->poll = ED_operator_view3d_active; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index cdb75cdfa74..ac721f3ea2e 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -965,7 +965,7 @@ eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], con r_co[1] = (short)floor(tvec[1]); } else { - return V3D_PROJ_RET_OVERFLOW; + ret = V3D_PROJ_RET_OVERFLOW; } } return ret; @@ -984,7 +984,25 @@ eV3DProjStatus ED_view3d_project_int_ex(ARegion *ar, float perspmat[4][4], const r_co[1] = (int)floor(tvec[1]); } else { - return V3D_PROJ_RET_OVERFLOW; + ret = V3D_PROJ_RET_OVERFLOW; + } + } + return ret; +} + +eV3DProjStatus ED_view3d_project_float_ex(ARegion *ar, float perspmat[4][4], const int is_local, + const float co[3], float r_co[2], eV3DProjTest flag) +{ + float tvec[2]; + eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag); + if (ret == V3D_PROJ_RET_SUCCESS) { + if (finite(tvec[0]) && + finite(tvec[1])) + { + copy_v2_v2(r_co, tvec); + } + else { + ret = V3D_PROJ_RET_OVERFLOW; } } return ret; @@ -1016,6 +1034,20 @@ eV3DProjStatus ED_view3d_project_int_object(ARegion *ar, const float co[3], int return ED_view3d_project_int_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); } +/* --- float --- */ +eV3DProjStatus ED_view3d_project_float_global(ARegion *ar, const float co[3], float r_co[2], eV3DProjTest flag) +{ + RegionView3D *rv3d = ar->regiondata; + return ED_view3d_project_float_ex(ar, rv3d->persmat, FALSE, co, r_co, flag); +} +/* object space, use ED_view3d_init_mats_rv3d before calling */ +eV3DProjStatus ED_view3d_project_float_object(ARegion *ar, const float co[3], float r_co[2], eV3DProjTest flag) +{ + RegionView3D *rv3d = ar->regiondata; + return ED_view3d_project_float_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); +} + + void ED_view3d_project_float(ARegion *ar, const float co[3], float r_co[2]) { RegionView3D *rv3d = ar->regiondata; From 61ce7926d305080d01a4903fb8dc90c5d74cf197 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 01:34:47 +0000 Subject: [PATCH 090/143] code cleanup: quiet warnings and use define for transform snap max distance. --- .../blender/editors/armature/meshlaplacian.c | 53 ++++++++++--------- .../editors/transform/transform_snap.c | 8 +-- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 5ca06c62c46..522622ec5c4 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -1133,8 +1133,9 @@ typedef struct MeshDeformIsect { /* our own triangle intersection, so we can fully control the epsilons and * prevent corner case from going wrong*/ -static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3], - float vert1[3], float vert2[3], float *isectco, float *uvw) +static int meshdeform_tri_intersect(const float orig[3], const float end[3], const float vert0[3], + const float vert1[3], const float vert2[3], + float r_isectco[3], float r_uvw[3]) { float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; float det, inv_det, u, v, dir[3], isectdir[3]; @@ -1151,8 +1152,10 @@ static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3], /* if determinant is near zero, ray lies in plane of triangle */ det = dot_v3v3(edge1, pvec); - if (det == 0.0f) + if (UNLIKELY(det == 0.0f)) { return 0; + } + inv_det = 1.0f / det; /* calculate distance from vert0 to ray origin */ @@ -1171,16 +1174,16 @@ static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3], if (v < -EPSILON || u + v > 1.0f + EPSILON) return 0; - isectco[0] = (1.0f - u - v) * vert0[0] + u * vert1[0] + v * vert2[0]; - isectco[1] = (1.0f - u - v) * vert0[1] + u * vert1[1] + v * vert2[1]; - isectco[2] = (1.0f - u - v) * vert0[2] + u * vert1[2] + v * vert2[2]; + r_isectco[0] = (1.0f - u - v) * vert0[0] + u * vert1[0] + v * vert2[0]; + r_isectco[1] = (1.0f - u - v) * vert0[1] + u * vert1[1] + v * vert2[1]; + r_isectco[2] = (1.0f - u - v) * vert0[2] + u * vert1[2] + v * vert2[2]; - uvw[0] = 1.0f - u - v; - uvw[1] = u; - uvw[2] = v; + r_uvw[0] = 1.0f - u - v; + r_uvw[1] = u; + r_uvw[2] = v; /* check if it is within the length of the line segment */ - sub_v3_v3v3(isectdir, isectco, orig); + sub_v3_v3v3(isectdir, r_isectco, orig); if (dot_v3v3(dir, isectdir) < -EPSILON) return 0; @@ -1191,7 +1194,7 @@ static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3], return 1; } -void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { void **data = userdata; MeshDeformBind *mdb = data[1]; @@ -1224,7 +1227,7 @@ void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *ray, BVH hit->dist = dist; copy_v3_v3(hit->co, co); - isec->isect = INPR(no, ray->direction) <= 0.0; + isec->isect = dot_v3v3(no, ray->direction) <= 0.0; isec->labda = dist; isec->face = mf; } @@ -1234,34 +1237,34 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float { MDefBoundIsect *isect; BVHTreeRayHit hit; - MeshDeformIsect isec; + MeshDeformIsect isect_mdef; float (*cagecos)[3]; - void *data[3] = {mdb->cagedm->getTessFaceArray(mdb->cagedm), mdb, &isec}; + void *data[3] = {mdb->cagedm->getTessFaceArray(mdb->cagedm), mdb, &isect_mdef}; MFace *mface1 = data[0], *mface; float vert[4][3], len, end[3]; static float epsilon[3] = {0, 0, 0}; //1e-4, 1e-4, 1e-4}; /* setup isec */ - memset(&isec, 0, sizeof(isec)); - isec.labda = 1e10f; + memset(&isect_mdef, 0, sizeof(isect_mdef)); + isect_mdef.labda = 1e10f; - add_v3_v3v3(isec.start, co1, epsilon); + add_v3_v3v3(isect_mdef.start, co1, epsilon); add_v3_v3v3(end, co2, epsilon); - sub_v3_v3v3(isec.vec, end, isec.start); + sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start); hit.index = -1; hit.dist = FLT_MAX; - if (BLI_bvhtree_ray_cast(mdb->bvhtree, isec.start, isec.vec, 0.0, &hit, harmonic_ray_callback, data) != -1) { - len= isec.labda; - isec.face = mface = mface1 + hit.index; + if (BLI_bvhtree_ray_cast(mdb->bvhtree, isect_mdef.start, isect_mdef.vec, 0.0, &hit, harmonic_ray_callback, data) != -1) { + len= isect_mdef.labda; + isect_mdef.face = mface = mface1 + hit.index; /* create MDefBoundIsect */ isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect)); /* compute intersection coordinate */ - isect->co[0] = co1[0] + isec.vec[0] * len; - isect->co[1] = co1[1] + isec.vec[1] * len; - isect->co[2] = co1[2] + isec.vec[2] * len; + isect->co[0] = co1[0] + isect_mdef.vec[0] * len; + isect->co[1] = co1[1] + isect_mdef.vec[1] * len; + isect->co[2] = co1[2] + isect_mdef.vec[2] * len; isect->len = len_v3v3(co1, isect->co); if (isect->len < MESHDEFORM_LEN_THRESHOLD) @@ -1273,7 +1276,7 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float isect->v[3] = mface->v4; isect->nvert = (mface->v4) ? 4 : 3; - isect->facing = isec.isect; + isect->facing = isect_mdef.isect; /* compute mean value coordinates for interpolation */ cagecos = mdb->cagecos; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 700869e10d5..c12c84b5ff5 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -80,6 +80,8 @@ #define USE_BVH_FACE_SNAP +#define TRANSFORM_DIST_MAX_PX 1000 + /********************* PROTOTYPES ***********************/ static void setSnappingCallback(TransInfo *t); @@ -296,7 +298,7 @@ void applyProject(TransInfo *t) for (i = 0; i < t->total; i++, td++) { float iloc[3], loc[3], no[3]; float mval[2]; - int dist = 1000; + int dist = TRANSFORM_DIST_MAX_PX; if (td->flag & TD_NOACTION) break; @@ -1238,7 +1240,7 @@ static int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], sh new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]); } else { - new_dist = 1000; + new_dist = TRANSFORM_DIST_MAX_PX; } /* 10% threshold if edge is closer but a bit further @@ -1299,7 +1301,7 @@ static int snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[][4], new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]); } else { - new_dist = 1000; + new_dist = TRANSFORM_DIST_MAX_PX; } From 080f4441d2e7538c99c22621991bdd6c11a8476f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 03:06:01 +0000 Subject: [PATCH 091/143] Improvements for knife tool execute function (code was a bit sloppy & could leak memory). - vertex to screenspace projections were not checking for failure to project (vertex behind the view for eg). - vertex screenspace 2d vectors were each malloc'd and added to own ghash, then fetched for each edge. now just store a vertex aligned array and do index lookups. - projections were done in global space, now do them in object space (avoids a matrix multiply). - error cases were commented out and would fail silently, now report them to the operator. - remove MAX_CUTS hard coded limit, dynamically allocate the mouse path. - add missing free calls in error cases. --- source/blender/editors/mesh/editmesh_tools.c | 137 ++++++++++--------- 1 file changed, 73 insertions(+), 64 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 1d96a3a958d..23348eed2b4 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -2527,11 +2527,6 @@ void MESH_OT_solidify(wmOperatorType *ot) RNA_def_property_ui_range(prop, -10, 10, 0.1, 4); } -typedef struct CutCurve { - float x; - float y; -} CutCurve; - /* ******************************************************************** */ /* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail * drawn by user. @@ -2565,15 +2560,14 @@ static EnumPropertyItem knife_items[] = { /* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */ -static float bm_edge_seg_isect(BMEdge *e, CutCurve *c, int len, char mode, - struct GHash *gh, int *isected) +static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], + float (*mouse_path)[2], int len, char mode, int *isected) { #define MAXSLOPE 100000 float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max; float y2min, dist, lastdist = 0, xdiff2, xdiff1; float m1, b1, m2, b2, x21, x22, y21, y22, xi; float yi, x1min, x1max, y1max, y1min, perc = 0; - float *scr; float threshold = 0.0; int i; @@ -2581,13 +2575,11 @@ static float bm_edge_seg_isect(BMEdge *e, CutCurve *c, int len, char mode, // XXX threshold = scene->toolsettings->select_thresh / 100; /* Get screen coords of verts */ - scr = BLI_ghash_lookup(gh, e->v1); - x21 = scr[0]; - y21 = scr[1]; + x21 = sco_a[0]; + y21 = sco_a[1]; - scr = BLI_ghash_lookup(gh, e->v2); - x22 = scr[0]; - y22 = scr[1]; + x22 = sco_b[0]; + y22 = sco_b[1]; xdiff2 = (x22 - x21); if (xdiff2) { @@ -2609,11 +2601,11 @@ static float bm_edge_seg_isect(BMEdge *e, CutCurve *c, int len, char mode, y11 = y12; } else { - x11 = c[i].x; - y11 = c[i].y; + x11 = mouse_path[i][0]; + y11 = mouse_path[i][1]; } - x12 = c[i].x; - y12 = c[i].y; + x12 = mouse_path[i][0]; + y12 = mouse_path[i][1]; /* test e->v1 */ if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) { @@ -2637,11 +2629,11 @@ static float bm_edge_seg_isect(BMEdge *e, CutCurve *c, int len, char mode, y11 = y12; } else { - x11 = c[i].x; - y11 = c[i].y; + x11 = mouse_path[i][0]; + y11 = mouse_path[i][1]; } - x12 = c[i].x; - y12 = c[i].y; + x12 = mouse_path[i][0]; + y12 = mouse_path[i][1]; /* Perp. Distance from point to line */ if (m2 != MAXSLOPE) dist = (y12 - m2 * x12 - b2); /* /sqrt(m2 * m2 + 1); Only looking for */ @@ -2719,9 +2711,9 @@ static float bm_edge_seg_isect(BMEdge *e, CutCurve *c, int len, char mode, lastdist = dist; } return perc; -} +} -#define MAX_CUTS 2048 +#define ELE_EDGE_CUT 1 static int edbm_knife_cut_exec(bContext *C, wmOperator *op) { @@ -2733,76 +2725,93 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) BMIter iter; BMEdge *be; BMOperator bmop; - CutCurve curve[MAX_CUTS]; - struct GHash *gh; float isect = 0.0f; - float *scr, co[4]; - int len = 0, isected; + int len = 0, isected, i; short numcuts = 1, mode = RNA_int_get(op->ptr, "type"); + + /* allocd vars */ + float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2]; /* edit-object needed for matrix, and ar->regiondata for projections to work */ if (ELEM3(NULL, obedit, ar, ar->regiondata)) return OPERATOR_CANCELLED; if (bm->totvertsel < 2) { - //error("No edges are selected to operate on"); + BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on"); return OPERATOR_CANCELLED; } + len = RNA_collection_length(op->ptr, "path"); + + if (len < 2) { + BKE_report(op->reports, RPT_ERROR, "Mouse path too short"); + return OPERATOR_CANCELLED; + } + + mouse_path = MEM_mallocN(len * sizeof(*mouse_path), __func__); + /* get the cut curve */ RNA_BEGIN(op->ptr, itemptr, "path") { - RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]); - len++; - if (len >= MAX_CUTS) { - break; - } + RNA_float_get_array(&itemptr, "loc", (float *)&mouse_path[len]); } RNA_END; - - if (len < 2) { - return OPERATOR_CANCELLED; - } + + /* for ED_view3d_project_float_object */ + ED_view3d_init_mats_rv3d(obedit, ar->regiondata); + + /* TODO, investigate using index lookup for screen_vert_coords() rather then a hash table */ /* the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer */ - gh = BLI_ghash_ptr_new("knife cut exec"); - for (bv = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); bv; bv = BM_iter_step(&iter)) { - scr = MEM_mallocN(sizeof(float) * 2, "Vertex Screen Coordinates"); - copy_v3_v3(co, bv->co); - co[3] = 1.0f; - mul_m4_v4(obedit->obmat, co); - ED_view3d_project_float(ar, co, scr); - BLI_ghash_insert(gh, bv, scr); + screen_vert_coords = sco = MEM_mallocN(bm->totvert * sizeof(float) * 2, __func__); + + BM_ITER_MESH_INDEX (bv, &iter, bm, BM_VERTS_OF_MESH, i) { + if (ED_view3d_project_float_object(ar, bv->co, *sco, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) { + copy_v2_fl(*sco, FLT_MAX); /* set error value */ + } + BM_elem_index_set(bv, i); /* set_ok */ + sco++; + } + bm->elem_index_dirty &= ~BM_VERT; /* clear dirty flag */ if (!EDBM_op_init(em, &bmop, op, "subdivide_edges")) { + MEM_freeN(mouse_path); + MEM_freeN(screen_vert_coords); return OPERATOR_CANCELLED; } /* store percentage of edge cut for KNIFE_EXACT here.*/ for (be = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); be; be = BM_iter_step(&iter)) { + int is_cut = FALSE; if (BM_elem_flag_test(be, BM_ELEM_SELECT)) { - isect = bm_edge_seg_isect(be, curve, len, mode, gh, &isected); - - if (isect != 0.0f) { - if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) { - BMO_slot_map_float_insert(bm, &bmop, - "edgepercents", - be, isect); + const float *sco_a = screen_vert_coords[BM_elem_index_get(be->v1)]; + const float *sco_b = screen_vert_coords[BM_elem_index_get(be->v2)]; + /* check for error value (vert cant be projected) */ + if ((sco_a[0] != FLT_MAX) && (sco_b[0] != FLT_MAX)) { + isect = bm_edge_seg_isect(sco_a, sco_b, mouse_path, len, mode, &isected); + + if (isect != 0.0f) { + if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) { + BMO_slot_map_float_insert(bm, &bmop, + "edgepercents", + be, isect); + } } - BMO_elem_flag_enable(bm, be, 1); - } - else { - BMO_elem_flag_disable(bm, be, 1); } } - else { - BMO_elem_flag_disable(bm, be, 1); - } + + BMO_elem_flag_set(bm, be, ELE_EDGE_CUT, is_cut); } - - BMO_slot_buffer_from_enabled_flag(bm, &bmop, "edges", BM_EDGE, 1); + + + /* free all allocs */ + MEM_freeN(screen_vert_coords); + MEM_freeN(mouse_path); + + + BMO_slot_buffer_from_enabled_flag(bm, &bmop, "edges", BM_EDGE, ELE_EDGE_CUT); if (mode == KNIFE_MIDPOINT) numcuts = 1; BMO_slot_int_set(&bmop, "numcuts", numcuts); @@ -2817,14 +2826,14 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) if (!EDBM_op_finish(em, &bmop, op, TRUE)) { return OPERATOR_CANCELLED; } - - BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); EDBM_update_generic(C, em, TRUE); return OPERATOR_FINISHED; } +#undef ELE_EDGE_CUT + void MESH_OT_knife_cut(wmOperatorType *ot) { PropertyRNA *prop; From b9113f205ceb7bc1f8620024a0adf4b4eb681792 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 03:20:14 +0000 Subject: [PATCH 092/143] replace ED_view3d_project_float with ED_view3d_project_float_global --- .../editors/armature/editarmature_sketch.c | 20 ++++++++-------- source/blender/editors/include/ED_view3d.h | 1 - .../editors/sculpt_paint/paint_cursor.c | 15 ++++++++---- .../editors/space_view3d/view3d_view.c | 19 --------------- .../editors/transform/transform_snap.c | 24 +++++++++---------- 5 files changed, 32 insertions(+), 47 deletions(-) diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index b72fad08d1f..5ba4a232250 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -910,9 +910,9 @@ static void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end, for (i = start; i <= end; i++) { float ray_start[3], ray_normal[3]; float delta = len_v3v3(stk->points[i].p, stk->points[i + 1].p); - float pval[2]; + float pval[2] = {0, 0}; - ED_view3d_project_float(ar, stk->points[i].p, pval); + ED_view3d_project_float_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP); ED_view3d_win_to_ray(ar, v3d, pval, ray_start, ray_normal); mul_v3_fl(ray_normal, distance * progress / length); @@ -1462,8 +1462,8 @@ static int sk_getSelfIntersections(bContext *C, ListBase *list, SK_Stroke *gestu float s_p2[3] = {0, 0, 0}; int g_i; - ED_view3d_project_float(ar, gesture->points[s_i].p, s_p1); - ED_view3d_project_float(ar, gesture->points[s_i + 1].p, s_p2); + ED_view3d_project_float_global(ar, gesture->points[s_i].p, s_p1, V3D_PROJ_TEST_NOP); + ED_view3d_project_float_global(ar, gesture->points[s_i + 1].p, s_p2, V3D_PROJ_TEST_NOP); /* start checking from second next, because two consecutive cannot intersect */ for (g_i = s_i + 2; g_i < gesture->nb_points - 1; g_i++) { @@ -1472,8 +1472,8 @@ static int sk_getSelfIntersections(bContext *C, ListBase *list, SK_Stroke *gestu float vi[3]; float lambda; - ED_view3d_project_float(ar, gesture->points[g_i].p, g_p1); - ED_view3d_project_float(ar, gesture->points[g_i + 1].p, g_p2); + ED_view3d_project_float_global(ar, gesture->points[g_i].p, g_p1, V3D_PROJ_TEST_NOP); + ED_view3d_project_float_global(ar, gesture->points[g_i + 1].p, g_p2, V3D_PROJ_TEST_NOP); if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) { SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection"); @@ -1540,8 +1540,8 @@ static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, S float s_p2[3] = {0, 0, 0}; int g_i; - ED_view3d_project_float(ar, stk->points[s_i].p, s_p1); - ED_view3d_project_float(ar, stk->points[s_i + 1].p, s_p2); + ED_view3d_project_float_global(ar, stk->points[s_i].p, s_p1, V3D_PROJ_TEST_NOP); + ED_view3d_project_float_global(ar, stk->points[s_i + 1].p, s_p2, V3D_PROJ_TEST_NOP); for (g_i = 0; g_i < gesture->nb_points - 1; g_i++) { float g_p1[3] = {0, 0, 0}; @@ -1549,8 +1549,8 @@ static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, S float vi[3]; float lambda; - ED_view3d_project_float(ar, gesture->points[g_i].p, g_p1); - ED_view3d_project_float(ar, gesture->points[g_i + 1].p, g_p2); + ED_view3d_project_float_global(ar, gesture->points[g_i].p, g_p1, V3D_PROJ_TEST_NOP); + ED_view3d_project_float_global(ar, gesture->points[g_i + 1].p, g_p2, V3D_PROJ_TEST_NOP); if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) { SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection"); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 7642ce565a0..60ade1ee9bb 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -150,7 +150,6 @@ eV3DProjStatus ED_view3d_project_float_ex(struct ARegion *ar, float perspmat[4][ eV3DProjStatus ED_view3d_project_float_global(struct ARegion *ar, const float co[3], float r_co[2], eV3DProjTest flag); eV3DProjStatus ED_view3d_project_float_object(struct ARegion *ar, const float co[3], float r_co[2], eV3DProjTest flag); -void ED_view3d_project_float(struct ARegion *ar, const float co[3], float r_co[2]); void ED_view3d_project_float_noclip(struct ARegion *ar, const float co[3], float r_co[2]); void ED_view3d_project_float_v2_m4(const struct ARegion *a, const float co[3], float r_co[2], float mat[4][4]); void ED_view3d_project_float_v3_m4(struct ARegion *a, const float co[3], float r_co[3], float mat[4][4]); diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index e14266c83a7..6120229190d 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -322,11 +322,16 @@ static int project_brush_radius(ViewContext *vc, add_v3_v3v3(offset, location, ortho); /* project the center of the brush, and the tangent point to the view onto the screen */ - ED_view3d_project_float(vc->ar, location, p1); - ED_view3d_project_float(vc->ar, offset, p2); - - /* the distance between these points is the size of the projected brush in pixels */ - return len_v2v2(p1, p2); + if ((ED_view3d_project_float_global(vc->ar, location, p1, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) && + (ED_view3d_project_float_global(vc->ar, offset, p2, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS)) + { + /* the distance between these points is the size of the projected brush in pixels */ + return len_v2v2(p1, p2); + } + else { + BLI_assert(0); /* assert because the code that sets up the vectors should disallow this */ + return 0; + } } static int sculpt_get_brush_geometry(bContext *C, ViewContext *vc, diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index ac721f3ea2e..0e4f64d2e53 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1047,25 +1047,6 @@ eV3DProjStatus ED_view3d_project_float_object(ARegion *ar, const float co[3], fl return ED_view3d_project_float_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); } - -void ED_view3d_project_float(ARegion *ar, const float co[3], float r_co[2]) -{ - RegionView3D *rv3d = ar->regiondata; - - float vec4[4]; - - copy_v3_v3(vec4, co); - vec4[3] = 1.0; - r_co[0] = IS_CLIPPED; - - mul_m4_v4(rv3d->persmat, vec4); - - if (vec4[3] > (float)BL_NEAR_CLIP) { - r_co[0] = (float)(ar->winx / 2.0f) + (ar->winx / 2.0f) * vec4[0] / vec4[3]; - r_co[1] = (float)(ar->winy / 2.0f) + (ar->winy / 2.0f) * vec4[1] / vec4[3]; - } -} - void ED_view3d_project_float_noclip(ARegion *ar, const float co[3], float r_co[2]) { RegionView3D *rv3d = ar->regiondata; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index c12c84b5ff5..2f2b31de89d 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -317,18 +317,18 @@ void applyProject(TransInfo *t) copy_v3_v3(iloc, td->ob->obmat[3]); } - ED_view3d_project_float(t->ar, iloc, mval); - - if (snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.modeSelect)) { -// if (t->flag & (T_EDIT|T_POSE)) { -// mul_m4_v3(imat, loc); -// } -// - sub_v3_v3v3(tvec, loc, iloc); - - mul_m3_v3(td->smtx, tvec); - - add_v3_v3(td->loc, tvec); + if (ED_view3d_project_float_global(t->ar, iloc, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + if (snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.modeSelect)) { +// if (t->flag & (T_EDIT|T_POSE)) { +// mul_m4_v3(imat, loc); +// } + + sub_v3_v3v3(tvec, loc, iloc); + + mul_m3_v3(td->smtx, tvec); + + add_v3_v3(td->loc, tvec); + } } //XXX constraintTransLim(t, td); From 5770e44f43d64066162a94c036d5e1a8730eda0f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 03:57:56 +0000 Subject: [PATCH 093/143] replace most uses of ED_view3d_project_float_noclip() with ED_view3d_project_float_global/object --- source/blender/editors/include/ED_mesh.h | 2 +- source/blender/editors/mesh/editmesh_slide.c | 31 +++++----- source/blender/editors/mesh/editmesh_tools.c | 58 ++++++++++--------- source/blender/editors/mesh/meshtools.c | 11 ++-- .../editors/sculpt_paint/paint_vertex.c | 26 +++++---- source/blender/editors/transform/transform.c | 18 +++--- 6 files changed, 82 insertions(+), 64 deletions(-) diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 02c7d52f08d..62818612509 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -174,7 +174,7 @@ void ED_spacetypes_init(void); /* editmesh_tools.c (could be moved) */ -void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct Object *obedit, struct BMEditMesh *em); +void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct BMEditMesh *em); /* editface.c */ diff --git a/source/blender/editors/mesh/editmesh_slide.c b/source/blender/editors/mesh/editmesh_slide.c index bd1d13f3528..e42b95c6013 100644 --- a/source/blender/editors/mesh/editmesh_slide.c +++ b/source/blender/editors/mesh/editmesh_slide.c @@ -381,22 +381,23 @@ static BMEdge *vtx_slide_nrst_in_frame(VertexSlideOp *vso, const float mval[2]) BMEdge *edge = NULL; float v1_proj[3], v2_proj[3]; - float dist = 0; float min_dist = FLT_MAX; for (i = 0; i < vso->disk_edges; i++) { edge = vso->edge_frame[i]; mul_v3_m4v3(v1_proj, vso->obj->obmat, edge->v1->co); - ED_view3d_project_float_noclip(vso->active_region, v1_proj, v1_proj); - mul_v3_m4v3(v2_proj, vso->obj->obmat, edge->v2->co); - ED_view3d_project_float_noclip(vso->active_region, v2_proj, v2_proj); - dist = dist_to_line_segment_v2(mval, v1_proj, v2_proj); - if (dist < min_dist) { - min_dist = dist; - cl_edge = edge; + /* we could use ED_view3d_project_float_object here, but for now dont since we dont have the context */ + if ((ED_view3d_project_float_global(vso->active_region, v1_proj, v1_proj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) && + (ED_view3d_project_float_global(vso->active_region, v2_proj, v2_proj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS)) + { + const float dist = dist_to_line_segment_v2(mval, v1_proj, v2_proj); + if (dist < min_dist) { + min_dist = dist; + cl_edge = edge; + } } } } @@ -448,17 +449,21 @@ static void vtx_slide_update(VertexSlideOp *vso, wmEvent *event) /* Calculate interpolation value for preview */ float t_val; - float mval_float[] = { (float)event->mval[0], (float)event->mval[1]}; + float mval_float[2] = { (float)event->mval[0], (float)event->mval[1]}; float closest_2d[2]; other = BM_edge_other_vert(edge, vso->start_vtx); /* Project points onto screen and do interpolation in 2D */ mul_v3_m4v3(start_vtx_proj, vso->obj->obmat, vso->start_vtx->co); - ED_view3d_project_float_noclip(vso->active_region, start_vtx_proj, start_vtx_proj); - mul_v3_m4v3(edge_other_proj, vso->obj->obmat, other->co); - ED_view3d_project_float_noclip(vso->active_region, edge_other_proj, edge_other_proj); + + if ((ED_view3d_project_float_global(vso->active_region, edge_other_proj, edge_other_proj, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) || + (ED_view3d_project_float_global(vso->active_region, start_vtx_proj, start_vtx_proj, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS)) + { + /* not much we can do here */ + return; + } closest_to_line_v2(closest_2d, mval_float, start_vtx_proj, edge_other_proj); @@ -470,7 +475,7 @@ static void vtx_slide_update(VertexSlideOp *vso, wmEvent *event) if (edge_len <= 0.0f) edge_len = VTX_SLIDE_SNAP_THRSH; - edge_len = (len_v3v3(edge->v1->co, edge->v2->co) * VTX_SLIDE_SNAP_THRSH) / edge_len; + edge_len = (BM_edge_calc_length(edge) * VTX_SLIDE_SNAP_THRSH) / edge_len; vso->snap_threshold = edge_len; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 23348eed2b4..879e20fcf8b 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -153,19 +153,22 @@ void MESH_OT_subdivide(wmOperatorType *ot) } -void EMBM_project_snap_verts(bContext *C, ARegion *ar, Object *obedit, BMEditMesh *em) +void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) { + Object *obedit = em->ob; BMIter iter; BMVert *eve; + ED_view3d_init_mats_rv3d(obedit, ar->regiondata); + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - float mval[2], vec[3], no_dummy[3]; + float mval[2], co_proj[3], no_dummy[3]; int dist_dummy; - mul_v3_m4v3(vec, obedit->obmat, eve->co); - ED_view3d_project_float_noclip(ar, vec, mval); - if (snapObjectsContext(C, mval, &dist_dummy, vec, no_dummy, SNAP_NOT_OBEDIT)) { - mul_v3_m4v3(eve->co, obedit->imat, vec); + if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + if (snapObjectsContext(C, mval, &dist_dummy, co_proj, no_dummy, SNAP_NOT_OBEDIT)) { + mul_v3_m4v3(eve->co, obedit->imat, co_proj); + } } } } @@ -731,7 +734,10 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent short use_proj; em_setup_viewcontext(C, &vc); - + + ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); + + use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) && (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE)); @@ -760,26 +766,26 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent BM_ITER_MESH (eed, &iter, vc.em->bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { float co1[3], co2[3]; - mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co); - mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co); - ED_view3d_project_float_noclip(vc.ar, co1, co1); - ED_view3d_project_float_noclip(vc.ar, co2, co2); - /* 2D rotate by 90d while adding. - * (x, y) = (y, -x) - * - * accumulate the screenspace normal in 2D, - * with screenspace edge length weighting the result. */ - if (line_point_side_v2(co1, co2, mval_f) >= 0.0f) { - nor[0] += (co1[1] - co2[1]); - nor[1] += -(co1[0] - co2[0]); - } - else { - nor[0] += (co2[1] - co1[1]); - nor[1] += -(co2[0] - co1[0]); + if ((ED_view3d_project_float_object(vc.ar, eed->v1->co, co1, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) && + (ED_view3d_project_float_object(vc.ar, eed->v2->co, co2, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS)) + { + /* 2D rotate by 90d while adding. + * (x, y) = (y, -x) + * + * accumulate the screenspace normal in 2D, + * with screenspace edge length weighting the result. */ + if (line_point_side_v2(co1, co2, mval_f) >= 0.0f) { + nor[0] += (co1[1] - co2[1]); + nor[1] += -(co1[0] - co2[0]); + } + else { + nor[0] += (co2[1] - co1[1]); + nor[1] += -(co2[0] - co1[0]); + } + done = TRUE; } } - done = TRUE; } if (done) { @@ -836,7 +842,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent /* also project the source, for retopo workflow */ if (use_proj) - EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); + EMBM_project_snap_verts(C, vc.ar, vc.em); } edbm_extrude_edge(vc.obedit, vc.em, BM_ELEM_SELECT, nor); @@ -869,7 +875,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent } if (use_proj) - EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); + EMBM_project_snap_verts(C, vc.ar, vc.em); /* This normally happens when pushing undo but modal operators * like this one don't push undo data until after modal mode is diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index ef826c07cc1..42d82fff38e 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -1237,11 +1237,12 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], const int v_idx = me->mloop[mp->loopstart + fidx].v; dm->getVertCo(dm, v_idx, co); mul_m4_v3(ob->obmat, co); - ED_view3d_project_float_noclip(ar, co, sco); - len = len_squared_v2v2(mval_f, sco); - if (len < len_best) { - len_best = len; - v_idx_best = v_idx; + if (ED_view3d_project_float_global(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + len = len_squared_v2v2(mval_f, sco); + if (len < len_best) { + len_best = len; + v_idx_best = v_idx; + } } } while (fidx--); } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 8aed92df3af..f1ee8f522d9 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -846,20 +846,22 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x static float calc_vp_strength_dl(VPaint *vp, ViewContext *vc, const float vert_nor[3], const float mval[2], const float brush_size_pressure) { - Brush *brush = paint_brush(&vp->paint); - float dist_squared; - float vertco[2], delta[2]; + float vertco[2]; - ED_view3d_project_float_noclip(vc->ar, vert_nor, vertco); - sub_v2_v2v2(delta, mval, vertco); - dist_squared = dot_v2v2(delta, delta); /* len squared */ - if (dist_squared > brush_size_pressure * brush_size_pressure) { - return 0.0f; - } - else { - const float dist = sqrtf(dist_squared); - return BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure); + if (ED_view3d_project_float_global(vc->ar, vert_nor, vertco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + float delta[2]; + float dist_squared; + + sub_v2_v2v2(delta, mval, vertco); + dist_squared = dot_v2v2(delta, delta); /* len squared */ + if (dist_squared <= brush_size_pressure * brush_size_pressure) { + Brush *brush = paint_brush(&vp->paint); + const float dist = sqrtf(dist_squared); + return BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure); + } } + + return 0.0f; } static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 32392b2fd66..631418598e5 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -351,7 +351,11 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2]) case SPACE_VIEW3D: { if (t->ar->regiontype == RGN_TYPE_WINDOW) { - ED_view3d_project_float_noclip(t->ar, vec, adr); + if (ED_view3d_project_float_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) { + /* XXX, 2.64 and prior did this, weak! */ + adr[0] = t->ar->winx / 2.0f; + adr[1] = t->ar->winy / 2.0f; + } return; } break; @@ -4793,12 +4797,12 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, SlideData *sld, const flo sv->edge_len = len_v3v3(dw_p, up_p); mul_v3_m4v3(v_proj, t->obedit->obmat, sv->v->co); - ED_view3d_project_float_noclip(t->ar, v_proj, v_proj); - - dist = len_squared_v2v2(mval, v_proj); - if (dist < min_dist) { - min_dist = dist; - sld->curr_sv_index = i; + if (ED_view3d_project_float_global(t->ar, v_proj, v_proj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + dist = len_squared_v2v2(mval, v_proj); + if (dist < min_dist) { + min_dist = dist; + sld->curr_sv_index = i; + } } } } From 07b52efa205d79e210a3d6bb6440407489a72439 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 04:18:52 +0000 Subject: [PATCH 094/143] fix for bug in loop select, picking the active vert/edge/face was using global space checks on object space coordinates. this removes last use of ED_view3d_project_float_noclip(). --- source/blender/editors/include/ED_view3d.h | 1 - source/blender/editors/mesh/editmesh_select.c | 33 +++++++++++-------- .../editors/space_view3d/view3d_view.c | 20 ----------- 3 files changed, 20 insertions(+), 34 deletions(-) diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 60ade1ee9bb..acc53861e95 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -150,7 +150,6 @@ eV3DProjStatus ED_view3d_project_float_ex(struct ARegion *ar, float perspmat[4][ eV3DProjStatus ED_view3d_project_float_global(struct ARegion *ar, const float co[3], float r_co[2], eV3DProjTest flag); eV3DProjStatus ED_view3d_project_float_object(struct ARegion *ar, const float co[3], float r_co[2], eV3DProjTest flag); -void ED_view3d_project_float_noclip(struct ARegion *ar, const float co[3], float r_co[2]); void ED_view3d_project_float_v2_m4(const struct ARegion *a, const float co[3], float r_co[2], float mat[4][4]); void ED_view3d_project_float_v3_m4(struct ARegion *a, const float co[3], float r_co[3], float mat[4][4]); diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 4d4cc1e2ed1..abc8cb6b327 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -1050,21 +1050,27 @@ static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short ring) /* sets as active, useful for other tools */ if (select) { if (em->selectmode & SCE_SELECT_VERTEX) { - /* Find nearest vert from mouse. */ + /* Find nearest vert from mouse + * (initialize to large values incase only one vertex can be projected) */ float v1_co[2], v2_co[2]; + float length_1 = FLT_MAX; + float length_2 = FLT_MAX; /* We can't be sure this has already been set... */ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); - ED_view3d_project_float_noclip(vc.ar, eed->v1->co, v1_co); - ED_view3d_project_float_noclip(vc.ar, eed->v2->co, v2_co); + + if (ED_view3d_project_float_object(vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + length_1 = len_squared_v2v2(mvalf, v1_co); + } + + if (ED_view3d_project_float_object(vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + length_2 = len_squared_v2v2(mvalf, v2_co); + } #if 0 printf("mouse to v1: %f\nmouse to v2: %f\n", len_squared_v2v2(mvalf, v1_co), len_squared_v2v2(mvalf, v2_co)); #endif - if (len_squared_v2v2(mvalf, v1_co) < len_squared_v2v2(mvalf, v2_co)) - BM_select_history_store(em->bm, eed->v1); - else - BM_select_history_store(em->bm, eed->v2); + BM_select_history_store(em->bm, (length_1 < length_2) ? eed->v1 : eed->v2); } else if (em->selectmode & SCE_SELECT_EDGE) { BM_select_history_store(em->bm, eed); @@ -1084,12 +1090,13 @@ static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short ring) float co[2], tdist; BM_face_calc_center_mean(f, cent); - ED_view3d_project_float_noclip(vc.ar, cent, co); - tdist = len_squared_v2v2(mvalf, co); - if (tdist < best_dist) { -/* printf("Best face: %p (%f)\n", f, tdist);*/ - best_dist = tdist; - efa = f; + if (ED_view3d_project_float_object(vc.ar, cent, co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_SUCCESS) { + tdist = len_squared_v2v2(mvalf, co); + if (tdist < best_dist) { +/* printf("Best face: %p (%f)\n", f, tdist);*/ + best_dist = tdist; + efa = f; + } } } } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 0e4f64d2e53..f138a95b0ef 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1047,26 +1047,6 @@ eV3DProjStatus ED_view3d_project_float_object(ARegion *ar, const float co[3], fl return ED_view3d_project_float_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); } -void ED_view3d_project_float_noclip(ARegion *ar, const float co[3], float r_co[2]) -{ - RegionView3D *rv3d = ar->regiondata; - float vec4[4]; - - copy_v3_v3(vec4, co); - vec4[3] = 1.0; - - mul_m4_v4(rv3d->persmat, vec4); - - if (fabs(vec4[3]) > BL_NEAR_CLIP) { - r_co[0] = (float)(ar->winx / 2.0f) + (ar->winx / 2.0f) * vec4[0] / vec4[3]; - r_co[1] = (float)(ar->winy / 2.0f) + (ar->winy / 2.0f) * vec4[1] / vec4[3]; - } - else { - r_co[0] = ar->winx / 2.0f; - r_co[1] = ar->winy / 2.0f; - } -} - /* copies logic of get_view3d_viewplane(), keep in sync */ int ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend) { From 2ba295bcd11186f602d4b7c21ba7da661c58eab3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 04:43:46 +0000 Subject: [PATCH 095/143] knife tool: avoid sqrt's for length comparison, and define KNIFE_FLT_EPS rather than using (FLT_EPSILON * 80). --- source/blender/editors/mesh/editmesh_knife.c | 43 ++++++++++---------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 1ddb210398e..969f185810e 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -73,6 +73,9 @@ #define KMAXDIST 10 /* max mouse distance from edge before not detecting it */ +#define KNIFE_FLT_EPS 0.00001f +#define KNIFE_FLT_EPS_SQUARED (KNIFE_FLT_EPS * KNIFE_FLT_EPS) + typedef struct KnifeColors { unsigned char line[3]; unsigned char edge[3]; @@ -430,7 +433,7 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float float perc, cageco[3], l12; l12 = len_v3v3(kfe->v1->co, kfe->v2->co); - if (l12 < FLT_EPSILON * 80) { + if (l12 < KNIFE_FLT_EPS) { copy_v3_v3(cageco, kfe->v1->cageco); } else { @@ -589,7 +592,7 @@ static void knife_sort_linehits(KnifeTool_OpData *kcd) * successor faces connected to the linehits at either end of the range */ for (i = 0; i < kcd->totlinehit - 1; i = nexti) { for (j = i + 1; j < kcd->totlinehit; j++) { - if (fabsf(kcd->linehits[j].l - kcd->linehits[i].l) > 80 * FLT_EPSILON) + if (fabsf(kcd->linehits[j].l - kcd->linehits[i].l) > KNIFE_FLT_EPS) break; } nexti = j; @@ -797,7 +800,7 @@ static void knife_add_cut(KnifeTool_OpData *kcd) for (i = 0; i < kcd->totlinehit; i++, (lastlh = lh), lh++) { BMFace *f = lastlh ? lastlh->f : lh->f; - if (lastlh && len_v3v3(lastlh->hit, lh->hit) == 0.0f) { + if (lastlh && len_squared_v3v3(lastlh->hit, lh->hit) == 0.0f) { if (!firstlh) firstlh = lastlh; continue; @@ -816,13 +819,13 @@ static void knife_add_cut(KnifeTool_OpData *kcd) lastlh = firstlh = NULL; } - if (len_v3v3(kcd->prev.cage, lh->realhit) < FLT_EPSILON * 80) + if (len_squared_v3v3(kcd->prev.cage, lh->realhit) < KNIFE_FLT_EPS_SQUARED) continue; - if (len_v3v3(kcd->curr.cage, lh->realhit) < FLT_EPSILON * 80) + if (len_squared_v3v3(kcd->curr.cage, lh->realhit) < KNIFE_FLT_EPS_SQUARED) continue; /* first linehit may be down face parallel to view */ - if (!lastlh && fabsf(lh->l) < FLT_EPSILON * 80) + if (!lastlh && fabsf(lh->l) < KNIFE_FLT_EPS) continue; if (kcd->prev.is_space) { @@ -843,7 +846,7 @@ static void knife_add_cut(KnifeTool_OpData *kcd) copy_v3_v3(kcd->curr.cage, lh->cagehit); /* don't draw edges down faces parallel to view */ - if (lastlh && fabsf(lastlh->l - lh->l) < FLT_EPSILON * 80) { + if (lastlh && fabsf(lastlh->l - lh->l) < KNIFE_FLT_EPS) { kcd->prev = kcd->curr; continue; } @@ -1044,6 +1047,9 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) } if (kcd->totlinehit > 0) { + const float vthresh4 = kcd->vthresh / 4.0f; + const float vthresh4_squared = vthresh4 * vthresh4; + BMEdgeHit *lh; int i; @@ -1062,12 +1068,12 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) knife_project_v3(kcd, lh->kfe->v2->cageco, sv2); knife_project_v3(kcd, lh->cagehit, lh->schit); - if (len_v2v2(lh->schit, sv1) < kcd->vthresh / 4.0f) { + if (len_squared_v2v2(lh->schit, sv1) < vthresh4_squared) { copy_v3_v3(lh->cagehit, lh->kfe->v1->cageco); glVertex3fv(lh->cagehit); lh->v = lh->kfe->v1; } - else if (len_v2v2(lh->schit, sv2) < kcd->vthresh / 4.0f) { + else if (len_squared_v2v2(lh->schit, sv2) < vthresh4_squared) { copy_v3_v3(lh->cagehit, lh->kfe->v2->cageco); glVertex3fv(lh->cagehit); lh->v = lh->kfe->v2; @@ -1136,11 +1142,11 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) static float len_v3_tri_side_max(const float v1[3], const float v2[3], const float v3[3]) { - const float s1 = len_v3v3(v1, v2); - const float s2 = len_v3v3(v2, v3); - const float s3 = len_v3v3(v3, v1); + const float s1 = len_squared_v3v3(v1, v2); + const float s2 = len_squared_v3v3(v2, v3); + const float s3 = len_squared_v3v3(v3, v1); - return MAX3(s1, s2, s3); + return sqrtf(MAX3(s1, s2, s3)); } static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, @@ -1158,7 +1164,7 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, /* for comparing distances, error of intersection depends on triangle scale. * need to scale down before squaring for accurate comparison */ - const float depsilon = 50 *FLT_EPSILON * len_v3_tri_side_max(v1, v2, v3); + const float depsilon = (KNIFE_FLT_EPS / 2.0f) * len_v3_tri_side_max(v1, v2, v3); const float depsilon_squared = depsilon * depsilon; copy_v3_v3(cos + 0, v1); @@ -1985,7 +1991,7 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd) ScanFillFace *sf_tri; ScanFillVert *sf_vert, *sf_vert_last; int j; - float rndscale = FLT_EPSILON * 25; + float rndscale = (KNIFE_FLT_EPS / 4.0f); f = faces[i]; BLI_smallhash_init(hash); @@ -3058,14 +3064,9 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) { - Object *obedit; + Object *obedit = CTX_data_edit_object(C); KnifeTool_OpData *kcd = op->customdata; - if (!C) { - return OPERATOR_FINISHED; - } - - obedit = CTX_data_edit_object(C); if (!obedit || obedit->type != OB_MESH || BMEdit_FromObject(obedit) != kcd->em) { knifetool_exit(C, op); ED_area_headerprint(CTX_wm_area(C), NULL); From 6e65c7842bfd39ead047215d5391114911170b28 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 05:11:10 +0000 Subject: [PATCH 096/143] replace ED_view3d_project_short_* with ED_view3d_project_int_*, when the result was converted to an int after. also optimization for particle editmode key_test_depth() was projecting the screen coords, but all callers had already done this, so pass an arg. --- .../blender/editors/physics/particle_edit.c | 85 +++++++++---------- .../blender/editors/space_view3d/drawobject.c | 77 ++++++++--------- 2 files changed, 77 insertions(+), 85 deletions(-) diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 6c1d2e651cb..b8ea4957ca0 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -398,44 +398,41 @@ static void PE_set_view3d_data(bContext *C, PEData *data) /*************************** selection utilities *******************************/ -/* TODO, many of the callers to this function already have a 2d projection that - * could be passed as an arg, save calling ED_view3d_project_short_global again. */ -static int key_test_depth(PEData *data, const float co[3]) +static int key_test_depth(PEData *data, const float co[3], int screen_co[2]) { View3D *v3d= data->vc.v3d; double ux, uy, uz; float depth; - short wco[3], x, y; /* nothing to do */ if ((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0) return 1; - - if (ED_view3d_project_short_global(data->vc.ar, co, wco, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_SUCCESS) + + /* used to calculate here but all callers have the screen_co already, so pass as arg */ +#if 0 + if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_SUCCESS) { return 0; } +#endif gluProject(co[0], co[1], co[2], data->mats.modelview, data->mats.projection, (GLint *)data->mats.viewport, &ux, &uy, &uz); - x=wco[0]; - y=wco[1]; - #if 0 /* works well but too slow on some systems [#23118] */ - x+= (short)data->vc.ar->winrct.xmin; - y+= (short)data->vc.ar->winrct.ymin; + screen_co[0] += (short)data->vc.ar->winrct.xmin; + screen_co[1] += (short)data->vc.ar->winrct.ymin; /* PE_set_view3d_data calls this. no need to call here */ /* view3d_validate_backbuf(&data->vc); */ - glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); + glReadPixels(screen_co[0], screen_co[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); #else /* faster to use depths, these are calculated in PE_set_view3d_data */ { ViewDepths *vd = data->vc.rv3d->depths; assert(vd && vd->depths); /* we know its not clipped */ - depth= vd->depths[y * vd->w + x]; + depth = vd->depths[screen_co[1] * vd->w + screen_co[0]]; } #endif @@ -448,21 +445,21 @@ static int key_test_depth(PEData *data, const float co[3]) static int key_inside_circle(PEData *data, float rad, const float co[3], float *distance) { float dx, dy, dist; - int sco[2]; + int screen_co[2]; /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */ - if (ED_view3d_project_int_global(data->vc.ar, co, sco, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_SUCCESS) { + if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_SUCCESS) { return 0; } - dx= data->mval[0] - sco[0]; - dy= data->mval[1] - sco[1]; + dx= data->mval[0] - screen_co[0]; + dy= data->mval[1] - screen_co[1]; dist= sqrt(dx*dx + dy*dy); if (dist > rad) return 0; - if (key_test_depth(data, co)) { + if (key_test_depth(data, co, screen_co)) { if (distance) *distance=dist; @@ -474,16 +471,16 @@ static int key_inside_circle(PEData *data, float rad, const float co[3], float * static int key_inside_rect(PEData *data, const float co[3]) { - int sco[2]; + int screen_co[2]; - if (ED_view3d_project_int_global(data->vc.ar, co, sco, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_SUCCESS) { + if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_SUCCESS) { return 0; } - if (sco[0] > data->rect->xmin && sco[0] < data->rect->xmax && - sco[1] > data->rect->ymin && sco[1] < data->rect->ymax) + if (screen_co[0] > data->rect->xmin && screen_co[0] < data->rect->xmax && + screen_co[1] > data->rect->ymin && screen_co[1] < data->rect->ymax) { - return key_test_depth(data, co); + return key_test_depth(data, co, screen_co); } return 0; @@ -1647,7 +1644,7 @@ int PE_lasso_select(bContext *C, int mcords[][2], short moves, short extend, sho ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); POINT_P; KEY_K; float co[3], mat[4][4]= MAT4_UNITY; - int vertco[2]; + int screen_co[2]; PEData data; @@ -1668,9 +1665,9 @@ int PE_lasso_select(bContext *C, int mcords[][2], short moves, short extend, sho LOOP_KEYS { copy_v3_v3(co, key->co); mul_m4_v3(mat, co); - if ((ED_view3d_project_int_global(ar, co, vertco, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) && - BLI_lasso_is_point_inside(mcords, moves, vertco[0], vertco[1], IS_CLIPPED) && - key_test_depth(&data, co)) + if ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) && + BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && + key_test_depth(&data, co, screen_co)) { if (select && !(key->flag & PEK_SELECT)) { key->flag |= PEK_SELECT; @@ -1688,9 +1685,9 @@ int PE_lasso_select(bContext *C, int mcords[][2], short moves, short extend, sho copy_v3_v3(co, key->co); mul_m4_v3(mat, co); - if ((ED_view3d_project_int_global(ar, co, vertco, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) && - BLI_lasso_is_point_inside(mcords, moves, vertco[0], vertco[1], IS_CLIPPED) && - key_test_depth(&data, co)) + if ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) && + BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && + key_test_depth(&data, co, screen_co)) { if (select && !(key->flag & PEK_SELECT)) { key->flag |= PEK_SELECT; @@ -2791,7 +2788,7 @@ static void brush_cut(PEData *data, int pa_index) float rad2, cut_time= 1.0; float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv; int k, cut, keys= (int)pow(2.0, (double)pset->draw_step); - int vertco[2]; + int screen_co[2]; /* blunt scissors */ if (BLI_frand() > data->cutfac) return; @@ -2800,15 +2797,15 @@ static void brush_cut(PEData *data, int pa_index) if (edit->points[pa_index].flag & PEP_HIDE) return; - if (ED_view3d_project_int_global(ar, key->co, vertco, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) + if (ED_view3d_project_int_global(ar, key->co, screen_co, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) return; rad2= data->rad * data->rad; cut=0; - x0= (float)vertco[0]; - x1= (float)vertco[1]; + x0 = (float)screen_co[0]; + x1 = (float)screen_co[1]; o0= (float)data->mval[0]; o1= (float)data->mval[1]; @@ -2817,7 +2814,7 @@ static void brush_cut(PEData *data, int pa_index) xo1= x1 - o1; /* check if root is inside circle */ - if (xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) { + if (xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co, screen_co)) { cut_time= -1.0f; cut= 1; } @@ -2825,19 +2822,19 @@ static void brush_cut(PEData *data, int pa_index) /* calculate path time closest to root that was inside the circle */ for (k=1, key++; k<=keys; k++, key++) { - if ((ED_view3d_project_int_global(ar, key->co, vertco, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) || - key_test_depth(data, key->co) == 0) + if ((ED_view3d_project_int_global(ar, key->co, screen_co, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_SUCCESS) || + key_test_depth(data, key->co, screen_co) == 0) { - x0= (float)vertco[0]; - x1= (float)vertco[1]; + x0 = (float)screen_co[0]; + x1 = (float)screen_co[1]; xo0= x0 - o0; xo1= x1 - o1; continue; } - v0= (float)vertco[0] - x0; - v1= (float)vertco[1] - x1; + v0 = (float)screen_co[0] - x0; + v1 = (float)screen_co[1] - x1; dv= v0*v0 + v1*v1; @@ -2862,8 +2859,8 @@ static void brush_cut(PEData *data, int pa_index) } } - x0= (float)vertco[0]; - x1= (float)vertco[1]; + x0 = (float)screen_co[0]; + x1 = (float)screen_co[1]; xo0= x0 - o0; xo1= x1 - o1; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index e368f06a35f..6e11df30da0 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -1877,16 +1877,16 @@ void lattice_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BPo DispList *dl = BKE_displist_find(&obedit->disp, DL_VERTS); float *co = dl ? dl->verts : NULL; int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw; - short s[2]; ED_view3d_clipping_local(vc->rv3d, obedit->obmat); /* for local clipping lookups */ for (i = 0; i < N; i++, bp++, co += 3) { if (bp->hide == 0) { - if (ED_view3d_project_short_object(vc->ar, dl ? co : bp->vec, s, - V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + int screen_co[2]; + if (ED_view3d_project_int_object(vc->ar, dl ? co : bp->vec, screen_co, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) { - func(userData, bp, s[0], s[1]); + func(userData, bp, screen_co[0], screen_co[1]); } } } @@ -1992,13 +1992,13 @@ static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const flo const eV3DProjTest flag = (data->clipVerts == V3D_CLIP_TEST_OFF) ? V3D_PROJ_TEST_NOP : V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN; - short s[2]; + int screen_co[2]; - if (ED_view3d_project_short_object(data->vc.ar, co, s, flag) != V3D_PROJ_RET_SUCCESS) { + if (ED_view3d_project_int_object(data->vc.ar, co, screen_co, flag) != V3D_PROJ_RET_SUCCESS) { return; } - data->func(data->userData, eve, s[0], s[1], index); + data->func(data->userData, eve, screen_co[0], screen_co[1], index); } } @@ -2059,16 +2059,17 @@ static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, const flo BMEdge *eed = EDBM_edge_at_index(data->vc.em, index); if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - short s[2][2]; + int screen_co_a[2]; + int screen_co_b[2]; const eV3DProjTest flag = (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) ? V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN : V3D_PROJ_TEST_NOP; - if (ED_view3d_project_short_object(data->vc.ar, v0co, s[0], flag) != V3D_PROJ_RET_SUCCESS) { + if (ED_view3d_project_int_object(data->vc.ar, v0co, screen_co_a, flag) != V3D_PROJ_RET_SUCCESS) { return; } - if (ED_view3d_project_short_object(data->vc.ar, v1co, s[1], flag) != V3D_PROJ_RET_SUCCESS) { + if (ED_view3d_project_int_object(data->vc.ar, v1co, screen_co_b, flag) != V3D_PROJ_RET_SUCCESS) { return; } @@ -2077,16 +2078,15 @@ static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, const flo } else { if (data->clipVerts == V3D_CLIP_TEST_REGION) { - /* make an int copy */ - int s_int[2][2] = {{s[0][0], s[0][1]}, - {s[1][0], s[1][1]}}; - if (!BLI_rcti_isect_segment(&data->win_rect, s_int[0], s_int[1])) { + if (!BLI_rcti_isect_segment(&data->win_rect, screen_co_a, screen_co_b)) { return; } } } - data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index); + data->func(data->userData, eed, + screen_co_a[0], screen_co_a[1], + screen_co_b[0], screen_co_b[1], index); } } @@ -2125,16 +2125,11 @@ static void mesh_foreachScreenFace__mapFunc(void *userData, int index, const flo BMFace *efa = EDBM_face_at_index(data->vc.em, index); if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - float cent2[3]; - short s[2]; - - /* TODO, use ED_view3d_project_short_object */ - - mul_v3_m4v3(cent2, data->vc.obedit->obmat, cent); - if (ED_view3d_project_short_global(data->vc.ar, cent2, s, + int screen_co[2]; + if (ED_view3d_project_int_object(data->vc.ar, cent, screen_co, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) { - data->func(data->userData, efa, s[0], s[1], index); + data->func(data->userData, efa, screen_co[0], screen_co[1], index); } } } @@ -2151,8 +2146,7 @@ void mesh_foreachScreenFace( data.func = func; data.userData = userData; - //if (clipVerts) - ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); EDBM_index_arrays_init(vc->em, 0, 0, 1); dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data); @@ -2167,7 +2161,6 @@ void nurbs_foreachScreenVert( void *userData) { Curve *cu = vc->obedit->data; - short s[2]; Nurb *nu; int i; ListBase *nurbs = BKE_curve_editNurbs_get(cu); @@ -2180,29 +2173,30 @@ void nurbs_foreachScreenVert( BezTriple *bezt = &nu->bezt[i]; if (bezt->hide == 0) { + int screen_co[2]; if (cu->drawflag & CU_HIDE_HANDLES) { - if (ED_view3d_project_short_object(vc->ar, bezt->vec[1], s, - V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + if (ED_view3d_project_int_object(vc->ar, bezt->vec[1], screen_co, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) { - func(userData, nu, NULL, bezt, 1, s[0], s[1]); + func(userData, nu, NULL, bezt, 1, screen_co[0], screen_co[1]); } } else { - if (ED_view3d_project_short_object(vc->ar, bezt->vec[0], s, - V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + if (ED_view3d_project_int_object(vc->ar, bezt->vec[0], screen_co, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) { - func(userData, nu, NULL, bezt, 0, s[0], s[1]); + func(userData, nu, NULL, bezt, 0, screen_co[0], screen_co[1]); } - if (ED_view3d_project_short_object(vc->ar, bezt->vec[1], s, - V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + if (ED_view3d_project_int_object(vc->ar, bezt->vec[1], screen_co, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) { - func(userData, nu, NULL, bezt, 1, s[0], s[1]); + func(userData, nu, NULL, bezt, 1, screen_co[0], screen_co[1]); } - if (ED_view3d_project_short_object(vc->ar, bezt->vec[2], s, - V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + if (ED_view3d_project_int_object(vc->ar, bezt->vec[2], screen_co, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) { - func(userData, nu, NULL, bezt, 2, s[0], s[1]); + func(userData, nu, NULL, bezt, 2, screen_co[0], screen_co[1]); } } } @@ -2213,10 +2207,11 @@ void nurbs_foreachScreenVert( BPoint *bp = &nu->bp[i]; if (bp->hide == 0) { - if (ED_view3d_project_short_object(vc->ar, bp->vec, s, - V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + int screen_co[2]; + if (ED_view3d_project_int_object(vc->ar, bp->vec, screen_co, + V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) { - func(userData, nu, bp, NULL, -1, s[0], s[1]); + func(userData, nu, bp, NULL, -1, screen_co[0], screen_co[1]); } } } From 07a0463ac5765af5f9bbf0791ae32066a7c7fff7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 05:27:51 +0000 Subject: [PATCH 097/143] fix for circle select ignoring lock selection option for pose and edit modes, added macros PBONE_SELECTABLE, EBONE_SELECTABLE --- source/blender/blenkernel/BKE_armature.h | 1 + .../blender/editors/armature/editarmature.c | 16 +-- source/blender/editors/armature/poseobject.c | 10 +- source/blender/editors/include/ED_armature.h | 1 + .../blender/editors/physics/particle_edit.c | 2 +- .../editors/space_view3d/view3d_select.c | 118 +++++++++--------- 6 files changed, 74 insertions(+), 74 deletions(-) diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index d750e88ac04..a3f3beefbaf 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -132,6 +132,7 @@ Mat4 *b_bone_spline_setup(struct bPoseChannel *pchan, int rest); /* like EBONE_VISIBLE */ #define PBONE_VISIBLE(arm, bone) (((bone)->layer & (arm)->layer) && !((bone)->flag & BONE_HIDDEN_P)) +#define PBONE_SELECTABLE(arm, bone) (PBONE_VISIBLE(arm, bone) && !((bone)->flag & BONE_UNSELECTABLE)) #ifdef __cplusplus } diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index b8b89785e17..707594ff590 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -1831,7 +1831,7 @@ void ED_armature_deselect_all_visible(Object *obedit) for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { /* first and foremost, bone must be visible and selected */ - if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE) == 0) { + if (EBONE_SELECTABLE(arm, ebone)) { ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } } @@ -4106,7 +4106,7 @@ static void select_similar_length(bArmature *arm, EditBone *ebone_act, const flo const float len_max = ebone_act->length * (1.0f + thresh); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE) == 0) { + if (EBONE_SELECTABLE(arm, ebone)) { if ((ebone->length >= len_min) && (ebone->length <= len_max)) { @@ -4123,7 +4123,7 @@ static void select_similar_direction(bArmature *arm, EditBone *ebone_act, const sub_v3_v3v3(dir_act, ebone_act->head, ebone_act->tail); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE) == 0) { + if (EBONE_SELECTABLE(arm, ebone)) { float dir[3]; sub_v3_v3v3(dir, ebone->head, ebone->tail); @@ -4139,7 +4139,7 @@ static void select_similar_layer(bArmature *arm, EditBone *ebone_act) EditBone *ebone; for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE) == 0) { + if (EBONE_SELECTABLE(arm, ebone)) { if (ebone->layer & ebone_act->layer) { ED_armature_edit_bone_select(ebone); } @@ -4161,7 +4161,7 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act) /* Find matches */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE) == 0) { + if (EBONE_SELECTABLE(arm, ebone)) { char prefix_other[MAX_VGROUP_NAME]; BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp); if (!strcmp(prefix_act, prefix_other)) { @@ -4185,7 +4185,7 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act) /* Find matches */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE) == 0) { + if (EBONE_SELECTABLE(arm, ebone)) { char suffix_other[MAX_VGROUP_NAME]; BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other); if (!strcmp(suffix_act, suffix_other)) { @@ -4270,7 +4270,7 @@ static int armature_select_hierarchy_exec(bContext *C, wmOperator *op) for (curbone = arm->edbo->first; curbone; curbone = curbone->next) { /* only work on bone if it is visible and its selection can change */ - if (EBONE_VISIBLE(arm, curbone) && (curbone->flag & BONE_UNSELECTABLE) == 0) { + if (EBONE_SELECTABLE(arm, curbone)) { if (curbone == arm->act_edbone) { if (direction == BONE_SELECT_PARENT) { if (curbone->parent == NULL) continue; @@ -4290,7 +4290,7 @@ static int armature_select_hierarchy_exec(bContext *C, wmOperator *op) chbone = editbone_get_child(arm, curbone, 1); if (chbone == NULL) continue; - if (EBONE_VISIBLE(arm, chbone) && (chbone->flag & BONE_UNSELECTABLE) == 0) { + if (EBONE_SELECTABLE(arm, chbone)) { chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); arm->act_edbone = chbone; diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index dc049e51062..189b2e977c2 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -492,7 +492,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) if (pchan->parent == NULL) continue; else pabone = pchan->parent->bone; - if (PBONE_VISIBLE(arm, pabone)) { + if (PBONE_SELECTABLE(arm, pabone)) { if (!add_to_sel) curbone->flag &= ~BONE_SELECTED; pabone->flag |= BONE_SELECTED; arm->act_bone = pabone; @@ -514,7 +514,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) { /* possible we have multiple children, some invisible */ - if (PBONE_VISIBLE(arm, pchan_child->bone)) { + if (PBONE_SELECTABLE(arm, pchan_child->bone)) { if (pchan_child->parent == pchan) { chbone = pchan_child->bone; break; @@ -526,7 +526,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) if (chbone == NULL) continue; #endif - if (PBONE_VISIBLE(arm, chbone)) { + if (PBONE_SELECTABLE(arm, chbone)) { if (!add_to_sel) curbone->flag &= ~BONE_SELECTED; chbone->flag |= BONE_SELECTED; arm->act_bone = chbone; @@ -719,9 +719,7 @@ static int pose_select_same_keyingset(bContext *C, Object *ob, short extend) if (pchan) { /* select if bone is visible and can be affected */ - if ((PBONE_VISIBLE(arm, pchan->bone)) && - (pchan->bone->flag & BONE_UNSELECTABLE) == 0) - { + if (PBONE_SELECTABLE(arm, pchan->bone)) { pchan->bone->flag |= BONE_SELECTED; changed = 1; } diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 4e33404be7e..b9996c87194 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -94,6 +94,7 @@ typedef struct EditBone { /* useful macros */ #define EBONE_VISIBLE(arm, ebone) (((arm)->layer & (ebone)->layer) && !((ebone)->flag & BONE_HIDDEN_A)) +#define EBONE_SELECTABLE(arm, ebone) (EBONE_VISIBLE(arm, ebone) && !(ebone->flag & BONE_UNSELECTABLE)) #define EBONE_EDITABLE(ebone) (((ebone)->flag & BONE_SELECTED) && !((ebone)->flag & BONE_EDITMODE_LOCKED)) /* used in bone_select_hierachy() */ diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index b8ea4957ca0..b03c637e67c 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -398,7 +398,7 @@ static void PE_set_view3d_data(bContext *C, PEData *data) /*************************** selection utilities *******************************/ -static int key_test_depth(PEData *data, const float co[3], int screen_co[2]) +static int key_test_depth(PEData *data, const float co[3], const int screen_co[2]) { View3D *v3d= data->vc.v3d; double ux, uy, uz; diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 2332ca98a66..fb18d6c64c9 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -333,7 +333,7 @@ static void do_lasso_select_pose(ViewContext *vc, Object *ob, int mcords[][2], s if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) return; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (PBONE_VISIBLE(arm, pchan->bone) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) { + if (PBONE_SELECTABLE(arm, pchan->bone)) { /* XXX, todo, use ED_view3d_project_int_object */ sco1[0] = sco2[0] = IS_CLIPPED; @@ -581,7 +581,7 @@ static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short mov /* set editdata in vc */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE) == 0) { + if (EBONE_SELECTABLE(arm, ebone)) { /* XXX, TODO, use ED_view3d_project_short_object here */ sco1[0] = sco2[0] = IS_CLIPPED; @@ -2380,33 +2380,31 @@ static void pose_circle_select(ViewContext *vc, int select, const int mval[2], f /* check each PoseChannel... */ /* TODO: could be optimized at some point */ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - short sco1[2], sco2[2], didpoint = 0; - float vec[3]; - - /* skip invisible bones */ - if (PBONE_VISIBLE(arm, pchan->bone) == 0) - continue; + if (PBONE_SELECTABLE(arm, pchan->bone)) { + short sco1[2], sco2[2], didpoint = 0; + float vec[3]; - /* XXX, TODO, center check does not check for clipping! */ - /* XXX, TODO, use ED_view3d_project_short_object here */ - - /* project head location to screenspace */ - mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_head); - ED_view3d_project_short_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); - - /* project tail location to screenspace */ - mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_tail); - ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); - - /* check if the head and/or tail is in the circle - * - the call to check also does the selection already - */ - if (pchan_circle_doSelectJoint(&data, pchan, sco1[0], sco1[1])) - didpoint = 1; - if (pchan_circle_doSelectJoint(&data, pchan, sco2[0], sco2[1])) - didpoint = 1; - - change |= didpoint; + /* XXX, TODO, center check does not check for clipping! */ + /* XXX, TODO, use ED_view3d_project_short_object here */ + + /* project head location to screenspace */ + mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_head); + ED_view3d_project_short_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); + + /* project tail location to screenspace */ + mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_tail); + ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); + + /* check if the head and/or tail is in the circle + * - the call to check also does the selection already + */ + if (pchan_circle_doSelectJoint(&data, pchan, sco1[0], sco1[1])) + didpoint = 1; + if (pchan_circle_doSelectJoint(&data, pchan, sco2[0], sco2[1])) + didpoint = 1; + + change |= didpoint; + } } if (change) { @@ -2455,39 +2453,41 @@ static void armature_circle_select(ViewContext *vc, int select, const int mval[2 /* check each EditBone... */ /* TODO: could be optimized at some point */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - short sco1[2], sco2[2], didpoint = 0; - float vec[3]; - - /* XXX, TODO, center check does not check for clipping! */ - /* XXX, TODO, use ED_view3d_project_short_object here */ + if (EBONE_SELECTABLE(arm, ebone)) { + short sco1[2], sco2[2], didpoint = 0; + float vec[3]; - /* project head location to screenspace */ - mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head); - ED_view3d_project_short_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); - - /* project tail location to screenspace */ - mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); - ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); - - /* check if the head and/or tail is in the circle - * - the call to check also does the selection already - */ - if (armature_circle_doSelectJoint(&data, ebone, sco1[0], sco1[1], 1)) - didpoint = 1; - if (armature_circle_doSelectJoint(&data, ebone, sco2[0], sco2[1], 0)) - didpoint = 1; - - /* only if the endpoints didn't get selected, deal with the middle of the bone too */ - /* XXX should we just do this always? */ - if ((didpoint == 0) && edge_inside_circle(mval[0], mval[1], rad, sco1[0], sco1[1], sco2[0], sco2[1])) { - if (select) - ebone->flag |= BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED; - else - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - change = TRUE; + /* XXX, TODO, center check does not check for clipping! */ + /* XXX, TODO, use ED_view3d_project_short_object here */ + + /* project head location to screenspace */ + mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head); + ED_view3d_project_short_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); + + /* project tail location to screenspace */ + mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); + ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); + + /* check if the head and/or tail is in the circle + * - the call to check also does the selection already + */ + if (armature_circle_doSelectJoint(&data, ebone, sco1[0], sco1[1], 1)) + didpoint = 1; + if (armature_circle_doSelectJoint(&data, ebone, sco2[0], sco2[1], 0)) + didpoint = 1; + + /* only if the endpoints didn't get selected, deal with the middle of the bone too */ + /* XXX should we just do this always? */ + if ((didpoint == 0) && edge_inside_circle(mval[0], mval[1], rad, sco1[0], sco1[1], sco2[0], sco2[1])) { + if (select) + ebone->flag |= BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED; + else + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + change = TRUE; + } + + change |= didpoint; } - - change |= didpoint; } if (change) { From a92171c21306bfe22b36573737e04defe433d611 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 05:59:15 +0000 Subject: [PATCH 098/143] fixes/minor improvements to circle select in armature and pose mode. - pose mode now checks if circle select intersects the bone if neither head/tail are reached (as with editmode) - checking if the mouse intersects with the bone now checks that neither projection failed. - use ED_view3d_project_int_object rather then the global version. --- .../editors/space_view3d/view3d_select.c | 103 +++++++++++------- 1 file changed, 64 insertions(+), 39 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index fb18d6c64c9..014a57a32d0 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -572,7 +572,7 @@ static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short mov bArmature *arm = vc->obedit->data; EditBone *ebone; float vec[3]; - short sco1[2], sco2[2], didpoint; + short sco1[2], sco2[2]; int change = FALSE; if (extend == 0 && select) @@ -582,6 +582,7 @@ static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short mov for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_SELECTABLE(arm, ebone)) { + int is_point_done = FALSE; /* XXX, TODO, use ED_view3d_project_short_object here */ sco1[0] = sco2[0] = IS_CLIPPED; @@ -591,21 +592,20 @@ static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short mov mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); - didpoint = 0; if (BLI_lasso_is_point_inside(mcords, moves, sco1[0], sco1[1], IS_CLIPPED)) { if (select) ebone->flag |= BONE_ROOTSEL; else ebone->flag &= ~BONE_ROOTSEL; - didpoint = 1; + is_point_done = TRUE; change = TRUE; } if (BLI_lasso_is_point_inside(mcords, moves, sco2[0], sco2[1], IS_CLIPPED)) { if (select) ebone->flag |= BONE_TIPSEL; else ebone->flag &= ~BONE_TIPSEL; - didpoint = 1; + is_point_done = TRUE; change = TRUE; } /* if one of points selected, we skip the bone itself */ - if (didpoint == 0 && + if ((is_point_done == FALSE) && BLI_lasso_is_edge_inside(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1], IS_CLIPPED)) { if (select) ebone->flag |= BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED; @@ -2381,29 +2381,45 @@ static void pose_circle_select(ViewContext *vc, int select, const int mval[2], f /* TODO: could be optimized at some point */ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { if (PBONE_SELECTABLE(arm, pchan->bone)) { - short sco1[2], sco2[2], didpoint = 0; - float vec[3]; - - /* XXX, TODO, center check does not check for clipping! */ - /* XXX, TODO, use ED_view3d_project_short_object here */ + int screen_co_a[2], screen_co_b[2]; + int is_point_done = FALSE; + int points_proj_tot = 0; /* project head location to screenspace */ - mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_head); - ED_view3d_project_short_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); + if (ED_view3d_project_int_object(vc->ar, pchan->pose_head, screen_co_a, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + if (pchan_circle_doSelectJoint(&data, pchan, screen_co_a[0], screen_co_a[1])) { + is_point_done = TRUE; + } + } /* project tail location to screenspace */ - mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_tail); - ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); + if (ED_view3d_project_int_object(vc->ar, pchan->pose_tail, screen_co_b, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + if (pchan_circle_doSelectJoint(&data, pchan, screen_co_b[0], screen_co_b[1])) { + is_point_done = TRUE; + } + } - /* check if the head and/or tail is in the circle - * - the call to check also does the selection already - */ - if (pchan_circle_doSelectJoint(&data, pchan, sco1[0], sco1[1])) - didpoint = 1; - if (pchan_circle_doSelectJoint(&data, pchan, sco2[0], sco2[1])) - didpoint = 1; + /* only if the endpoints didn't get selected, deal with the middle of the bone too */ + /* XXX should we just do this always? */ + if ((is_point_done == FALSE) && (points_proj_tot == 2) && + edge_inside_circle(mval[0], mval[1], rad, + screen_co_a[0], screen_co_a[1], + screen_co_b[0], screen_co_b[1])) + { + if (select) + pchan->bone->flag |= BONE_SELECTED; + else + pchan->bone->flag &= ~BONE_SELECTED; + change = TRUE; + } - change |= didpoint; + change |= is_point_done; } } @@ -2451,34 +2467,43 @@ static void armature_circle_select(ViewContext *vc, int select, const int mval[2 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ /* check each EditBone... */ - /* TODO: could be optimized at some point */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_SELECTABLE(arm, ebone)) { - short sco1[2], sco2[2], didpoint = 0; - float vec[3]; - - /* XXX, TODO, center check does not check for clipping! */ - /* XXX, TODO, use ED_view3d_project_short_object here */ + int screen_co_a[2], screen_co_b[2]; + int is_point_done = FALSE; + int points_proj_tot = 0; /* project head location to screenspace */ - mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head); - ED_view3d_project_short_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); + if (ED_view3d_project_int_object(vc->ar, ebone->head, screen_co_a, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + if (armature_circle_doSelectJoint(&data, ebone, screen_co_a[0], screen_co_a[1], TRUE)) { + is_point_done = TRUE; + } + } /* project tail location to screenspace */ - mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); - ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); + if (ED_view3d_project_int_object(vc->ar, ebone->tail, screen_co_b, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + if (armature_circle_doSelectJoint(&data, ebone, screen_co_b[0], screen_co_b[1], FALSE)) { + is_point_done = TRUE; + } + } /* check if the head and/or tail is in the circle - * - the call to check also does the selection already + * - the call to check also does the selection already */ - if (armature_circle_doSelectJoint(&data, ebone, sco1[0], sco1[1], 1)) - didpoint = 1; - if (armature_circle_doSelectJoint(&data, ebone, sco2[0], sco2[1], 0)) - didpoint = 1; /* only if the endpoints didn't get selected, deal with the middle of the bone too */ /* XXX should we just do this always? */ - if ((didpoint == 0) && edge_inside_circle(mval[0], mval[1], rad, sco1[0], sco1[1], sco2[0], sco2[1])) { + if ((is_point_done == FALSE) && (points_proj_tot == 2) && + edge_inside_circle(mval[0], mval[1], rad, + screen_co_a[0], screen_co_a[1], + screen_co_b[0], screen_co_b[1])) + { if (select) ebone->flag |= BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED; else @@ -2486,7 +2511,7 @@ static void armature_circle_select(ViewContext *vc, int select, const int mval[2 change = TRUE; } - change |= didpoint; + change |= is_point_done; } } From 3986a5f83a5c101b57cfdaeb456afedd371c5463 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 5 Oct 2012 06:40:21 +0000 Subject: [PATCH 099/143] Bugfix [#32760] Crash on entering pose mode if motion paths have no baked points Dunno how a file with this situation arose, but we now perform some more sanity checking to abort in this sticky situation. --- .../blender/editors/space_view3d/drawanimviz.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c index 5f312ff7fca..135e9b891bb 100644 --- a/source/blender/editors/space_view3d/drawanimviz.c +++ b/source/blender/editors/space_view3d/drawanimviz.c @@ -107,11 +107,6 @@ void draw_motion_path_instance(Scene *scene, * - abort if whole range is past ends of path * - otherwise clamp endpoints to extents of path */ - if ((sfra > mpath->end_frame) || (efra < mpath->start_frame)) { - /* whole path is out of bounds */ - return; - } - if (sfra < mpath->start_frame) { /* start clamp */ sfra = mpath->start_frame; @@ -121,9 +116,14 @@ void draw_motion_path_instance(Scene *scene, efra = mpath->end_frame; } + if ((sfra > mpath->end_frame) || (efra < mpath->start_frame)) { + /* whole path is out of bounds */ + return; + } + len = efra - sfra; - if (len <= 0) { + if ((len <= 0) || (mpath->points == NULL)) { return; } @@ -180,7 +180,7 @@ void draw_motion_path_instance(Scene *scene, UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10); } - /* draw a vertex with this color */ + /* draw a vertex with this color */ glVertex3fv(mpv->co); } @@ -230,7 +230,7 @@ void draw_motion_path_instance(Scene *scene, unsigned char col[4]; UI_GetThemeColor3ubv(TH_TEXT_HI, col); col[3] = 255; - + for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) { char numstr[32]; float co[3]; From a320773b88ca1de2e16a71c3480950e8f3cc21be Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 5 Oct 2012 07:05:52 +0000 Subject: [PATCH 100/143] Some effect-less code cleanup... --- source/blender/editors/object/object_add.c | 472 ++++++++++----------- 1 file changed, 236 insertions(+), 236 deletions(-) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index c2e5f145ff7..102353ce1d1 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -110,7 +110,7 @@ #include "object_intern.h" /* this is an exact copy of the define in rna_lamp.c - * kept here because of linking order. + * kept here because of linking order. * Icons are only defined here */ EnumPropertyItem lamp_type_items[] = { {LA_LOCAL, "POINT", ICON_LAMP_POINT, "Point", "Omnidirectional point light source"}, @@ -121,6 +121,23 @@ EnumPropertyItem lamp_type_items[] = { {0, NULL, 0, NULL, NULL} }; +/* copy from rna_object_force.c */ +static EnumPropertyItem field_type_items[] = { + {PFIELD_FORCE, "FORCE", ICON_FORCE_FORCE, "Force", ""}, + {PFIELD_WIND, "WIND", ICON_FORCE_WIND, "Wind", ""}, + {PFIELD_VORTEX, "VORTEX", ICON_FORCE_VORTEX, "Vortex", ""}, + {PFIELD_MAGNET, "MAGNET", ICON_FORCE_MAGNETIC, "Magnetic", ""}, + {PFIELD_HARMONIC, "HARMONIC", ICON_FORCE_HARMONIC, "Harmonic", ""}, + {PFIELD_CHARGE, "CHARGE", ICON_FORCE_CHARGE, "Charge", ""}, + {PFIELD_LENNARDJ, "LENNARDJ", ICON_FORCE_LENNARDJONES, "Lennard-Jones", ""}, + {PFIELD_TEXTURE, "TEXTURE", ICON_FORCE_TEXTURE, "Texture", ""}, + {PFIELD_GUIDE, "GUIDE", ICON_FORCE_CURVE, "Curve Guide", ""}, + {PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""}, + {PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", ""}, + {PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", ""}, + {0, NULL, 0, NULL, NULL} +}; + /************************** Exported *****************************/ void ED_object_location_from_view(bContext *C, float loc[3]) @@ -128,7 +145,7 @@ void ED_object_location_from_view(bContext *C, float loc[3]) View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); float *cursor; - + cursor = give_cursor(scene, v3d); copy_v3_v3(loc, cursor); @@ -152,44 +169,44 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3], { Object *ob = base->object; Scene *scene = CTX_data_scene(C); - + if (!scene) return; - + if (loc) copy_v3_v3(ob->loc, loc); - + if (rot) copy_v3_v3(ob->rot, rot); - + BKE_object_where_is_calc(scene, ob); } -/* uses context to figure out transform for primitive */ -/* returns standard diameter */ +/* Uses context to figure out transform for primitive. + * Returns standard diameter. */ float ED_object_new_primitive_matrix(bContext *C, Object *obedit, const float loc[3], const float rot[3], float primmat[][4]) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3]; - + unit_m4(primmat); - + eul_to_mat3(rmat, rot); invert_m3(rmat); - + /* inverse transform for initial rotation and object */ copy_m3_m4(mat, obedit->obmat); mul_m3_m3m3(cmat, rmat, mat); invert_m3_m3(imat, cmat); copy_m4_m3(primmat, imat); - + /* center */ copy_v3_v3(primmat[3], loc); sub_v3_v3v3(primmat[3], primmat[3], obedit->obmat[3]); invert_m3_m3(imat, mat); mul_m3_v3(imat, primmat[3]); - + if (v3d) return ED_view3d_grid_scale(scene, v3d, NULL); @@ -206,7 +223,7 @@ static void view_align_update(struct Main *UNUSED(main), struct Scene *UNUSED(sc void ED_object_add_generic_props(wmOperatorType *ot, int do_editmode) { PropertyRNA *prop; - + /* note: this property gets hidden for add-camera operator */ prop = RNA_def_boolean(ot->srna, "view_align", 0, "Align to View", "Align the new object to the view"); RNA_def_property_update_runtime(prop, view_align_update); @@ -216,14 +233,14 @@ void ED_object_add_generic_props(wmOperatorType *ot, int do_editmode) "Enter editmode when adding this object"); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } - + prop = RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "Location for the newly added object", -FLT_MAX, FLT_MAX); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_float_rotation(ot->srna, "rotation", 3, NULL, -FLT_MAX, FLT_MAX, "Rotation", "Rotation for the newly added object", (float)-M_PI * 2.0f, (float)M_PI * 2.0f); RNA_def_property_flag(prop, PROP_SKIP_SAVE); - + prop = RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } @@ -233,14 +250,14 @@ static void object_add_generic_invoke_options(bContext *C, wmOperator *op) if (RNA_struct_find_property(op->ptr, "enter_editmode")) /* optional */ if (!RNA_struct_property_is_set(op->ptr, "enter_editmode")) RNA_boolean_set(op->ptr, "enter_editmode", U.flag & USER_ADD_EDITMODE); - + if (!RNA_struct_property_is_set(op->ptr, "location")) { float loc[3]; - + ED_object_location_from_view(C, loc); RNA_float_set_array(op->ptr, "location", loc); } - + if (!RNA_struct_property_is_set(op->ptr, "layers")) { View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); @@ -273,7 +290,7 @@ int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float loc[3], fl View3D *v3d = CTX_wm_view3d(C); int a, layer_values[20]; int view_align; - + *enter_editmode = FALSE; if (RNA_struct_find_property(op->ptr, "enter_editmode") && RNA_boolean_get(op->ptr, "enter_editmode")) { *enter_editmode = TRUE; @@ -308,17 +325,17 @@ int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float loc[3], fl view_align = U.flag & USER_ADD_VIEWALIGNED; RNA_boolean_set(op->ptr, "view_align", view_align); } - + if (view_align) { ED_object_rotation_from_view(C, rot); RNA_float_set_array(op->ptr, "rotation", rot); } else RNA_float_get_array(op->ptr, "rotation", rot); - + if (is_view_aligned) *is_view_aligned = view_align; - + RNA_float_get_array(op->ptr, "location", loc); if (*layer == 0) { @@ -329,19 +346,19 @@ int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float loc[3], fl return 1; } -/* for object add primitive operators */ -/* do not call undo push in this function (users of this function have to) */ +/* For object add primitive operators. + * Do not call undo push in this function (users of this function have to). */ Object *ED_object_add_type(bContext *C, int type, const float loc[3], const float rot[3], int enter_editmode, unsigned int layer) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob; - - /* for as long scene has editmode... */ + + /* For as long scene has editmode... */ if (CTX_data_edit_object(C)) ED_object_exit_editmode(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */ - + /* deselects all, sets scene->basact */ ob = BKE_object_add(scene, type); BASACT->lay = ob->lay = layer; @@ -371,12 +388,12 @@ static int object_add_exec(bContext *C, wmOperator *op) int enter_editmode; unsigned int layer; float loc[3], rot[3]; - + if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), loc, rot, enter_editmode, layer); - + return OPERATOR_FINISHED; } @@ -386,37 +403,22 @@ void OBJECT_OT_add(wmOperatorType *ot) ot->name = "Add Object"; ot->description = "Add an object to the scene"; ot->idname = "OBJECT_OT_add"; - + /* api callbacks */ ot->invoke = ED_object_add_generic_invoke; ot->exec = object_add_exec; - + ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + RNA_def_enum(ot->srna, "type", object_type_items, 0, "Type", ""); ED_object_add_generic_props(ot, TRUE); } /********************* Add Effector Operator ********************/ -/* copy from rna_object_force.c*/ -static EnumPropertyItem field_type_items[] = { - {PFIELD_FORCE, "FORCE", ICON_FORCE_FORCE, "Force", ""}, - {PFIELD_WIND, "WIND", ICON_FORCE_WIND, "Wind", ""}, - {PFIELD_VORTEX, "VORTEX", ICON_FORCE_VORTEX, "Vortex", ""}, - {PFIELD_MAGNET, "MAGNET", ICON_FORCE_MAGNETIC, "Magnetic", ""}, - {PFIELD_HARMONIC, "HARMONIC", ICON_FORCE_HARMONIC, "Harmonic", ""}, - {PFIELD_CHARGE, "CHARGE", ICON_FORCE_CHARGE, "Charge", ""}, - {PFIELD_LENNARDJ, "LENNARDJ", ICON_FORCE_LENNARDJONES, "Lennard-Jones", ""}, - {PFIELD_TEXTURE, "TEXTURE", ICON_FORCE_TEXTURE, "Texture", ""}, - {PFIELD_GUIDE, "GUIDE", ICON_FORCE_CURVE, "Curve Guide", ""}, - {PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""}, - {PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", ""}, - {PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", ""}, - {0, NULL, 0, NULL, NULL}}; /* for effector add primitive operators */ static Object *effector_add_type(bContext *C, wmOperator *op, int type) @@ -426,7 +428,7 @@ static Object *effector_add_type(bContext *C, wmOperator *op, int type) unsigned int layer; float loc[3], rot[3]; float mat[4][4]; - + object_add_generic_invoke_options(C, op); if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) @@ -478,22 +480,22 @@ void OBJECT_OT_effector_add(wmOperatorType *ot) ot->name = "Add Effector"; ot->description = "Add an empty object with a physics effector to the scene"; ot->idname = "OBJECT_OT_effector_add"; - + /* api callbacks */ ot->invoke = WM_menu_invoke; ot->exec = effector_add_exec; - + ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + ot->prop = RNA_def_enum(ot->srna, "type", field_type_items, 0, "Type", ""); ED_object_add_generic_props(ot, TRUE); } -/* ***************** Add Camera *************** */ +/********************* Add Camera Operator ********************/ static int object_camera_add_exec(bContext *C, wmOperator *op) { @@ -503,17 +505,17 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) int enter_editmode; unsigned int layer; float loc[3], rot[3]; - + /* force view align for cameras */ RNA_boolean_set(op->ptr, "view_align", TRUE); - + object_add_generic_invoke_options(C, op); if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; ob = ED_object_add_type(C, OB_CAMERA, loc, rot, FALSE, layer); - + if (v3d) { if (v3d->camera == NULL) v3d->camera = ob; @@ -528,33 +530,32 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) void OBJECT_OT_camera_add(wmOperatorType *ot) { PropertyRNA *prop; - + /* identifiers */ ot->name = "Add Camera"; ot->description = "Add a camera object to the scene"; ot->idname = "OBJECT_OT_camera_add"; - + /* api callbacks */ ot->exec = object_camera_add_exec; ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + ED_object_add_generic_props(ot, TRUE); - + /* hide this for cameras, default */ prop = RNA_struct_type_find_property(ot->srna, "view_align"); RNA_def_property_flag(prop, PROP_HIDDEN); - } -/* ***************** add primitives *************** */ +/********************* Add Metaball Operator ********************/ + static int object_metaball_add_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); - /*MetaElem *elem;*/ /*UNUSED*/ int newob = 0; int enter_editmode; unsigned int layer; @@ -565,24 +566,24 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; - + if (obedit == NULL || obedit->type != OB_MBALL) { obedit = ED_object_add_type(C, OB_MBALL, loc, rot, TRUE, layer); newob = 1; } else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); - + ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); - - /* elem= (MetaElem *) */ add_metaball_primitive(C, obedit, mat, RNA_enum_get(op->ptr, "type"), newob); + + add_metaball_primitive(C, obedit, mat, RNA_enum_get(op->ptr, "type"), newob); /* userdef */ if (newob && !enter_editmode) { ED_object_exit_editmode(C, EM_FREEDATA); } - + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); - + return OPERATOR_FINISHED; } @@ -619,29 +620,31 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + RNA_def_enum(ot->srna, "type", metaelem_type_items, 0, "Primitive", ""); ED_object_add_generic_props(ot, TRUE); } +/********************* Add Text Operator ********************/ + static int object_add_text_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); int enter_editmode; unsigned int layer; float loc[3], rot[3]; - + object_add_generic_invoke_options(C, op); /* XXX these props don't get set right when only exec() is called */ if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; - + if (obedit && obedit->type == OB_FONT) return OPERATOR_CANCELLED; obedit = ED_object_add_type(C, OB_FONT, loc, rot, enter_editmode, layer); - + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); - + return OPERATOR_FINISHED; } @@ -651,17 +654,19 @@ void OBJECT_OT_text_add(wmOperatorType *ot) ot->name = "Add Text"; ot->description = "Add a text object to the scene"; ot->idname = "OBJECT_OT_text_add"; - + /* api callbacks */ ot->invoke = ED_object_add_generic_invoke; ot->exec = object_add_text_exec; ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ED_object_add_generic_props(ot, TRUE); } +/********************* Add Armature Operator ********************/ + static int object_armature_add_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -687,36 +692,38 @@ static int object_armature_add_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "Cannot create editmode armature"); return OPERATOR_CANCELLED; } - + /* v3d and rv3d are allowed to be NULL */ add_primitive_bone(CTX_data_scene(C), v3d, rv3d); /* userdef */ if (newob && !enter_editmode) ED_object_exit_editmode(C, EM_FREEDATA); - + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); - + return OPERATOR_FINISHED; } void OBJECT_OT_armature_add(wmOperatorType *ot) -{ +{ /* identifiers */ ot->name = "Add Armature"; ot->description = "Add an armature object to the scene"; ot->idname = "OBJECT_OT_armature_add"; - + /* api callbacks */ ot->invoke = ED_object_add_generic_invoke; ot->exec = object_armature_add_exec; ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ED_object_add_generic_props(ot, TRUE); } +/********************* Add Lamp Operator ********************/ + static const char *get_lamp_defname(int type) { switch (type) { @@ -739,7 +746,7 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op) int enter_editmode; unsigned int layer; float loc[3], rot[3]; - + object_add_generic_invoke_options(C, op); if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; @@ -755,7 +762,7 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op) ED_node_shader_default(scene, &la->id); la->use_nodes = TRUE; } - + return OPERATOR_FINISHED; } @@ -765,12 +772,12 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot) ot->name = "Add Lamp"; ot->description = "Add a lamp object to the scene"; ot->idname = "OBJECT_OT_lamp_add"; - + /* api callbacks */ ot->invoke = WM_menu_invoke; ot->exec = object_lamp_add_exec; ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -780,6 +787,8 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot) ED_object_add_generic_props(ot, FALSE); } +/********************* Add Group Instance Operator ********************/ + static int group_instance_add_exec(bContext *C, wmOperator *op) { Group *group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group")); @@ -787,7 +796,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) int enter_editmode; unsigned int layer; float loc[3], rot[3]; - + object_add_generic_invoke_options(C, op); if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; @@ -812,61 +821,6 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int object_speaker_add_exec(bContext *C, wmOperator *op) -{ - Object *ob; - int enter_editmode; - unsigned int layer; - float loc[3], rot[3]; - Scene *scene = CTX_data_scene(C); - - object_add_generic_invoke_options(C, op); - if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) - return OPERATOR_CANCELLED; - - ob = ED_object_add_type(C, OB_SPEAKER, loc, rot, FALSE, layer); - - /* to make it easier to start using this immediately in NLA, a default sound clip is created - * ready to be moved around to retime the sound and/or make new sound clips - */ - { - /* create new data for NLA hierarchy */ - AnimData *adt = BKE_id_add_animdata(&ob->id); - NlaTrack *nlt = add_nlatrack(adt, NULL); - NlaStrip *strip = add_nla_soundstrip(CTX_data_scene(C), ob->data); - strip->start = CFRA; - strip->end += strip->start; - - /* hook them up */ - BKE_nlatrack_add_strip(nlt, strip); - - /* auto-name the strip, and give the track an interesting name */ - strcpy(nlt->name, "SoundTrack"); - BKE_nlastrip_validate_name(adt, strip); - - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); - } - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_speaker_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Speaker"; - ot->description = "Add a speaker object to the scene"; - ot->idname = "OBJECT_OT_speaker_add"; - - /* api callbacks */ - ot->exec = object_speaker_add_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - /* only used as menu */ void OBJECT_OT_group_instance_add(wmOperatorType *ot) { @@ -893,6 +847,63 @@ void OBJECT_OT_group_instance_add(wmOperatorType *ot) ED_object_add_generic_props(ot, FALSE); } +/********************* Add Speaker Operator ********************/ + +static int object_speaker_add_exec(bContext *C, wmOperator *op) +{ + Object *ob; + int enter_editmode; + unsigned int layer; + float loc[3], rot[3]; + Scene *scene = CTX_data_scene(C); + + object_add_generic_invoke_options(C, op); + if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) + return OPERATOR_CANCELLED; + + ob = ED_object_add_type(C, OB_SPEAKER, loc, rot, FALSE, layer); + + /* to make it easier to start using this immediately in NLA, a default sound clip is created + * ready to be moved around to retime the sound and/or make new sound clips + */ + { + /* create new data for NLA hierarchy */ + AnimData *adt = BKE_id_add_animdata(&ob->id); + NlaTrack *nlt = add_nlatrack(adt, NULL); + NlaStrip *strip = add_nla_soundstrip(CTX_data_scene(C), ob->data); + strip->start = CFRA; + strip->end += strip->start; + + /* hook them up */ + BKE_nlatrack_add_strip(nlt, strip); + + /* auto-name the strip, and give the track an interesting name */ + strcpy(nlt->name, "SoundTrack"); + BKE_nlastrip_validate_name(adt, strip); + + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); + } + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_speaker_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Speaker"; + ot->description = "Add a speaker object to the scene"; + ot->idname = "OBJECT_OT_speaker_add"; + + /* api callbacks */ + ot->exec = object_speaker_add_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_generic_props(ot, TRUE); +} + /**************************** Delete Object *************************/ static void object_delete_check_glsl_update(Object *ob) @@ -901,7 +912,7 @@ static void object_delete_check_glsl_update(Object *ob) * are being tagged to be updated when object is removing from scene */ if (ob->type == OB_LAMP) { - if (ob->gpulamp.first) + if (ob->gpulamp.first) GPU_lamp_free(ob); } } @@ -923,16 +934,12 @@ static int object_delete_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); const short use_global = RNA_boolean_get(op->ptr, "use_global"); - /* int is_lamp = FALSE; */ /* UNUSED */ - + if (CTX_data_edit_object(C)) return OPERATOR_CANCELLED; - + CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - - /* if (base->object->type==OB_LAMP) is_lamp = TRUE; */ - /* deselect object -- it could be used in other scenes */ base->object->flag &= ~SELECT; @@ -959,10 +966,10 @@ static int object_delete_exec(bContext *C, wmOperator *op) DAG_scene_sort(bmain, scene); DAG_ids_flush_update(bmain, 0); - + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); - + return OPERATOR_FINISHED; } @@ -972,12 +979,12 @@ void OBJECT_OT_delete(wmOperatorType *ot) ot->name = "Delete"; ot->description = "Delete selected objects"; ot->idname = "OBJECT_OT_delete"; - + /* api callbacks */ ot->invoke = WM_operator_confirm; ot->exec = object_delete_exec; ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -993,29 +1000,29 @@ static void copy_object_set_idnew(bContext *C, int dupflag) Material *ma, *mao; ID *id; int a; - + /* XXX check object pointers */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { BKE_object_relink(ob); } CTX_DATA_END; - + /* materials */ if (dupflag & USER_DUP_MAT) { mao = bmain->mat.first; while (mao) { if (mao->id.newid) { - ma = (Material *)mao->id.newid; - + if (dupflag & USER_DUP_TEX) { for (a = 0; a < MAX_MTEX; a++) { if (ma->mtex[a]) { id = (ID *)ma->mtex[a]->tex; if (id) { ID_NEW_US(ma->mtex[a]->tex) - else ma->mtex[a]->tex = BKE_texture_copy(ma->mtex[a]->tex); + else + ma->mtex[a]->tex = BKE_texture_copy(ma->mtex[a]->tex); id->us--; } } @@ -1025,7 +1032,8 @@ static void copy_object_set_idnew(bContext *C, int dupflag) id = (ID *)ma->ipo; if (id) { ID_NEW_US(ma->ipo) - else ma->ipo = copy_ipo(ma->ipo); + else + ma->ipo = copy_ipo(ma->ipo); id->us--; } #endif // XXX old animation system @@ -1033,7 +1041,7 @@ static void copy_object_set_idnew(bContext *C, int dupflag) mao = mao->id.next; } } - + #if 0 // XXX old animation system /* lamps */ if (dupflag & USER_DUP_IPO) { @@ -1044,14 +1052,15 @@ static void copy_object_set_idnew(bContext *C, int dupflag) id = (ID *)lan->ipo; if (id) { ID_NEW_US(lan->ipo) - else lan->ipo = copy_ipo(lan->ipo); + else + lan->ipo = copy_ipo(lan->ipo); id->us--; } } la = la->id.next; } } - + /* ipos */ ipo = bmain->ipo.first; while (ipo) { @@ -1067,9 +1076,9 @@ static void copy_object_set_idnew(bContext *C, int dupflag) ipo = ipo->id.next; } #endif // XXX old animation system - + set_sca_new_poins(); - + clear_id_newpoins(); } @@ -1082,17 +1091,17 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, ListBase *lb; DupliObject *dob; GHash *dupli_gh = NULL, *parent_gh = NULL; - + if (!(base->object->transflag & OB_DUPLI)) return; - + lb = object_duplilist(scene, base->object, FALSE); if (use_hierarchy || use_base_parent) { dupli_gh = BLI_ghash_ptr_new("make_object_duplilist_real dupli_gh"); parent_gh = BLI_ghash_pair_new("make_object_duplilist_real parent_gh"); } - + for (dob = lb->first; dob; dob = dob->next) { Base *basen; Object *ob = BKE_object_copy(dob->ob); @@ -1100,24 +1109,24 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, * should be implemented better... */ if (ob->mat == NULL) ob->totcol = 0; - + basen = MEM_dupallocN(base); basen->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP); ob->flag = basen->flag; basen->lay = base->lay; BLI_addhead(&scene->base, basen); /* addhead: othwise eternal loop */ basen->object = ob; - + /* make sure apply works */ BKE_free_animdata(&ob->id); ob->adt = NULL; - + ob->parent = NULL; ob->constraints.first = ob->constraints.last = NULL; ob->disp.first = ob->disp.last = NULL; ob->transflag &= ~OB_DUPLI; ob->lay = base->lay; - + copy_m4_m4(ob->obmat, dob->mat); BKE_object_apply_mat4(ob, ob->obmat, FALSE, FALSE); @@ -1126,7 +1135,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (parent_gh) BLI_ghash_insert(parent_gh, BLI_ghashutil_pairalloc(dob->ob, SET_INT_IN_POINTER(dob->index)), ob); } - + if (use_hierarchy) { for (dob = lb->first; dob; dob = dob->next) { /* original parents */ @@ -1186,8 +1195,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, invert_m4_m4(ob_dst->parentinv, dob->mat); BKE_object_apply_mat4(ob_dst, dob->mat, FALSE, TRUE); DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB); - - } } @@ -1197,9 +1204,9 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, BLI_ghash_free(parent_gh, BLI_ghashutil_pairfree, NULL); copy_object_set_idnew(C, 0); - + free_object_duplilist(lb); - + base->object->transflag &= ~OB_DUPLI; } @@ -1210,9 +1217,9 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op) const short use_base_parent = RNA_boolean_get(op->ptr, "use_base_parent"); const short use_hierarchy = RNA_boolean_get(op->ptr, "use_hierarchy"); - + clear_id_newpoins(); - + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { make_object_duplilist_real(C, scene, base, use_base_parent, use_hierarchy); @@ -1226,23 +1233,22 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op) DAG_ids_flush_update(bmain, 0); WM_event_add_notifier(C, NC_SCENE, scene); WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); - + return OPERATOR_FINISHED; } void OBJECT_OT_duplicates_make_real(wmOperatorType *ot) { - /* identifiers */ ot->name = "Make Duplicates Real"; ot->description = "Make dupli objects attached to this object real"; ot->idname = "OBJECT_OT_duplicates_make_real"; - + /* api callbacks */ ot->exec = object_duplicates_make_real_exec; - + ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1616,12 +1622,12 @@ void OBJECT_OT_convert(wmOperatorType *ot) ot->name = "Convert to"; ot->description = "Convert selected objects to another type"; ot->idname = "OBJECT_OT_convert"; - + /* api callbacks */ ot->invoke = WM_menu_invoke; ot->exec = convert_exec; ot->poll = convert_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1655,12 +1661,12 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base else { obn = BKE_object_copy(ob); obn->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; - + basen = MEM_mallocN(sizeof(Base), "duplibase"); *basen = *base; BLI_addhead(&scene->base, basen); /* addhead: prevent eternal loop */ basen->object = obn; - + if (basen->flag & OB_FROMGROUP) { Group *group; for (group = bmain->group.first; group; group = group->id.next) { @@ -1668,20 +1674,21 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base add_to_group(group, obn, scene, basen); } } - + /* duplicates using userflags */ if (dupflag & USER_DUP_ACT) { BKE_copy_animdata_id_action(&obn->id); } - + if (dupflag & USER_DUP_MAT) { for (a = 0; a < obn->totcol; a++) { id = (ID *)obn->mat[a]; if (id) { ID_NEW_US(obn->mat[a]) - else obn->mat[a] = BKE_material_copy(obn->mat[a]); + else + obn->mat[a] = BKE_material_copy(obn->mat[a]); id->us--; - + if (dupflag & USER_DUP_ACT) { BKE_copy_animdata_id_action(&obn->mat[a]->id); } @@ -1694,8 +1701,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base id = (ID *) psys->part; if (id) { ID_NEW_US(psys->part) - else psys->part = BKE_particlesettings_copy(psys->part); - + else + psys->part = BKE_particlesettings_copy(psys->part); + if (dupflag & USER_DUP_ACT) { BKE_copy_animdata_id_action(&psys->part->id); } @@ -1704,21 +1712,19 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base } } } - + id = obn->data; didit = 0; - + switch (obn->type) { case OB_MESH: if (dupflag & USER_DUP_MESH) { ID_NEW_US2(obn->data) else { obn->data = BKE_mesh_copy(obn->data); - if (obn->fluidsimSettings) { obn->fluidsimSettings->orgMesh = (Mesh *)obn->data; } - didit = 1; } id->us--; @@ -1774,11 +1780,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base id->us--; } break; - case OB_ARMATURE: obn->recalc |= OB_RECALC_DATA; - if (obn->pose) obn->pose->flag |= POSE_RECALC; - + if (obn->pose) + obn->pose->flag |= POSE_RECALC; if (dupflag & USER_DUP_ARM) { ID_NEW_US2(obn->data) else { @@ -1788,9 +1793,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base } id->us--; } - break; - case OB_LATTICE: if (dupflag != 0) { ID_NEW_US2(obn->data) @@ -1821,13 +1824,12 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base id->us--; } break; - } /* check if obdata is copied */ if (didit) { Key *key = BKE_key_from_object(obn); - + if (dupflag & USER_DUP_ACT) { bActuator *act; @@ -1846,7 +1848,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base } } } - + if (dupflag & USER_DUP_MAT) { matarar = give_matarar(obn); if (matarar) { @@ -1854,8 +1856,8 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base id = (ID *)(*matarar)[a]; if (id) { ID_NEW_US((*matarar)[a]) - else (*matarar)[a] = BKE_material_copy((*matarar)[a]); - + else + (*matarar)[a] = BKE_material_copy((*matarar)[a]); id->us--; } } @@ -1906,14 +1908,14 @@ static int duplicate_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); int linked = RNA_boolean_get(op->ptr, "linked"); int dupflag = (linked) ? 0 : U.dupflag; - + clear_id_newpoins(); clear_sca_new_poins(); /* sensor/contr/act */ - + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { Base *basen = object_add_duplicate_internal(bmain, scene, base, dupflag); - + /* note that this is safe to do with this context iterator, * the list is made in advance */ ED_base_object_select(base, BA_DESELECT); @@ -1945,19 +1947,19 @@ static int duplicate_exec(bContext *C, wmOperator *op) void OBJECT_OT_duplicate(wmOperatorType *ot) { PropertyRNA *prop; - + /* identifiers */ ot->name = "Duplicate Objects"; ot->description = "Duplicate selected objects"; ot->idname = "OBJECT_OT_duplicate"; - + /* api callbacks */ ot->exec = duplicate_exec; ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* to give to transform */ RNA_def_boolean(ot->srna, "linked", 0, "Linked", "Duplicate object but not object data, linking to the original data"); prop = RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", ""); @@ -1966,7 +1968,6 @@ void OBJECT_OT_duplicate(wmOperatorType *ot) /* **************** add named object, for dragdrop ************* */ - static int add_named_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -2021,34 +2022,32 @@ void OBJECT_OT_add_named(wmOperatorType *ot) ot->name = "Add Named Object"; ot->description = "Add named object"; ot->idname = "OBJECT_OT_add_named"; - + /* api callbacks */ ot->exec = add_named_exec; ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + RNA_def_boolean(ot->srna, "linked", 0, "Linked", "Duplicate object but not object data, linking to the original data"); RNA_def_string(ot->srna, "name", "Cube", MAX_ID_NAME - 2, "Name", "Object name to add"); } - - /**************************** Join *************************/ + static int join_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - + if (!ob || ob->id.lib) return 0; - + if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE)) return ED_operator_screenactive(C); else return 0; } - static int join_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -2069,7 +2068,7 @@ static int join_exec(bContext *C, wmOperator *op) return join_curve_exec(C, op); else if (ob->type == OB_ARMATURE) return join_armature_exec(C, op); - + return OPERATOR_CANCELLED; } @@ -2079,22 +2078,23 @@ void OBJECT_OT_join(wmOperatorType *ot) ot->name = "Join"; ot->description = "Join selected objects into active object"; ot->idname = "OBJECT_OT_join"; - + /* api callbacks */ ot->exec = join_exec; ot->poll = join_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /**************************** Join as Shape Key*************************/ + static int join_shapes_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - + if (!ob || ob->id.lib) return 0; - + /* only meshes supported at the moment */ if (ob->type == OB_MESH) return ED_operator_screenactive(C); @@ -2106,7 +2106,7 @@ static int join_shapes_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - + if (scene->obedit) { BKE_report(op->reports, RPT_ERROR, "This data does not support joining in editmode"); return OPERATOR_CANCELLED; @@ -2115,10 +2115,10 @@ static int join_shapes_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata"); return OPERATOR_CANCELLED; } - + if (ob->type == OB_MESH) return join_mesh_shapes_exec(C, op); - + return OPERATOR_CANCELLED; } @@ -2128,11 +2128,11 @@ void OBJECT_OT_join_shapes(wmOperatorType *ot) ot->name = "Join as Shapes"; ot->description = "Merge selected objects to shapes of active object"; ot->idname = "OBJECT_OT_join_shapes"; - + /* api callbacks */ ot->exec = join_shapes_exec; ot->poll = join_shapes_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } From cc26da4421cc9bf825fc5f8dd565fdbbc0b7ab39 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 5 Oct 2012 07:17:45 +0000 Subject: [PATCH 101/143] Fix #32707: texture preview not loaded --- source/blender/editors/interface/interface_templates.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index d3d4e01bc75..5f9722d0ec0 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -362,6 +362,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str type = idptr.type; if (flag & UI_ID_PREVIEWS) { + template->preview = TRUE; but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, TIP_(template_id_browse_tip(type))); @@ -374,7 +375,6 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str uiButSetFlag(but, UI_BUT_DISABLED); uiLayoutRow(layout, TRUE); - template->preview = 1; } else if (flag & UI_ID_BROWSE) { but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y, From 862decfc82a30066ccb8e3da13f6ba8b89fbadff Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 5 Oct 2012 07:31:30 +0000 Subject: [PATCH 102/143] Booleans: epsilon for planar checks seems a bit too small for single precision math This could solve issue #32748: Boolean Modifiers Making unneeded edges? --- intern/bsp/intern/BOP_CarveInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/bsp/intern/BOP_CarveInterface.cpp b/intern/bsp/intern/BOP_CarveInterface.cpp index 255d885007c..1f9c989cbc8 100644 --- a/intern/bsp/intern/BOP_CarveInterface.cpp +++ b/intern/bsp/intern/BOP_CarveInterface.cpp @@ -58,7 +58,7 @@ static bool isQuadPlanar(carve::geom3d::Vector &v1, carve::geom3d::Vector &v2, cross = carve::geom::cross(vec1, vec2); float production = carve::geom::dot(cross, vec3); - float magnitude = 1e-6 * cross.length(); + float magnitude = 1e-5 * cross.length(); return fabs(production) < magnitude; } From 4c3620c69d0c39f288b82327b9c549919bac98ee Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 5 Oct 2012 10:05:26 +0000 Subject: [PATCH 103/143] Fixed compilation error on widows Was caused by mixing up own C-API typedefs with OCIO's --- intern/opencolorio/CMakeLists.txt | 1 - intern/opencolorio/fallback_impl.cc | 130 +++++---- intern/opencolorio/ocio_capi.cc | 98 ++++--- intern/opencolorio/ocio_capi.h | 125 ++++---- intern/opencolorio/ocio_impl.cc | 195 ++++++------- intern/opencolorio/ocio_impl.h | 270 +++++++++--------- .../imbuf/intern/IMB_colormanagement_intern.h | 10 +- source/blender/imbuf/intern/colormanagement.c | 108 +++---- 8 files changed, 466 insertions(+), 471 deletions(-) diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt index fb74d5e3f4e..d46b09cf76a 100644 --- a/intern/opencolorio/CMakeLists.txt +++ b/intern/opencolorio/CMakeLists.txt @@ -62,4 +62,3 @@ endif() blender_add_lib(bf_intern_opencolorio "${SRC}" "${INC}" "${INC_SYS}") - diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc index 4badcc54ebd..44c02d1442b 100644 --- a/intern/opencolorio/fallback_impl.cc +++ b/intern/opencolorio/fallback_impl.cc @@ -28,20 +28,18 @@ #include "MEM_guardedalloc.h" #include "BLI_math_color.h" -namespace OCIO_NAMESPACE {}; - #include "ocio_impl.h" -#define CONFIG_DEFAULT ((ConstConfigRcPtr*)1) +#define CONFIG_DEFAULT ((OCIO_ConstConfigRcPtr*)1) -#define PROCESSOR_LINEAR_TO_SRGB ((ConstProcessorRcPtr*)1) -#define PROCESSOR_SRGB_TO_LINEAR ((ConstProcessorRcPtr*)2) -#define PROCESSOR_UNKNOWN ((ConstProcessorRcPtr*)3) +#define PROCESSOR_LINEAR_TO_SRGB ((OCIO_ConstProcessorRcPtr*)1) +#define PROCESSOR_SRGB_TO_LINEAR ((OCIO_ConstProcessorRcPtr*)2) +#define PROCESSOR_UNKNOWN ((OCIO_ConstProcessorRcPtr*)3) -#define COLORSPACE_LINEAR ((ConstColorSpaceRcPtr*)1) -#define COLORSPACE_SRGB ((ConstColorSpaceRcPtr*)2) +#define COLORSPACE_LINEAR ((OCIO_ConstColorSpaceRcPtr*)1) +#define COLORSPACE_SRGB ((OCIO_ConstColorSpaceRcPtr*)2) -typedef struct PackedImageDescription { +typedef struct OCIO_PackedImageDescription { float *data; long width; long height; @@ -49,37 +47,37 @@ typedef struct PackedImageDescription { long chanStrideBytes; long xStrideBytes; long yStrideBytes; -} PackedImageDescription; +} OCIO_PackedImageDescription; -ConstConfigRcPtr *FallbackImpl::getCurrentConfig(void) +OCIO_ConstConfigRcPtr *FallbackImpl::getCurrentConfig(void) { return CONFIG_DEFAULT; } -void FallbackImpl::setCurrentConfig(const ConstConfigRcPtr *) +void FallbackImpl::setCurrentConfig(const OCIO_ConstConfigRcPtr *) { } -ConstConfigRcPtr *FallbackImpl::configCreateFromEnv(void) +OCIO_ConstConfigRcPtr *FallbackImpl::configCreateFromEnv(void) { return CONFIG_DEFAULT; } -ConstConfigRcPtr *FallbackImpl::configCreateFromFile(const char *) +OCIO_ConstConfigRcPtr *FallbackImpl::configCreateFromFile(const char *) { return CONFIG_DEFAULT; } -void FallbackImpl::configRelease(ConstConfigRcPtr *) +void FallbackImpl::configRelease(OCIO_ConstConfigRcPtr *) { } -int FallbackImpl::configGetNumColorSpaces(ConstConfigRcPtr *) +int FallbackImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr *) { return 2; } -const char *FallbackImpl::configGetColorSpaceNameByIndex(ConstConfigRcPtr *, int index) +const char *FallbackImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *, int index) { if (index == 0) return "Linear"; @@ -89,7 +87,7 @@ const char *FallbackImpl::configGetColorSpaceNameByIndex(ConstConfigRcPtr *, int return NULL; } -ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(ConstConfigRcPtr *, const char *name) +OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcPtr *, const char *name) { if (strcmp(name, "scene_linear") == 0) return COLORSPACE_LINEAR; @@ -111,9 +109,9 @@ ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(ConstConfigRcPtr *, cons return NULL; } -int FallbackImpl::configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) +int FallbackImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) { - ConstColorSpaceRcPtr *cs = configGetColorSpace(config, name); + OCIO_ConstColorSpaceRcPtr *cs = configGetColorSpace(config, name); if (cs == COLORSPACE_LINEAR) return 0; @@ -123,17 +121,17 @@ int FallbackImpl::configGetIndexForColorSpace(ConstConfigRcPtr *config, const ch return -1; } -const char *FallbackImpl::configGetDefaultDisplay(ConstConfigRcPtr *) +const char *FallbackImpl::configGetDefaultDisplay(OCIO_ConstConfigRcPtr *) { return "sRGB"; } -int FallbackImpl::configGetNumDisplays(ConstConfigRcPtr* config) +int FallbackImpl::configGetNumDisplays(OCIO_ConstConfigRcPtr* config) { return 1; } -const char *FallbackImpl::configGetDisplay(ConstConfigRcPtr *, int index) +const char *FallbackImpl::configGetDisplay(OCIO_ConstConfigRcPtr *, int index) { if (index == 0) return "sRGB"; @@ -141,17 +139,17 @@ const char *FallbackImpl::configGetDisplay(ConstConfigRcPtr *, int index) return NULL; } -const char *FallbackImpl::configGetDefaultView(ConstConfigRcPtr *, const char *) +const char *FallbackImpl::configGetDefaultView(OCIO_ConstConfigRcPtr *, const char *) { return "Default"; } -int FallbackImpl::configGetNumViews(ConstConfigRcPtr *, const char *) +int FallbackImpl::configGetNumViews(OCIO_ConstConfigRcPtr *, const char *) { return 1; } -const char *FallbackImpl::configGetView(ConstConfigRcPtr *, const char *, int index) +const char *FallbackImpl::configGetView(OCIO_ConstConfigRcPtr *, const char *, int index) { if (index == 0) return "Default"; @@ -159,29 +157,29 @@ const char *FallbackImpl::configGetView(ConstConfigRcPtr *, const char *, int in return NULL; } -const char *FallbackImpl::configGetDisplayColorSpaceName(ConstConfigRcPtr *, const char *, const char *) +const char *FallbackImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *, const char *, const char *) { return "sRGB"; } -int FallbackImpl::colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) +int FallbackImpl::colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs) { return 1; } -int FallbackImpl::colorSpaceIsData(ConstColorSpaceRcPtr *cs) +int FallbackImpl::colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs) { return 0; } -void FallbackImpl::colorSpaceRelease(ConstColorSpaceRcPtr *cs) +void FallbackImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs) { } -ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName) +OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName) { - ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName); - ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName); + OCIO_ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName); + OCIO_ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName); if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) return PROCESSOR_LINEAR_TO_SRGB; @@ -191,15 +189,15 @@ ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(ConstConfigRcPtr return 0; } -ConstProcessorRcPtr *FallbackImpl::configGetProcessor(ConstConfigRcPtr *, ConstTransformRcPtr *tfm) +OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessor(OCIO_ConstConfigRcPtr *, OCIO_ConstTransformRcPtr *tfm) { - return (ConstProcessorRcPtr*)tfm; + return (OCIO_ConstProcessorRcPtr*)tfm; } -void FallbackImpl::processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) +void FallbackImpl::processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) { /* OCIO_TODO stride not respected, channels must be 3 or 4 */ - PackedImageDescription *desc = (PackedImageDescription*)img; + OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)img; int channels = desc->numChannels; float *pixels = desc->data; int width = desc->width; @@ -218,10 +216,10 @@ void FallbackImpl::processorApply(ConstProcessorRcPtr *processor, PackedImageDes } } -void FallbackImpl::processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img) +void FallbackImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) { /* OCIO_TODO stride not respected, channels must be 3 or 4 */ - PackedImageDescription *desc = (PackedImageDescription*)img; + OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)img; int channels = desc->numChannels; float *pixels = desc->data; int width = desc->width; @@ -240,7 +238,7 @@ void FallbackImpl::processorApply_predivide(ConstProcessorRcPtr *processor, Pack } } -void FallbackImpl::processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) +void FallbackImpl::processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel) { if (processor == PROCESSOR_LINEAR_TO_SRGB) linearrgb_to_srgb_v3_v3(pixel, pixel); @@ -248,7 +246,7 @@ void FallbackImpl::processorApplyRGB(ConstProcessorRcPtr *processor, float *pixe srgb_to_linearrgb_v3_v3(pixel, pixel); } -void FallbackImpl::processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) +void FallbackImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel) { if (processor == PROCESSOR_LINEAR_TO_SRGB) linearrgb_to_srgb_v4(pixel, pixel); @@ -256,7 +254,7 @@ void FallbackImpl::processorApplyRGBA(ConstProcessorRcPtr *processor, float *pix srgb_to_linearrgb_v4(pixel, pixel); } -void FallbackImpl::processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel) +void FallbackImpl::processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel) { if (pixel[3] == 1.0f || pixel[3] == 0.0f) { processorApplyRGBA(processor, pixel); @@ -279,11 +277,11 @@ void FallbackImpl::processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, } } -void FallbackImpl::processorRelease(ConstProcessorRcPtr *) +void FallbackImpl::processorRelease(OCIO_ConstProcessorRcPtr *) { } -const char *FallbackImpl::colorSpaceGetName(ConstColorSpaceRcPtr *cs) +const char *FallbackImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs) { if (cs == COLORSPACE_LINEAR) return "Linear"; @@ -293,49 +291,49 @@ const char *FallbackImpl::colorSpaceGetName(ConstColorSpaceRcPtr *cs) return NULL; } -const char *FallbackImpl::colorSpaceGetDescription(ConstColorSpaceRcPtr *) +const char *FallbackImpl::colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *) { return ""; } -const char *FallbackImpl::colorSpaceGetFamily(ConstColorSpaceRcPtr *) +const char *FallbackImpl::colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *) { return ""; } -DisplayTransformRcPtr *FallbackImpl::createDisplayTransform(void) +OCIO_DisplayTransformRcPtr *FallbackImpl::createDisplayTransform(void) { - return (DisplayTransformRcPtr*)PROCESSOR_LINEAR_TO_SRGB; + return (OCIO_DisplayTransformRcPtr*)PROCESSOR_LINEAR_TO_SRGB; } -void FallbackImpl::displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *, const char *) +void FallbackImpl::displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr *, const char *) { } -void FallbackImpl::displayTransformSetDisplay(DisplayTransformRcPtr *, const char *) +void FallbackImpl::displayTransformSetDisplay(OCIO_DisplayTransformRcPtr *, const char *) { } -void FallbackImpl::displayTransformSetView(DisplayTransformRcPtr *, const char *) +void FallbackImpl::displayTransformSetView(OCIO_DisplayTransformRcPtr *, const char *) { } -void FallbackImpl::displayTransformSetDisplayCC(DisplayTransformRcPtr *, ConstTransformRcPtr *) +void FallbackImpl::displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr *, OCIO_ConstTransformRcPtr *) { } -void FallbackImpl::displayTransformSetLinearCC(DisplayTransformRcPtr *, ConstTransformRcPtr *) +void FallbackImpl::displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr *, OCIO_ConstTransformRcPtr *) { } -void FallbackImpl::displayTransformRelease(DisplayTransformRcPtr *) +void FallbackImpl::displayTransformRelease(OCIO_DisplayTransformRcPtr *) { } -PackedImageDesc *FallbackImpl::createPackedImageDesc(float *data, long width, long height, long numChannels, +OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes) { - PackedImageDescription *desc = (PackedImageDescription*)MEM_callocN(sizeof(PackedImageDescription), "PackedImageDescription"); + OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)MEM_callocN(sizeof(OCIO_PackedImageDescription), "OCIO_PackedImageDescription"); desc->data = data; desc->width = width; @@ -345,37 +343,37 @@ PackedImageDesc *FallbackImpl::createPackedImageDesc(float *data, long width, lo desc->xStrideBytes = xStrideBytes; desc->yStrideBytes = yStrideBytes; - return (PackedImageDesc*)desc; + return (OCIO_PackedImageDesc*)desc; } -void FallbackImpl::packedImageDescRelease(PackedImageDesc* id) +void FallbackImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc* id) { MEM_freeN(id); } -ExponentTransformRcPtr *FallbackImpl::createExponentTransform(void) +OCIO_ExponentTransformRcPtr *FallbackImpl::createExponentTransform(void) { - return (ExponentTransformRcPtr*)PROCESSOR_UNKNOWN; + return (OCIO_ExponentTransformRcPtr*)PROCESSOR_UNKNOWN; } -void FallbackImpl::exponentTransformSetValue(ExponentTransformRcPtr *, const float *) +void FallbackImpl::exponentTransformSetValue(OCIO_ExponentTransformRcPtr *, const float *) { } -void FallbackImpl::exponentTransformRelease(ExponentTransformRcPtr *) +void FallbackImpl::exponentTransformRelease(OCIO_ExponentTransformRcPtr *) { } -MatrixTransformRcPtr *FallbackImpl::createMatrixTransform(void) +OCIO_MatrixTransformRcPtr *FallbackImpl::createMatrixTransform(void) { - return (MatrixTransformRcPtr*)PROCESSOR_UNKNOWN; + return (OCIO_MatrixTransformRcPtr*)PROCESSOR_UNKNOWN; } -void FallbackImpl::matrixTransformSetValue(MatrixTransformRcPtr *, const float *, const float *) +void FallbackImpl::matrixTransformSetValue(OCIO_MatrixTransformRcPtr *, const float *, const float *) { } -void FallbackImpl::matrixTransformRelease(MatrixTransformRcPtr *) +void FallbackImpl::matrixTransformRelease(OCIO_MatrixTransformRcPtr *) { } diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc index 20e7cc23daa..18fa4b7cb1b 100644 --- a/intern/opencolorio/ocio_capi.cc +++ b/intern/opencolorio/ocio_capi.cc @@ -25,8 +25,6 @@ #include "MEM_guardedalloc.h" -namespace OCIO_NAMESPACE {}; - #include "ocio_impl.h" static IOCIOImpl *impl = NULL; @@ -46,12 +44,12 @@ void OCIO_exit(void) impl = NULL; } -ConstConfigRcPtr *OCIO_getCurrentConfig(void) +OCIO_ConstConfigRcPtr *OCIO_getCurrentConfig(void) { return impl->getCurrentConfig(); } -ConstConfigRcPtr *OCIO_configCreateFallback(void) +OCIO_ConstConfigRcPtr *OCIO_configCreateFallback(void) { delete impl; impl = new FallbackImpl(); @@ -59,223 +57,223 @@ ConstConfigRcPtr *OCIO_configCreateFallback(void) return impl->getCurrentConfig(); } -void OCIO_setCurrentConfig(const ConstConfigRcPtr *config) +void OCIO_setCurrentConfig(const OCIO_ConstConfigRcPtr *config) { impl->setCurrentConfig(config); } -ConstConfigRcPtr *OCIO_configCreateFromEnv(void) +OCIO_ConstConfigRcPtr *OCIO_configCreateFromEnv(void) { return impl->configCreateFromEnv(); } -ConstConfigRcPtr *OCIO_configCreateFromFile(const char *filename) +OCIO_ConstConfigRcPtr *OCIO_configCreateFromFile(const char *filename) { return impl->configCreateFromFile(filename); } -void OCIO_configRelease(ConstConfigRcPtr *config) +void OCIO_configRelease(OCIO_ConstConfigRcPtr *config) { impl->configRelease(config); } -int OCIO_configGetNumColorSpaces(ConstConfigRcPtr *config) +int OCIO_configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config) { return impl->configGetNumColorSpaces(config); } -const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index) +const char *OCIO_configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index) { return impl->configGetColorSpaceNameByIndex(config, index); } -ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *config, const char *name) +OCIO_ConstColorSpaceRcPtr *OCIO_configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) { return impl->configGetColorSpace(config, name); } -int OCIO_configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) +int OCIO_configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) { return impl->configGetIndexForColorSpace(config, name); } -const char *OCIO_configGetDefaultDisplay(ConstConfigRcPtr *config) +const char *OCIO_configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config) { return impl->configGetDefaultDisplay(config); } -int OCIO_configGetNumDisplays(ConstConfigRcPtr* config) +int OCIO_configGetNumDisplays(OCIO_ConstConfigRcPtr* config) { return impl->configGetNumDisplays(config); } -const char *OCIO_configGetDisplay(ConstConfigRcPtr *config, int index) +const char *OCIO_configGetDisplay(OCIO_ConstConfigRcPtr *config, int index) { return impl->configGetDisplay(config, index); } -const char *OCIO_configGetDefaultView(ConstConfigRcPtr *config, const char *display) +const char *OCIO_configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display) { return impl->configGetDefaultView(config, display); } -int OCIO_configGetNumViews(ConstConfigRcPtr *config, const char *display) +int OCIO_configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display) { return impl->configGetNumViews(config, display); } -const char *OCIO_configGetView(ConstConfigRcPtr *config, const char *display, int index) +const char *OCIO_configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index) { return impl->configGetView(config, display, index); } -const char *OCIO_configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view) +const char *OCIO_configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view) { return impl->configGetDisplayColorSpaceName(config, display, view); } -int OCIO_colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) +int OCIO_colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs) { return impl->colorSpaceIsInvertible(cs); } -int OCIO_colorSpaceIsData(ConstColorSpaceRcPtr *cs) +int OCIO_colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs) { return impl->colorSpaceIsData(cs); } -void OCIO_colorSpaceRelease(ConstColorSpaceRcPtr *cs) +void OCIO_colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs) { impl->colorSpaceRelease(cs); } -ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName) +OCIO_ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName) { return impl->configGetProcessorWithNames(config, srcName, dstName); } -ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform) +OCIO_ConstProcessorRcPtr *OCIO_configGetProcessor(OCIO_ConstConfigRcPtr *config, OCIO_ConstTransformRcPtr *transform) { return impl->configGetProcessor(config, transform); } -void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) +void OCIO_processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) { impl->processorApply(processor, img); } -void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img) +void OCIO_processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) { impl->processorApply_predivide(processor, img); } -void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) +void OCIO_processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel) { impl->processorApplyRGB(processor, pixel); } -void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) +void OCIO_processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel) { impl->processorApplyRGBA(processor, pixel); } -void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel) +void OCIO_processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel) { impl->processorApplyRGBA_predivide(processor, pixel); } -void OCIO_processorRelease(ConstProcessorRcPtr *p) +void OCIO_processorRelease(OCIO_ConstProcessorRcPtr *p) { impl->processorRelease(p); } -const char *OCIO_colorSpaceGetName(ConstColorSpaceRcPtr *cs) +const char *OCIO_colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs) { return impl->colorSpaceGetName(cs); } -const char *OCIO_colorSpaceGetDescription(ConstColorSpaceRcPtr *cs) +const char *OCIO_colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs) { return impl->colorSpaceGetDescription(cs); } -const char *OCIO_colorSpaceGetFamily(ConstColorSpaceRcPtr *cs) +const char *OCIO_colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs) { return impl->colorSpaceGetFamily(cs); } -DisplayTransformRcPtr *OCIO_createDisplayTransform(void) +OCIO_DisplayTransformRcPtr *OCIO_createDisplayTransform(void) { return impl->createDisplayTransform(); } -void OCIO_displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name) +void OCIO_displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr *dt, const char *name) { impl->displayTransformSetInputColorSpaceName(dt, name); } -void OCIO_displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name) +void OCIO_displayTransformSetDisplay(OCIO_DisplayTransformRcPtr *dt, const char *name) { impl->displayTransformSetDisplay(dt, name); } -void OCIO_displayTransformSetView(DisplayTransformRcPtr *dt, const char *name) +void OCIO_displayTransformSetView(OCIO_DisplayTransformRcPtr *dt, const char *name) { impl->displayTransformSetView(dt, name); } -void OCIO_displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t) +void OCIO_displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *t) { impl->displayTransformSetDisplayCC(dt, t); } -void OCIO_displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t) +void OCIO_displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *t) { impl->displayTransformSetLinearCC(dt, t); } -void OCIO_displayTransformRelease(DisplayTransformRcPtr *dt) +void OCIO_displayTransformRelease(OCIO_DisplayTransformRcPtr *dt) { impl->displayTransformRelease(dt); } -PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height, long numChannels, +OCIO_PackedImageDesc *OCIO_createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes) { - return impl->createPackedImageDesc(data, width, height, numChannels, chanStrideBytes, xStrideBytes, yStrideBytes); + return impl->createOCIO_PackedImageDesc(data, width, height, numChannels, chanStrideBytes, xStrideBytes, yStrideBytes); } -void OCIO_packedImageDescRelease(PackedImageDesc* id) +void OCIO_OCIO_PackedImageDescRelease(OCIO_PackedImageDesc* id) { - impl->packedImageDescRelease(id); + impl->OCIO_PackedImageDescRelease(id); } -ExponentTransformRcPtr *OCIO_createExponentTransform(void) +OCIO_ExponentTransformRcPtr *OCIO_createExponentTransform(void) { return impl->createExponentTransform(); } -void OCIO_exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent) +void OCIO_exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent) { impl->exponentTransformSetValue(et, exponent); } -void OCIO_exponentTransformRelease(ExponentTransformRcPtr *et) +void OCIO_exponentTransformRelease(OCIO_ExponentTransformRcPtr *et) { impl->exponentTransformRelease(et); } -MatrixTransformRcPtr *OCIO_createMatrixTransform(void) +OCIO_MatrixTransformRcPtr *OCIO_createMatrixTransform(void) { return impl->createMatrixTransform(); } -void OCIO_matrixTransformSetValue(MatrixTransformRcPtr *mt, const float *m44, const float *offset4) +void OCIO_matrixTransformSetValue(OCIO_MatrixTransformRcPtr *mt, const float *m44, const float *offset4) { impl->matrixTransformSetValue(mt, m44, offset4); } -void OCIO_matrixTransformRelease(MatrixTransformRcPtr *mt) +void OCIO_matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt) { impl->matrixTransformRelease(mt); } diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h index f924bffb8e0..0ce5f8a1456 100644 --- a/intern/opencolorio/ocio_capi.h +++ b/intern/opencolorio/ocio_capi.h @@ -29,96 +29,93 @@ #define __OCIO_CAPI_H__ #ifdef __cplusplus -using namespace OCIO_NAMESPACE; extern "C" { #endif #define OCIO_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name -#ifndef OCIO_CAPI_IMPLEMENTATION - #define OCIO_ROLE_SCENE_LINEAR "scene_linear" - #define OCIO_ROLE_COLOR_PICKING "color_picking" - #define OCIO_ROLE_TEXTURE_PAINT "texture_paint" - #define OCIO_ROLE_DEFAULT_BYTE "default_byte" - #define OCIO_ROLE_DEFAULT_FLOAT "default_float" - #define OCIO_ROLE_DEFAULT_SEQUENCER "default_sequencer" +#define OCIO_ROLE_SCENE_LINEAR "scene_linear" +#define OCIO_ROLE_COLOR_PICKING "color_picking" +#define OCIO_ROLE_TEXTURE_PAINT "texture_paint" +#define OCIO_ROLE_DEFAULT_BYTE "default_byte" +#define OCIO_ROLE_DEFAULT_FLOAT "default_float" +#define OCIO_ROLE_DEFAULT_SEQUENCER "default_sequencer" - OCIO_DECLARE_HANDLE(ConstConfigRcPtr); - OCIO_DECLARE_HANDLE(ConstColorSpaceRcPtr); - OCIO_DECLARE_HANDLE(ConstProcessorRcPtr); - OCIO_DECLARE_HANDLE(ConstContextRcPtr); - OCIO_DECLARE_HANDLE(PackedImageDesc); - OCIO_DECLARE_HANDLE(DisplayTransformRcPtr); - OCIO_DECLARE_HANDLE(ConstTransformRcPtr); - OCIO_DECLARE_HANDLE(ExponentTransformRcPtr); - OCIO_DECLARE_HANDLE(MatrixTransformRcPtr); -#endif +OCIO_DECLARE_HANDLE(OCIO_ConstConfigRcPtr); +OCIO_DECLARE_HANDLE(OCIO_ConstColorSpaceRcPtr); +OCIO_DECLARE_HANDLE(OCIO_ConstProcessorRcPtr); +OCIO_DECLARE_HANDLE(OCIO_ConstContextRcPtr); +OCIO_DECLARE_HANDLE(OCIO_PackedImageDesc); +OCIO_DECLARE_HANDLE(OCIO_DisplayTransformRcPtr); +OCIO_DECLARE_HANDLE(OCIO_ConstTransformRcPtr); +OCIO_DECLARE_HANDLE(OCIO_ExponentTransformRcPtr); +OCIO_DECLARE_HANDLE(OCIO_MatrixTransformRcPtr); void OCIO_init(void); void OCIO_exit(void); -ConstConfigRcPtr *OCIO_getCurrentConfig(void); -void OCIO_setCurrentConfig(const ConstConfigRcPtr *config); +OCIO_ConstConfigRcPtr *OCIO_getCurrentConfig(void); +void OCIO_setCurrentConfig(const OCIO_ConstConfigRcPtr *config); -ConstConfigRcPtr *OCIO_configCreateFromEnv(void); -ConstConfigRcPtr *OCIO_configCreateFromFile(const char* filename); -ConstConfigRcPtr *OCIO_configCreateFallback(void); +OCIO_ConstConfigRcPtr *OCIO_configCreateFromEnv(void); +OCIO_ConstConfigRcPtr *OCIO_configCreateFromFile(const char* filename); +OCIO_ConstConfigRcPtr *OCIO_configCreateFallback(void); -void OCIO_configRelease(ConstConfigRcPtr *config); +void OCIO_configRelease(OCIO_ConstConfigRcPtr *config); -int OCIO_configGetNumColorSpaces(ConstConfigRcPtr *config); -const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index); -ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *config, const char *name); -int OCIO_configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name); +int OCIO_configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config); +const char *OCIO_configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index); +OCIO_ConstColorSpaceRcPtr *OCIO_configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name); +int OCIO_configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name); -int OCIO_colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs); -int OCIO_colorSpaceIsData(ConstColorSpaceRcPtr *cs); +int OCIO_colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs); +int OCIO_colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs); -void OCIO_colorSpaceRelease(ConstColorSpaceRcPtr *cs); +void OCIO_colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs); -const char *OCIO_configGetDefaultDisplay(ConstConfigRcPtr *config); -int OCIO_configGetNumDisplays(ConstConfigRcPtr *config); -const char *OCIO_configGetDisplay(ConstConfigRcPtr *config, int index); -const char *OCIO_configGetDefaultView(ConstConfigRcPtr *config, const char *display); -int OCIO_configGetNumViews(ConstConfigRcPtr *config, const char *display); -const char *OCIO_configGetView(ConstConfigRcPtr *config, const char *display, int index); -const char *OCIO_configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view); +const char *OCIO_configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config); +int OCIO_configGetNumDisplays(OCIO_ConstConfigRcPtr *config); +const char *OCIO_configGetDisplay(OCIO_ConstConfigRcPtr *config, int index); +const char *OCIO_configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display); +int OCIO_configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display); +const char *OCIO_configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index); +const char *OCIO_configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view); -ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName); -ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform); +OCIO_ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName); +OCIO_ConstProcessorRcPtr *OCIO_configGetProcessor(OCIO_ConstConfigRcPtr *config, OCIO_ConstTransformRcPtr *transform); -void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img); -void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img); -void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel); -void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel); -void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel); +void OCIO_processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img); +void OCIO_processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img); +void OCIO_processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel); +void OCIO_processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel); +void OCIO_processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel); -void OCIO_processorRelease(ConstProcessorRcPtr *p); +void OCIO_processorRelease(OCIO_ConstProcessorRcPtr *p); -const char *OCIO_colorSpaceGetName(ConstColorSpaceRcPtr *cs); -const char *OCIO_colorSpaceGetDescription(ConstColorSpaceRcPtr *cs); -const char *OCIO_colorSpaceGetFamily(ConstColorSpaceRcPtr *cs); +const char *OCIO_colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs); +const char *OCIO_colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs); +const char *OCIO_colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs); -DisplayTransformRcPtr *OCIO_createDisplayTransform(void); -void OCIO_displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name); -void OCIO_displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name); -void OCIO_displayTransformSetView(DisplayTransformRcPtr *dt, const char *name); -void OCIO_displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et); -void OCIO_displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et); -void OCIO_displayTransformRelease(DisplayTransformRcPtr *dt); +OCIO_DisplayTransformRcPtr *OCIO_createDisplayTransform(void); +void OCIO_displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr *dt, const char *name); +void OCIO_displayTransformSetDisplay(OCIO_DisplayTransformRcPtr *dt, const char *name); +void OCIO_displayTransformSetView(OCIO_DisplayTransformRcPtr *dt, const char *name); +void OCIO_displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *et); +void OCIO_displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *et); +void OCIO_displayTransformRelease(OCIO_DisplayTransformRcPtr *dt); -PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height, long numChannels, +OCIO_PackedImageDesc *OCIO_createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes); -void OCIO_packedImageDescRelease(PackedImageDesc *p); +void OCIO_OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *p); -ExponentTransformRcPtr *OCIO_createExponentTransform(void); -void OCIO_exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent); -void OCIO_exponentTransformRelease(ExponentTransformRcPtr *et); +OCIO_ExponentTransformRcPtr *OCIO_createExponentTransform(void); +void OCIO_exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent); +void OCIO_exponentTransformRelease(OCIO_ExponentTransformRcPtr *et); -MatrixTransformRcPtr *OCIO_createMatrixTransform(void); -void OCIO_matrixTransformSetValue(MatrixTransformRcPtr *et, const float *m44, const float *offset4); -void OCIO_matrixTransformRelease(MatrixTransformRcPtr *mt); +OCIO_MatrixTransformRcPtr *OCIO_createMatrixTransform(void); +void OCIO_matrixTransformSetValue(OCIO_MatrixTransformRcPtr *et, const float *m44, const float *offset4); +void OCIO_matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt); void OCIO_matrixTransformScale(float * m44, float * offset4, const float * scale4); diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc index 5d5c66cd356..49fc44d1e12 100644 --- a/intern/opencolorio/ocio_impl.cc +++ b/intern/opencolorio/ocio_impl.cc @@ -30,9 +30,10 @@ #include +using namespace OCIO_NAMESPACE; + #include "MEM_guardedalloc.h" -#define OCIO_CAPI_IMPLEMENTATION #include "ocio_impl.h" #if !defined(WITH_ASSERT_ABORT) @@ -47,7 +48,7 @@ #endif #define MEM_NEW(type) new(MEM_mallocN(sizeof(type), __func__)) type() -#define MEM_DELETE(what, type) if(what) { what->~type(); MEM_freeN(what); } (void)0 +#define MEM_DELETE(what, type) if(what) { (what)->~type(); MEM_freeN(what); } (void)0 static void OCIO_reportError(const char *err) { @@ -61,15 +62,15 @@ static void OCIO_reportException(Exception &exception) OCIO_reportError(exception.what()); } -ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void) +OCIO_ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void) { ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr); try { *config = GetCurrentConfig(); - if(*config) - return config; + if (*config) + return (OCIO_ConstConfigRcPtr *) config; } catch (Exception &exception) { OCIO_reportException(exception); @@ -80,17 +81,17 @@ ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void) return NULL; } -void OCIOImpl::setCurrentConfig(const ConstConfigRcPtr *config) +void OCIOImpl::setCurrentConfig(const OCIO_ConstConfigRcPtr *config) { try { - SetCurrentConfig(*config); + SetCurrentConfig(*(ConstConfigRcPtr *) config); } catch (Exception &exception) { OCIO_reportException(exception); } } -ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void) +OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void) { ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr); @@ -98,7 +99,7 @@ ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void) *config = Config::CreateFromEnv(); if (*config) - return config; + return (OCIO_ConstConfigRcPtr *) config; } catch (Exception &exception) { OCIO_reportException(exception); @@ -110,7 +111,7 @@ ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void) } -ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename) +OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename) { ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr); @@ -118,7 +119,7 @@ ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename) *config = Config::CreateFromFile(filename); if (*config) - return config; + return (OCIO_ConstConfigRcPtr *) config; } catch (Exception &exception) { OCIO_reportException(exception); @@ -129,15 +130,15 @@ ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename) return NULL; } -void OCIOImpl::configRelease(ConstConfigRcPtr *config) +void OCIOImpl::configRelease(OCIO_ConstConfigRcPtr *config) { - MEM_DELETE(config, ConstConfigRcPtr); + MEM_DELETE((ConstConfigRcPtr *) config, ConstConfigRcPtr); } -int OCIOImpl::configGetNumColorSpaces(ConstConfigRcPtr *config) +int OCIOImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config) { try { - return (*config)->getNumColorSpaces(); + return (*(ConstConfigRcPtr *) config)->getNumColorSpaces(); } catch (Exception &exception) { OCIO_reportException(exception); @@ -146,10 +147,10 @@ int OCIOImpl::configGetNumColorSpaces(ConstConfigRcPtr *config) return 0; } -const char *OCIOImpl::configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index) +const char *OCIOImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index) { try { - return (*config)->getColorSpaceNameByIndex(index); + return (*(ConstConfigRcPtr *) config)->getColorSpaceNameByIndex(index); } catch (Exception &exception) { OCIO_reportException(exception); @@ -158,15 +159,15 @@ const char *OCIOImpl::configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, i return NULL; } -ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(ConstConfigRcPtr *config, const char *name) +OCIO_ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) { ConstColorSpaceRcPtr *cs = MEM_NEW(ConstColorSpaceRcPtr); try { - *cs = (*config)->getColorSpace(name); + *cs = (*(ConstConfigRcPtr *) config)->getColorSpace(name); if (*cs) - return cs; + return (OCIO_ConstColorSpaceRcPtr *) cs; } catch (Exception &exception) { OCIO_reportException(exception); @@ -177,10 +178,10 @@ ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(ConstConfigRcPtr *config, co return NULL; } -int OCIOImpl::configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) +int OCIOImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) { try { - return (*config)->getIndexForColorSpace(name); + return (*(ConstConfigRcPtr *) config)->getIndexForColorSpace(name); } catch (Exception &exception) { OCIO_reportException(exception); @@ -189,10 +190,10 @@ int OCIOImpl::configGetIndexForColorSpace(ConstConfigRcPtr *config, const char * return -1; } -const char *OCIOImpl::configGetDefaultDisplay(ConstConfigRcPtr *config) +const char *OCIOImpl::configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config) { try { - return (*config)->getDefaultDisplay(); + return (*(ConstConfigRcPtr *) config)->getDefaultDisplay(); } catch (Exception &exception) { OCIO_reportException(exception); @@ -201,10 +202,10 @@ const char *OCIOImpl::configGetDefaultDisplay(ConstConfigRcPtr *config) return NULL; } -int OCIOImpl::configGetNumDisplays(ConstConfigRcPtr* config) +int OCIOImpl::configGetNumDisplays(OCIO_ConstConfigRcPtr* config) { try { - return (*config)->getNumDisplays(); + return (*(ConstConfigRcPtr *) config)->getNumDisplays(); } catch (Exception &exception) { OCIO_reportException(exception); @@ -213,10 +214,10 @@ int OCIOImpl::configGetNumDisplays(ConstConfigRcPtr* config) return 0; } -const char *OCIOImpl::configGetDisplay(ConstConfigRcPtr *config, int index) +const char *OCIOImpl::configGetDisplay(OCIO_ConstConfigRcPtr *config, int index) { try { - return (*config)->getDisplay(index); + return (*(ConstConfigRcPtr *) config)->getDisplay(index); } catch (Exception &exception) { OCIO_reportException(exception); @@ -225,10 +226,10 @@ const char *OCIOImpl::configGetDisplay(ConstConfigRcPtr *config, int index) return NULL; } -const char *OCIOImpl::configGetDefaultView(ConstConfigRcPtr *config, const char *display) +const char *OCIOImpl::configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display) { try { - return (*config)->getDefaultView(display); + return (*(ConstConfigRcPtr *) config)->getDefaultView(display); } catch (Exception &exception) { OCIO_reportException(exception); @@ -237,10 +238,10 @@ const char *OCIOImpl::configGetDefaultView(ConstConfigRcPtr *config, const char return NULL; } -int OCIOImpl::configGetNumViews(ConstConfigRcPtr *config, const char *display) +int OCIOImpl::configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display) { try { - return (*config)->getNumViews(display); + return (*(ConstConfigRcPtr *) config)->getNumViews(display); } catch (Exception &exception) { OCIO_reportException(exception); @@ -249,10 +250,10 @@ int OCIOImpl::configGetNumViews(ConstConfigRcPtr *config, const char *display) return 0; } -const char *OCIOImpl::configGetView(ConstConfigRcPtr *config, const char *display, int index) +const char *OCIOImpl::configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index) { try { - return (*config)->getView(display, index); + return (*(ConstConfigRcPtr *) config)->getView(display, index); } catch (Exception &exception) { OCIO_reportException(exception); @@ -261,10 +262,10 @@ const char *OCIOImpl::configGetView(ConstConfigRcPtr *config, const char *displa return NULL; } -const char *OCIOImpl::configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view) +const char *OCIOImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view) { try { - return (*config)->getDisplayColorSpaceName(display, view); + return (*(ConstConfigRcPtr *) config)->getDisplayColorSpaceName(display, view); } catch (Exception &exception) { OCIO_reportException(exception); @@ -273,8 +274,9 @@ const char *OCIOImpl::configGetDisplayColorSpaceName(ConstConfigRcPtr *config, c return NULL; } -int OCIOImpl::colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) +int OCIOImpl::colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs_) { + ConstColorSpaceRcPtr *cs = (ConstColorSpaceRcPtr *) cs_; const char *family = (*cs)->getFamily(); if (!strcmp(family, "rrt") || !strcmp(family, "display")) { @@ -297,25 +299,25 @@ int OCIOImpl::colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) return true; } -int OCIOImpl::colorSpaceIsData(ConstColorSpaceRcPtr *cs) +int OCIOImpl::colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs) { - return ((*cs)->isData()); + return (*(ConstColorSpaceRcPtr *) cs)->isData(); } -void OCIOImpl::colorSpaceRelease(ConstColorSpaceRcPtr *cs) +void OCIOImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs) { - MEM_DELETE(cs, ConstColorSpaceRcPtr); + MEM_DELETE((ConstColorSpaceRcPtr *) cs, ConstColorSpaceRcPtr); } -ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName) +OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName) { ConstProcessorRcPtr *p = MEM_NEW(ConstProcessorRcPtr); try { - *p = (*config)->getProcessor(srcName, dstName); + *p = (*(ConstConfigRcPtr *) config)->getProcessor(srcName, dstName); if (*p) - return p; + return (OCIO_ConstProcessorRcPtr *) p; } catch (Exception &exception) { OCIO_reportException(exception); @@ -326,15 +328,15 @@ ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(ConstConfigRcPtr *con return 0; } -ConstProcessorRcPtr *OCIOImpl::configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform) +OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessor(OCIO_ConstConfigRcPtr *config, OCIO_ConstTransformRcPtr *transform) { ConstProcessorRcPtr *p = MEM_NEW(ConstProcessorRcPtr); try { - *p = (*config)->getProcessor(*transform); + *p = (*(ConstConfigRcPtr *) config)->getProcessor(*(ConstTransformRcPtr *) transform); if (*p) - return p; + return (OCIO_ConstProcessorRcPtr *) p; } catch (Exception &exception) { OCIO_reportException(exception); @@ -345,19 +347,20 @@ ConstProcessorRcPtr *OCIOImpl::configGetProcessor(ConstConfigRcPtr *config, Cons return NULL; } -void OCIOImpl::processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) +void OCIOImpl::processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) { try { - (*processor)->apply(*img); + (*(ConstProcessorRcPtr *) processor)->apply(*(PackedImageDesc *) img); } catch (Exception &exception) { OCIO_reportException(exception); } } -void OCIOImpl::processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img) +void OCIOImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img_) { try { + PackedImageDesc *img = (PackedImageDesc *) img_; int channels = img->getNumChannels(); if (channels == 4) { @@ -375,7 +378,7 @@ void OCIOImpl::processorApply_predivide(ConstProcessorRcPtr *processor, PackedIm } } else { - (*processor)->apply(*img); + (*(ConstProcessorRcPtr *) processor)->apply(*img); } } catch (Exception &exception) { @@ -383,20 +386,20 @@ void OCIOImpl::processorApply_predivide(ConstProcessorRcPtr *processor, PackedIm } } -void OCIOImpl::processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) +void OCIOImpl::processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel) { - (*processor)->applyRGB(pixel); + (*(ConstProcessorRcPtr *) processor)->applyRGB(pixel); } -void OCIOImpl::processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) +void OCIOImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel) { - (*processor)->applyRGBA(pixel); + (*(ConstProcessorRcPtr *) processor)->applyRGBA(pixel); } -void OCIOImpl::processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel) +void OCIOImpl::processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel) { if (pixel[3] == 1.0f || pixel[3] == 0.0f) { - (*processor)->applyRGBA(pixel); + (*(ConstProcessorRcPtr *) processor)->applyRGBA(pixel); } else { float alpha, inv_alpha; @@ -408,7 +411,7 @@ void OCIOImpl::processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, floa pixel[1] *= inv_alpha; pixel[2] *= inv_alpha; - (*processor)->applyRGBA(pixel); + (*(ConstProcessorRcPtr *) processor)->applyRGBA(pixel); pixel[0] *= alpha; pixel[1] *= alpha; @@ -416,74 +419,74 @@ void OCIOImpl::processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, floa } } -void OCIOImpl::processorRelease(ConstProcessorRcPtr *p) +void OCIOImpl::processorRelease(OCIO_ConstProcessorRcPtr *p) { - p->~ConstProcessorRcPtr(); + p->~OCIO_ConstProcessorRcPtr(); MEM_freeN(p); } -const char *OCIOImpl::colorSpaceGetName(ConstColorSpaceRcPtr *cs) +const char *OCIOImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs) { - return (*cs)->getName(); + return (*(ConstColorSpaceRcPtr *) cs)->getName(); } -const char *OCIOImpl::colorSpaceGetDescription(ConstColorSpaceRcPtr *cs) +const char *OCIOImpl::colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs) { - return (*cs)->getDescription(); + return (*(ConstColorSpaceRcPtr *) cs)->getDescription(); } -const char *OCIOImpl::colorSpaceGetFamily(ConstColorSpaceRcPtr *cs) +const char *OCIOImpl::colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs) { - return (*cs)->getFamily(); + return (*(ConstColorSpaceRcPtr *)cs)->getFamily(); } -DisplayTransformRcPtr *OCIOImpl::createDisplayTransform(void) +OCIO_DisplayTransformRcPtr *OCIOImpl::createDisplayTransform(void) { DisplayTransformRcPtr *dt = MEM_NEW(DisplayTransformRcPtr); *dt = DisplayTransform::Create(); - return dt; + return (OCIO_DisplayTransformRcPtr *) dt; } -void OCIOImpl::displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name) +void OCIOImpl::displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr *dt, const char *name) { - (*dt)->setInputColorSpaceName(name); + (*(DisplayTransformRcPtr *) dt)->setInputColorSpaceName(name); } -void OCIOImpl::displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name) +void OCIOImpl::displayTransformSetDisplay(OCIO_DisplayTransformRcPtr *dt, const char *name) { - (*dt)->setDisplay(name); + (*(DisplayTransformRcPtr *) dt)->setDisplay(name); } -void OCIOImpl::displayTransformSetView(DisplayTransformRcPtr *dt, const char *name) +void OCIOImpl::displayTransformSetView(OCIO_DisplayTransformRcPtr *dt, const char *name) { - (*dt)->setView(name); + (*(DisplayTransformRcPtr *) dt)->setView(name); } -void OCIOImpl::displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t) +void OCIOImpl::displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *t) { - (*dt)->setDisplayCC(*t); + (*(DisplayTransformRcPtr *) dt)->setDisplayCC(* (ConstTransformRcPtr *) t); } -void OCIOImpl::displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t) +void OCIOImpl::displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *t) { - (*dt)->setLinearCC(*t); + (*(DisplayTransformRcPtr *) dt)->setLinearCC(*(ConstTransformRcPtr *) t); } -void OCIOImpl::displayTransformRelease(DisplayTransformRcPtr *dt) +void OCIOImpl::displayTransformRelease(OCIO_DisplayTransformRcPtr *dt) { - MEM_DELETE(dt, DisplayTransformRcPtr); + MEM_DELETE((DisplayTransformRcPtr *) dt, DisplayTransformRcPtr); } -PackedImageDesc *OCIOImpl::createPackedImageDesc(float *data, long width, long height, long numChannels, +OCIO_PackedImageDesc *OCIOImpl::createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes) { try { void *mem = MEM_mallocN(sizeof(PackedImageDesc), __func__); PackedImageDesc *id = new(mem) PackedImageDesc(data, width, height, numChannels, chanStrideBytes, xStrideBytes, yStrideBytes); - return id; + return (OCIO_PackedImageDesc *) id; } catch (Exception &exception) { OCIO_reportException(exception); @@ -492,47 +495,47 @@ PackedImageDesc *OCIOImpl::createPackedImageDesc(float *data, long width, long h return NULL; } -void OCIOImpl::packedImageDescRelease(PackedImageDesc* id) +void OCIOImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc* id) { - MEM_DELETE(id, PackedImageDesc); + MEM_DELETE((PackedImageDesc *) id, PackedImageDesc); } -ExponentTransformRcPtr *OCIOImpl::createExponentTransform(void) +OCIO_ExponentTransformRcPtr *OCIOImpl::createExponentTransform(void) { ExponentTransformRcPtr *et = MEM_NEW(ExponentTransformRcPtr); *et = ExponentTransform::Create(); - return et; + return (OCIO_ExponentTransformRcPtr *) et; } -void OCIOImpl::exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent) +void OCIOImpl::exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent) { - (*et)->setValue(exponent); + (*(ExponentTransformRcPtr *) et)->setValue(exponent); } -void OCIOImpl::exponentTransformRelease(ExponentTransformRcPtr *et) +void OCIOImpl::exponentTransformRelease(OCIO_ExponentTransformRcPtr *et) { - MEM_DELETE(et, ExponentTransformRcPtr); + MEM_DELETE((ExponentTransformRcPtr *) et, ExponentTransformRcPtr); } -MatrixTransformRcPtr *OCIOImpl::createMatrixTransform(void) +OCIO_MatrixTransformRcPtr *OCIOImpl::createMatrixTransform(void) { MatrixTransformRcPtr *mt = MEM_NEW(MatrixTransformRcPtr); *mt = MatrixTransform::Create(); - return mt; + return (OCIO_MatrixTransformRcPtr *) mt; } -void OCIOImpl::matrixTransformSetValue(MatrixTransformRcPtr *mt, const float *m44, const float *offset4) +void OCIOImpl::matrixTransformSetValue(OCIO_MatrixTransformRcPtr *mt, const float *m44, const float *offset4) { - (*mt)->setValue(m44, offset4); + (*(MatrixTransformRcPtr *) mt)->setValue(m44, offset4); } -void OCIOImpl::matrixTransformRelease(MatrixTransformRcPtr *mt) +void OCIOImpl::matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt) { - MEM_DELETE(mt, MatrixTransformRcPtr); + MEM_DELETE((MatrixTransformRcPtr *) mt, MatrixTransformRcPtr); } void OCIOImpl::matrixTransformScale(float * m44, float * offset4, const float *scale4f) diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h index e05b35648b9..64cf5ec3322 100644 --- a/intern/opencolorio/ocio_impl.h +++ b/intern/opencolorio/ocio_impl.h @@ -32,67 +32,67 @@ class IOCIOImpl { public: virtual ~IOCIOImpl() {}; - virtual ConstConfigRcPtr *getCurrentConfig(void) = 0; - virtual void setCurrentConfig(const ConstConfigRcPtr *config) = 0; + virtual OCIO_ConstConfigRcPtr *getCurrentConfig(void) = 0; + virtual void setCurrentConfig(const OCIO_ConstConfigRcPtr *config) = 0; - virtual ConstConfigRcPtr *configCreateFromEnv(void) = 0; - virtual ConstConfigRcPtr *configCreateFromFile(const char* filename) = 0; + virtual OCIO_ConstConfigRcPtr *configCreateFromEnv(void) = 0; + virtual OCIO_ConstConfigRcPtr *configCreateFromFile(const char* filename) = 0; - virtual void configRelease(ConstConfigRcPtr *config) = 0; + virtual void configRelease(OCIO_ConstConfigRcPtr *config) = 0; - virtual int configGetNumColorSpaces(ConstConfigRcPtr *config) = 0; - virtual const char *configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index) = 0; - virtual ConstColorSpaceRcPtr *configGetColorSpace(ConstConfigRcPtr *config, const char *name) = 0; - virtual int configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name) = 0; + virtual int configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config) = 0; + virtual const char *configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index) = 0; + virtual OCIO_ConstColorSpaceRcPtr *configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) = 0; + virtual int configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) = 0; - virtual int colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs) = 0; - virtual int colorSpaceIsData(ConstColorSpaceRcPtr *cs) = 0; + virtual int colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs) = 0; + virtual int colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs) = 0; - virtual void colorSpaceRelease(ConstColorSpaceRcPtr *cs) = 0; + virtual void colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs) = 0; - virtual const char *configGetDefaultDisplay(ConstConfigRcPtr *config) = 0; - virtual int configGetNumDisplays(ConstConfigRcPtr *config) = 0; - virtual const char *configGetDisplay(ConstConfigRcPtr *config, int index) = 0; - virtual const char *configGetDefaultView(ConstConfigRcPtr *config, const char *display) = 0; - virtual int configGetNumViews(ConstConfigRcPtr *config, const char *display) = 0; - virtual const char *configGetView(ConstConfigRcPtr *config, const char *display, int index) = 0; - virtual const char *configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view) = 0; + virtual const char *configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config) = 0; + virtual int configGetNumDisplays(OCIO_ConstConfigRcPtr *config) = 0; + virtual const char *configGetDisplay(OCIO_ConstConfigRcPtr *config, int index) = 0; + virtual const char *configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display) = 0; + virtual int configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display) = 0; + virtual const char *configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index) = 0; + virtual const char *configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view) = 0; - virtual ConstProcessorRcPtr *configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName) = 0; - virtual ConstProcessorRcPtr *configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform) = 0; + virtual OCIO_ConstProcessorRcPtr *configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName) = 0; + virtual OCIO_ConstProcessorRcPtr *configGetProcessor(OCIO_ConstConfigRcPtr *config, OCIO_ConstTransformRcPtr *transform) = 0; - virtual void processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img) = 0; - virtual void processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img) = 0; - virtual void processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel) = 0; - virtual void processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel) = 0; - virtual void processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel) = 0; + virtual void processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) = 0; + virtual void processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) = 0; + virtual void processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel) = 0; + virtual void processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel) = 0; + virtual void processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel) = 0; - virtual void processorRelease(ConstProcessorRcPtr *p) = 0; + virtual void processorRelease(OCIO_ConstProcessorRcPtr *p) = 0; - virtual const char *colorSpaceGetName(ConstColorSpaceRcPtr *cs) = 0; - virtual const char *colorSpaceGetDescription(ConstColorSpaceRcPtr *cs) = 0; - virtual const char *colorSpaceGetFamily(ConstColorSpaceRcPtr *cs) = 0; + virtual const char *colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs) = 0; + virtual const char *colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs) = 0; + virtual const char *colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs) = 0; - virtual DisplayTransformRcPtr *createDisplayTransform(void) = 0; - virtual void displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name) = 0; - virtual void displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name) = 0; - virtual void displayTransformSetView(DisplayTransformRcPtr *dt, const char *name) = 0; - virtual void displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et) = 0; - virtual void displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et) = 0; - virtual void displayTransformRelease(DisplayTransformRcPtr *dt) = 0; + virtual OCIO_DisplayTransformRcPtr *createDisplayTransform(void) = 0; + virtual void displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr *dt, const char *name) = 0; + virtual void displayTransformSetDisplay(OCIO_DisplayTransformRcPtr *dt, const char *name) = 0; + virtual void displayTransformSetView(OCIO_DisplayTransformRcPtr *dt, const char *name) = 0; + virtual void displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *et) = 0; + virtual void displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *et) = 0; + virtual void displayTransformRelease(OCIO_DisplayTransformRcPtr *dt) = 0; - virtual PackedImageDesc *createPackedImageDesc(float *data, long width, long height, long numChannels, + virtual OCIO_PackedImageDesc *createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes) = 0; - virtual void packedImageDescRelease(PackedImageDesc *p) = 0; + virtual void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *p) = 0; - virtual ExponentTransformRcPtr *createExponentTransform(void) = 0; - virtual void exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent) = 0; - virtual void exponentTransformRelease(ExponentTransformRcPtr *et) = 0; + virtual OCIO_ExponentTransformRcPtr *createExponentTransform(void) = 0; + virtual void exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent) = 0; + virtual void exponentTransformRelease(OCIO_ExponentTransformRcPtr *et) = 0; - virtual MatrixTransformRcPtr *createMatrixTransform(void) = 0; - virtual void matrixTransformSetValue(MatrixTransformRcPtr *et, const float *m44, const float *offset4) = 0; - virtual void matrixTransformRelease(MatrixTransformRcPtr *mt) = 0; + virtual OCIO_MatrixTransformRcPtr *createMatrixTransform(void) = 0; + virtual void matrixTransformSetValue(OCIO_MatrixTransformRcPtr *et, const float *m44, const float *offset4) = 0; + virtual void matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt) = 0; virtual void matrixTransformScale(float * m44, float * offset4, const float * scale4) = 0; }; @@ -101,67 +101,67 @@ class FallbackImpl : public IOCIOImpl { public: FallbackImpl() {}; - ConstConfigRcPtr *getCurrentConfig(void); - void setCurrentConfig(const ConstConfigRcPtr *config); + OCIO_ConstConfigRcPtr *getCurrentConfig(void); + void setCurrentConfig(const OCIO_ConstConfigRcPtr *config); - ConstConfigRcPtr *configCreateFromEnv(void); - ConstConfigRcPtr *configCreateFromFile(const char* filename); + OCIO_ConstConfigRcPtr *configCreateFromEnv(void); + OCIO_ConstConfigRcPtr *configCreateFromFile(const char* filename); - void configRelease(ConstConfigRcPtr *config); + void configRelease(OCIO_ConstConfigRcPtr *config); - int configGetNumColorSpaces(ConstConfigRcPtr *config); - const char *configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index); - ConstColorSpaceRcPtr *configGetColorSpace(ConstConfigRcPtr *config, const char *name); - int configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name); + int configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config); + const char *configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index); + OCIO_ConstColorSpaceRcPtr *configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name); + int configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name); - int colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs); - int colorSpaceIsData(ConstColorSpaceRcPtr *cs); + int colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs); + int colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs); - void colorSpaceRelease(ConstColorSpaceRcPtr *cs); + void colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs); - const char *configGetDefaultDisplay(ConstConfigRcPtr *config); - int configGetNumDisplays(ConstConfigRcPtr *config); - const char *configGetDisplay(ConstConfigRcPtr *config, int index); - const char *configGetDefaultView(ConstConfigRcPtr *config, const char *display); - int configGetNumViews(ConstConfigRcPtr *config, const char *display); - const char *configGetView(ConstConfigRcPtr *config, const char *display, int index); - const char *configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view); + const char *configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config); + int configGetNumDisplays(OCIO_ConstConfigRcPtr *config); + const char *configGetDisplay(OCIO_ConstConfigRcPtr *config, int index); + const char *configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display); + int configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display); + const char *configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index); + const char *configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view); - ConstProcessorRcPtr *configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName); - ConstProcessorRcPtr *configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform); + OCIO_ConstProcessorRcPtr *configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName); + OCIO_ConstProcessorRcPtr *configGetProcessor(OCIO_ConstConfigRcPtr *config, OCIO_ConstTransformRcPtr *transform); - void processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img); - void processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img); - void processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel); - void processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel); - void processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel); + void processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img); + void processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img); + void processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel); + void processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel); + void processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel); - void processorRelease(ConstProcessorRcPtr *p); + void processorRelease(OCIO_ConstProcessorRcPtr *p); - const char *colorSpaceGetName(ConstColorSpaceRcPtr *cs); - const char *colorSpaceGetDescription(ConstColorSpaceRcPtr *cs); - const char *colorSpaceGetFamily(ConstColorSpaceRcPtr *cs); + const char *colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs); + const char *colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs); + const char *colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs); - DisplayTransformRcPtr *createDisplayTransform(void); - void displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name); - void displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name); - void displayTransformSetView(DisplayTransformRcPtr *dt, const char *name); - void displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et); - void displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et); - void displayTransformRelease(DisplayTransformRcPtr *dt); + OCIO_DisplayTransformRcPtr *createDisplayTransform(void); + void displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetDisplay(OCIO_DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetView(OCIO_DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *et); + void displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *et); + void displayTransformRelease(OCIO_DisplayTransformRcPtr *dt); - PackedImageDesc *createPackedImageDesc(float *data, long width, long height, long numChannels, + OCIO_PackedImageDesc *createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes); - void packedImageDescRelease(PackedImageDesc *p); + void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *p); - ExponentTransformRcPtr *createExponentTransform(void); - void exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent); - void exponentTransformRelease(ExponentTransformRcPtr *et); + OCIO_ExponentTransformRcPtr *createExponentTransform(void); + void exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent); + void exponentTransformRelease(OCIO_ExponentTransformRcPtr *et); - MatrixTransformRcPtr *createMatrixTransform(void); - void matrixTransformSetValue(MatrixTransformRcPtr *et, const float *m44, const float *offset4); - void matrixTransformRelease(MatrixTransformRcPtr *mt); + OCIO_MatrixTransformRcPtr *createMatrixTransform(void); + void matrixTransformSetValue(OCIO_MatrixTransformRcPtr *et, const float *m44, const float *offset4); + void matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt); void matrixTransformScale(float * m44, float * offset4, const float * scale4); }; @@ -171,67 +171,67 @@ class OCIOImpl : public IOCIOImpl { public: OCIOImpl() {}; - ConstConfigRcPtr *getCurrentConfig(void); - void setCurrentConfig(const ConstConfigRcPtr *config); + OCIO_ConstConfigRcPtr *getCurrentConfig(void); + void setCurrentConfig(const OCIO_ConstConfigRcPtr *config); - ConstConfigRcPtr *configCreateFromEnv(void); - ConstConfigRcPtr *configCreateFromFile(const char* filename); + OCIO_ConstConfigRcPtr *configCreateFromEnv(void); + OCIO_ConstConfigRcPtr *configCreateFromFile(const char* filename); - void configRelease(ConstConfigRcPtr *config); + void configRelease(OCIO_ConstConfigRcPtr *config); - int configGetNumColorSpaces(ConstConfigRcPtr *config); - const char *configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index); - ConstColorSpaceRcPtr *configGetColorSpace(ConstConfigRcPtr *config, const char *name); - int configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name); + int configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config); + const char *configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index); + OCIO_ConstColorSpaceRcPtr *configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name); + int configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name); - int colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs); - int colorSpaceIsData(ConstColorSpaceRcPtr *cs); + int colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs); + int colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs); - void colorSpaceRelease(ConstColorSpaceRcPtr *cs); + void colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs); - const char *configGetDefaultDisplay(ConstConfigRcPtr *config); - int configGetNumDisplays(ConstConfigRcPtr *config); - const char *configGetDisplay(ConstConfigRcPtr *config, int index); - const char *configGetDefaultView(ConstConfigRcPtr *config, const char *display); - int configGetNumViews(ConstConfigRcPtr *config, const char *display); - const char *configGetView(ConstConfigRcPtr *config, const char *display, int index); - const char *configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view); + const char *configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config); + int configGetNumDisplays(OCIO_ConstConfigRcPtr *config); + const char *configGetDisplay(OCIO_ConstConfigRcPtr *config, int index); + const char *configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display); + int configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display); + const char *configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index); + const char *configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view); - ConstProcessorRcPtr *configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName); - ConstProcessorRcPtr *configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform); + OCIO_ConstProcessorRcPtr *configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName); + OCIO_ConstProcessorRcPtr *configGetProcessor(OCIO_ConstConfigRcPtr *config, OCIO_ConstTransformRcPtr *transform); - void processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img); - void processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img); - void processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel); - void processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel); - void processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel); + void processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img); + void processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img); + void processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel); + void processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel); + void processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel); - void processorRelease(ConstProcessorRcPtr *p); + void processorRelease(OCIO_ConstProcessorRcPtr *p); - const char *colorSpaceGetName(ConstColorSpaceRcPtr *cs); - const char *colorSpaceGetDescription(ConstColorSpaceRcPtr *cs); - const char *colorSpaceGetFamily(ConstColorSpaceRcPtr *cs); + const char *colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs); + const char *colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs); + const char *colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs); - DisplayTransformRcPtr *createDisplayTransform(void); - void displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name); - void displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name); - void displayTransformSetView(DisplayTransformRcPtr *dt, const char *name); - void displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et); - void displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et); - void displayTransformRelease(DisplayTransformRcPtr *dt); + OCIO_DisplayTransformRcPtr *createDisplayTransform(void); + void displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetDisplay(OCIO_DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetView(OCIO_DisplayTransformRcPtr *dt, const char *name); + void displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *et); + void displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *et); + void displayTransformRelease(OCIO_DisplayTransformRcPtr *dt); - PackedImageDesc *createPackedImageDesc(float *data, long width, long height, long numChannels, + OCIO_PackedImageDesc *createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes); - void packedImageDescRelease(PackedImageDesc *p); + void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *p); - ExponentTransformRcPtr *createExponentTransform(void); - void exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent); - void exponentTransformRelease(ExponentTransformRcPtr *et); + OCIO_ExponentTransformRcPtr *createExponentTransform(void); + void exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent); + void exponentTransformRelease(OCIO_ExponentTransformRcPtr *et); - MatrixTransformRcPtr *createMatrixTransform(void); - void matrixTransformSetValue(MatrixTransformRcPtr *et, const float *m44, const float *offset4); - void matrixTransformRelease(MatrixTransformRcPtr *mt); + OCIO_MatrixTransformRcPtr *createMatrixTransform(void); + void matrixTransformSetValue(OCIO_MatrixTransformRcPtr *et, const float *m44, const float *offset4); + void matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt); void matrixTransformScale(float * m44, float * offset4, const float * scale4); }; diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h index 35a6ea9b207..ba9e20ac411 100644 --- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h +++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h @@ -35,7 +35,7 @@ #define BCM_CONFIG_FILE "config.ocio" -struct ConstProcessorRcPtr; +struct OCIO_ConstProcessorRcPtr; struct ImBuf; typedef struct ColorSpace { @@ -44,8 +44,8 @@ typedef struct ColorSpace { char name[64]; char description[64]; - struct ConstProcessorRcPtr *to_scene_linear; - struct ConstProcessorRcPtr *from_scene_linear; + struct OCIO_ConstProcessorRcPtr *to_scene_linear; + struct OCIO_ConstProcessorRcPtr *from_scene_linear; int is_invertible; int is_data; @@ -57,8 +57,8 @@ typedef struct ColorManagedDisplay { char name[64]; ListBase views; - struct ConstProcessorRcPtr *to_scene_linear; - struct ConstProcessorRcPtr *from_scene_linear; + struct OCIO_ConstProcessorRcPtr *to_scene_linear; + struct OCIO_ConstProcessorRcPtr *from_scene_linear; } ColorManagedDisplay; typedef struct ColorManagedView { diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 50000b9eeea..c7bdd532bb9 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -96,7 +96,7 @@ static int global_tot_view = 0; static pthread_mutex_t processor_lock = BLI_MUTEX_INITIALIZER; typedef struct ColormanageProcessor { - ConstProcessorRcPtr *processor; + OCIO_ConstProcessorRcPtr *processor; CurveMapping *curve_mapping; } ColormanageProcessor; @@ -419,9 +419,9 @@ static void colormanage_cache_handle_release(void *cache_handle) /*********************** Initialization / De-initialization *************************/ -static void colormanage_role_color_space_name_get(ConstConfigRcPtr *config, char *colorspace_name, const char *role, const char *backup_role) +static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config, char *colorspace_name, const char *role, const char *backup_role) { - ConstColorSpaceRcPtr *ociocs; + OCIO_ConstColorSpaceRcPtr *ociocs; ociocs = OCIO_configGetColorSpace(config, role); @@ -440,7 +440,7 @@ static void colormanage_role_color_space_name_get(ConstConfigRcPtr *config, char } } -static void colormanage_load_config(ConstConfigRcPtr *config) +static void colormanage_load_config(OCIO_ConstConfigRcPtr *config) { int tot_colorspace, tot_display, tot_display_view, index, viewindex, viewindex2; const char *name; @@ -456,7 +456,7 @@ static void colormanage_load_config(ConstConfigRcPtr *config) /* load colorspaces */ tot_colorspace = OCIO_configGetNumColorSpaces(config); for (index = 0 ; index < tot_colorspace; index++) { - ConstColorSpaceRcPtr *ocio_colorspace; + OCIO_ConstColorSpaceRcPtr *ocio_colorspace; const char *description; int is_invertible, is_data; @@ -521,10 +521,10 @@ static void colormanage_free_config(void) /* free precomputer processors */ if (colorspace->to_scene_linear) - OCIO_processorRelease((ConstProcessorRcPtr *) colorspace->to_scene_linear); + OCIO_processorRelease((OCIO_ConstProcessorRcPtr *) colorspace->to_scene_linear); if (colorspace->from_scene_linear) - OCIO_processorRelease((ConstProcessorRcPtr *) colorspace->from_scene_linear); + OCIO_processorRelease((OCIO_ConstProcessorRcPtr *) colorspace->from_scene_linear); /* free color space itself */ MEM_freeN(colorspace); @@ -539,10 +539,10 @@ static void colormanage_free_config(void) /* free precomputer processors */ if (display->to_scene_linear) - OCIO_processorRelease((ConstProcessorRcPtr *) display->to_scene_linear); + OCIO_processorRelease((OCIO_ConstProcessorRcPtr *) display->to_scene_linear); if (display->from_scene_linear) - OCIO_processorRelease((ConstProcessorRcPtr *) display->from_scene_linear); + OCIO_processorRelease((OCIO_ConstProcessorRcPtr *) display->from_scene_linear); /* free list of views */ BLI_freelistN(&display->views); @@ -562,7 +562,7 @@ void colormanagement_init(void) const char *ocio_env; const char *configdir; char configfile[FILE_MAX]; - ConstConfigRcPtr *config = NULL; + OCIO_ConstConfigRcPtr *config = NULL; OCIO_init(); @@ -649,7 +649,7 @@ static void display_transform_get_from_ctx(const bContext *C, ColorManagedViewSe static const char *display_transform_get_colorspace_name(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings) { - ConstConfigRcPtr *config = OCIO_getCurrentConfig(); + OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig(); const char *display = display_settings->display_device; const char *view = view_settings->view_transform; @@ -673,12 +673,12 @@ static ColorSpace *display_transform_get_colorspace(const ColorManagedViewSettin return NULL; } -static ConstProcessorRcPtr *create_display_buffer_processor(const char *view_transform, const char *display, +static OCIO_ConstProcessorRcPtr *create_display_buffer_processor(const char *view_transform, const char *display, float exposure, float gamma) { - ConstConfigRcPtr *config = OCIO_getCurrentConfig(); - DisplayTransformRcPtr *dt; - ConstProcessorRcPtr *processor; + OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig(); + OCIO_DisplayTransformRcPtr *dt; + OCIO_ConstProcessorRcPtr *processor; dt = OCIO_createDisplayTransform(); @@ -689,7 +689,7 @@ static ConstProcessorRcPtr *create_display_buffer_processor(const char *view_tra /* fstop exposure control */ if (exposure != 0.0f) { - MatrixTransformRcPtr *mt; + OCIO_MatrixTransformRcPtr *mt; float gain = powf(2.0f, exposure); const float scale4f[] = {gain, gain, gain, gain}; float m44[16], offset4[4]; @@ -697,25 +697,25 @@ static ConstProcessorRcPtr *create_display_buffer_processor(const char *view_tra OCIO_matrixTransformScale(m44, offset4, scale4f); mt = OCIO_createMatrixTransform(); OCIO_matrixTransformSetValue(mt, m44, offset4); - OCIO_displayTransformSetLinearCC(dt, (ConstTransformRcPtr *) mt); + OCIO_displayTransformSetLinearCC(dt, (OCIO_ConstTransformRcPtr *) mt); OCIO_matrixTransformRelease(mt); } /* post-display gamma transform */ if (gamma != 1.0f) { - ExponentTransformRcPtr *et; + OCIO_ExponentTransformRcPtr *et; float exponent = 1.0f / MAX2(FLT_EPSILON, gamma); const float exponent4f[] = {exponent, exponent, exponent, exponent}; et = OCIO_createExponentTransform(); OCIO_exponentTransformSetValue(et, exponent4f); - OCIO_displayTransformSetDisplayCC(dt, (ConstTransformRcPtr *) et); + OCIO_displayTransformSetDisplayCC(dt, (OCIO_ConstTransformRcPtr *) et); OCIO_exponentTransformRelease(et); } - processor = OCIO_configGetProcessor(config, (ConstTransformRcPtr *) dt); + processor = OCIO_configGetProcessor(config, (OCIO_ConstTransformRcPtr *) dt); OCIO_displayTransformRelease(dt); OCIO_configRelease(config); @@ -723,11 +723,11 @@ static ConstProcessorRcPtr *create_display_buffer_processor(const char *view_tra return processor; } -static ConstProcessorRcPtr *create_colorspace_transform_processor(const char *from_colorspace, +static OCIO_ConstProcessorRcPtr *create_colorspace_transform_processor(const char *from_colorspace, const char *to_colorspace) { - ConstConfigRcPtr *config = OCIO_getCurrentConfig(); - ConstProcessorRcPtr *processor; + OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig(); + OCIO_ConstProcessorRcPtr *processor; processor = OCIO_configGetProcessorWithNames(config, from_colorspace, to_colorspace); @@ -736,49 +736,49 @@ static ConstProcessorRcPtr *create_colorspace_transform_processor(const char *fr return processor; } -static ConstProcessorRcPtr *colorspace_to_scene_linear_processor(ColorSpace *colorspace) +static OCIO_ConstProcessorRcPtr *colorspace_to_scene_linear_processor(ColorSpace *colorspace) { if (colorspace->to_scene_linear == NULL) { BLI_mutex_lock(&processor_lock); if (colorspace->to_scene_linear == NULL) { - ConstProcessorRcPtr *to_scene_linear; + OCIO_ConstProcessorRcPtr *to_scene_linear; to_scene_linear = create_colorspace_transform_processor(colorspace->name, global_role_scene_linear); - colorspace->to_scene_linear = (struct ConstProcessorRcPtr *) to_scene_linear; + colorspace->to_scene_linear = (struct OCIO_ConstProcessorRcPtr *) to_scene_linear; } BLI_mutex_unlock(&processor_lock); } - return (ConstProcessorRcPtr *) colorspace->to_scene_linear; + return (OCIO_ConstProcessorRcPtr *) colorspace->to_scene_linear; } -static ConstProcessorRcPtr *colorspace_from_scene_linear_processor(ColorSpace *colorspace) +static OCIO_ConstProcessorRcPtr *colorspace_from_scene_linear_processor(ColorSpace *colorspace) { if (colorspace->from_scene_linear == NULL) { BLI_mutex_lock(&processor_lock); if (colorspace->from_scene_linear == NULL) { - ConstProcessorRcPtr *from_scene_linear; + OCIO_ConstProcessorRcPtr *from_scene_linear; from_scene_linear = create_colorspace_transform_processor(global_role_scene_linear, colorspace->name); - colorspace->from_scene_linear = (struct ConstProcessorRcPtr *) from_scene_linear; + colorspace->from_scene_linear = (struct OCIO_ConstProcessorRcPtr *) from_scene_linear; } BLI_mutex_unlock(&processor_lock); } - return (ConstProcessorRcPtr *) colorspace->from_scene_linear; + return (OCIO_ConstProcessorRcPtr *) colorspace->from_scene_linear; } -static ConstProcessorRcPtr *display_from_scene_linear_processor(ColorManagedDisplay *display) +static OCIO_ConstProcessorRcPtr *display_from_scene_linear_processor(ColorManagedDisplay *display) { if (display->from_scene_linear == NULL) { BLI_mutex_lock(&processor_lock); if (display->from_scene_linear == NULL) { const char *view_name = colormanage_view_get_default_name(display); - ConstConfigRcPtr *config = OCIO_getCurrentConfig(); - ConstProcessorRcPtr *processor = NULL; + OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig(); + OCIO_ConstProcessorRcPtr *processor = NULL; if (view_name && config) { const char *view_colorspace = OCIO_configGetDisplayColorSpaceName(config, display->name, view_name); @@ -787,24 +787,24 @@ static ConstProcessorRcPtr *display_from_scene_linear_processor(ColorManagedDisp OCIO_configRelease(config); } - display->from_scene_linear = (struct ConstProcessorRcPtr *) processor; + display->from_scene_linear = (struct OCIO_ConstProcessorRcPtr *) processor; } BLI_mutex_unlock(&processor_lock); } - return (ConstProcessorRcPtr *) display->from_scene_linear; + return (OCIO_ConstProcessorRcPtr *) display->from_scene_linear; } -static ConstProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDisplay *display) +static OCIO_ConstProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDisplay *display) { if (display->to_scene_linear == NULL) { BLI_mutex_lock(&processor_lock); if (display->to_scene_linear == NULL) { const char *view_name = colormanage_view_get_default_name(display); - ConstConfigRcPtr *config = OCIO_getCurrentConfig(); - ConstProcessorRcPtr *processor = NULL; + OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig(); + OCIO_ConstProcessorRcPtr *processor = NULL; if (view_name && config) { const char *view_colorspace = OCIO_configGetDisplayColorSpaceName(config, display->name, view_name); @@ -813,13 +813,13 @@ static ConstProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDispla OCIO_configRelease(config); } - display->to_scene_linear = (struct ConstProcessorRcPtr *) processor; + display->to_scene_linear = (struct OCIO_ConstProcessorRcPtr *) processor; } BLI_mutex_unlock(&processor_lock); } - return (ConstProcessorRcPtr *) display->to_scene_linear; + return (OCIO_ConstProcessorRcPtr *) display->to_scene_linear; } static void init_default_view_settings(const ColorManagedDisplaySettings *display_settings, @@ -1533,7 +1533,7 @@ void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspac */ void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace) { - ConstProcessorRcPtr *processor; + OCIO_ConstProcessorRcPtr *processor; if (!colorspace) { /* should never happen */ @@ -1550,7 +1550,7 @@ void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpac /* same as above, but converts colors in opposite direction */ void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace) { - ConstProcessorRcPtr *processor; + OCIO_ConstProcessorRcPtr *processor; if (!colorspace) { /* should never happen */ @@ -1566,7 +1566,7 @@ void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpac void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, int predivide) { - ConstProcessorRcPtr *processor; + OCIO_ConstProcessorRcPtr *processor; if (!colorspace) { /* should never happen */ @@ -1577,9 +1577,9 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, in processor = colorspace_to_scene_linear_processor(colorspace); if (processor) { - PackedImageDesc *img; + OCIO_PackedImageDesc *img; - img = OCIO_createPackedImageDesc(buffer, width, height, channels, sizeof(float), + img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float), channels * sizeof(float), channels * sizeof(float) * width); if (predivide) @@ -1587,7 +1587,7 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, in else OCIO_processorApply(processor, img); - OCIO_packedImageDescRelease(img); + OCIO_OCIO_PackedImageDescRelease(img); } } @@ -1597,7 +1597,7 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, in */ void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display) { - ConstProcessorRcPtr *processor; + OCIO_ConstProcessorRcPtr *processor; processor = display_from_scene_linear_processor(display); @@ -1608,7 +1608,7 @@ void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManaged /* same as above, but converts color in opposite direction */ void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], ColorManagedDisplay *display) { - ConstProcessorRcPtr *processor; + OCIO_ConstProcessorRcPtr *processor; processor = display_to_scene_linear_processor(display); @@ -1892,7 +1892,7 @@ void IMB_display_buffer_release(void *cache_handle) const char *colormanage_display_get_default_name(void) { - ConstConfigRcPtr *config = OCIO_getCurrentConfig(); + OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig(); const char *display_name; display_name = OCIO_configGetDefaultDisplay(config); @@ -2003,7 +2003,7 @@ const char *IMB_colormanagement_display_get_none_name(void) const char *colormanage_view_get_default_name(const ColorManagedDisplay *display) { - ConstConfigRcPtr *config = OCIO_getCurrentConfig(); + OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig(); const char *name; name = OCIO_configGetDefaultView(config, display->name); @@ -2511,10 +2511,10 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo } if (cm_processor->processor && channels >= 3) { - PackedImageDesc *img; + OCIO_PackedImageDesc *img; /* apply OCIO processor */ - img = OCIO_createPackedImageDesc(buffer, width, height, channels, sizeof(float), + img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float), channels * sizeof(float), channels * sizeof(float) * width); if (predivide) @@ -2522,7 +2522,7 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo else OCIO_processorApply(cm_processor->processor, img); - OCIO_packedImageDescRelease(img); + OCIO_OCIO_PackedImageDescRelease(img); } } From d5157a2259ec63340e6e9f4ed7403c5a3ce067e3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 10:28:36 +0000 Subject: [PATCH 104/143] more improvements to logic for selection/projection: replace ED_view3d_project_short_global() with ED_view3d_project_int_object() in some places. --- .../editors/space_view3d/view3d_select.c | 145 +++++++++++------- 1 file changed, 88 insertions(+), 57 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 014a57a32d0..926c19df95a 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -326,26 +326,49 @@ static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2) static void do_lasso_select_pose(ViewContext *vc, Object *ob, int mcords[][2], short moves, short select) { bPoseChannel *pchan; - float vec[3]; - int sco1[2], sco2[2]; bArmature *arm = ob->data; - if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) return; + if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) { + return; + } + + ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (PBONE_SELECTABLE(arm, pchan->bone)) { + int screen_co_a[2], screen_co_b[2]; + int is_point_done = FALSE; + int points_proj_tot = 0; - /* XXX, todo, use ED_view3d_project_int_object */ - sco1[0] = sco2[0] = IS_CLIPPED; + /* project head location to screenspace */ + if (ED_view3d_project_int_object(vc->ar, pchan->pose_head, screen_co_a, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + if (BLI_lasso_is_point_inside(mcords, moves, screen_co_a[0], screen_co_a[1], INT_MAX)) { + is_point_done = TRUE; + } + } - mul_v3_m4v3(vec, ob->obmat, pchan->pose_head); - ED_view3d_project_int_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); - mul_v3_m4v3(vec, ob->obmat, pchan->pose_tail); - ED_view3d_project_int_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); - - if (BLI_lasso_is_edge_inside(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1], IS_CLIPPED)) { - if (select) pchan->bone->flag |= BONE_SELECTED; - else pchan->bone->flag &= ~BONE_SELECTED; + /* project tail location to screenspace */ + if (ED_view3d_project_int_object(vc->ar, pchan->pose_tail, screen_co_b, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + if (BLI_lasso_is_point_inside(mcords, moves, screen_co_b[0], screen_co_b[1], INT_MAX)) { + is_point_done = TRUE; + } + } + + /* if one of points selected, we skip the bone itself */ + if ((is_point_done == TRUE) || + ((is_point_done == FALSE) && (points_proj_tot == 2) && + BLI_lasso_is_edge_inside(mcords, moves, + screen_co_a[0], screen_co_a[1], + screen_co_b[0], screen_co_b[1], INT_MAX))) + { + if (select) pchan->bone->flag |= BONE_SELECTED; + else pchan->bone->flag &= ~BONE_SELECTED; } } } @@ -571,47 +594,57 @@ static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short mov { bArmature *arm = vc->obedit->data; EditBone *ebone; - float vec[3]; - short sco1[2], sco2[2]; int change = FALSE; if (extend == 0 && select) ED_armature_deselect_all_visible(vc->obedit); + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + /* set editdata in vc */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_SELECTABLE(arm, ebone)) { + int screen_co_a[2], screen_co_b[2]; int is_point_done = FALSE; + int points_proj_tot = 0; - /* XXX, TODO, use ED_view3d_project_short_object here */ - sco1[0] = sco2[0] = IS_CLIPPED; - - mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head); - ED_view3d_project_short_global(vc->ar, vec, sco1, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); - mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); - ED_view3d_project_short_global(vc->ar, vec, sco2, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN); - - if (BLI_lasso_is_point_inside(mcords, moves, sco1[0], sco1[1], IS_CLIPPED)) { - if (select) ebone->flag |= BONE_ROOTSEL; - else ebone->flag &= ~BONE_ROOTSEL; - is_point_done = TRUE; - change = TRUE; - } - if (BLI_lasso_is_point_inside(mcords, moves, sco2[0], sco2[1], IS_CLIPPED)) { - if (select) ebone->flag |= BONE_TIPSEL; - else ebone->flag &= ~BONE_TIPSEL; - is_point_done = TRUE; - change = TRUE; - } - /* if one of points selected, we skip the bone itself */ - if ((is_point_done == FALSE) && - BLI_lasso_is_edge_inside(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1], IS_CLIPPED)) + /* project head location to screenspace */ + if (ED_view3d_project_int_object(vc->ar, ebone->head, screen_co_a, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) { - if (select) ebone->flag |= BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED; - else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + points_proj_tot++; + if (BLI_lasso_is_point_inside(mcords, moves, screen_co_a[0], screen_co_a[1], INT_MAX)) { + is_point_done = TRUE; + if (select) ebone->flag |= BONE_ROOTSEL; + else ebone->flag &= ~BONE_ROOTSEL; + } + } + + /* project tail location to screenspace */ + if (ED_view3d_project_int_object(vc->ar, ebone->tail, screen_co_b, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + if (BLI_lasso_is_point_inside(mcords, moves, screen_co_b[0], screen_co_b[1], INT_MAX)) { + is_point_done = TRUE; + if (select) ebone->flag |= BONE_TIPSEL; + else ebone->flag &= ~BONE_TIPSEL; + } + } + + /* if one of points selected, we skip the bone itself */ + if ((is_point_done == FALSE) && (points_proj_tot == 2) && + BLI_lasso_is_edge_inside(mcords, moves, + screen_co_a[0], screen_co_a[1], + screen_co_b[0], screen_co_b[1], INT_MAX)) + { + if (select) ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); change = TRUE; } + + change |= is_point_done; } } @@ -623,32 +656,28 @@ static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short mov } - - static void do_lasso_select_meta(ViewContext *vc, int mcords[][2], short moves, short extend, short select) { MetaBall *mb = (MetaBall *)vc->obedit->data; MetaElem *ml; - float vec[3]; - short sco[2]; if (extend == 0 && select) { + /* XXX, make an editor function as is done elsewhere */ for (ml = mb->editelems->first; ml; ml = ml->next) { ml->flag &= ~SELECT; } } - for (ml = mb->editelems->first; ml; ml = ml->next) { - - /* TODO, use ED_view3d_project_short_object */ + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mul_v3_m4v3(vec, vc->obedit->obmat, &ml->x); - if (ED_view3d_project_short_global(vc->ar, vec, sco, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + for (ml = mb->editelems->first; ml; ml = ml->next) { + int screen_co[2]; + if (ED_view3d_project_int_object(vc->ar, &ml->x, screen_co, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) { - if (BLI_lasso_is_point_inside(mcords, moves, sco[0], sco[1], INT_MAX)) { - if (select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; + if (BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) { + if (select) ml->flag |= SELECT; + else ml->flag &= ~SELECT; } } } @@ -2405,8 +2434,9 @@ static void pose_circle_select(ViewContext *vc, int select, const int mval[2], f } } - /* only if the endpoints didn't get selected, deal with the middle of the bone too */ - /* XXX should we just do this always? */ + /* only if the endpoints didn't get selected, deal with the middle of the bone too + * It works nicer to only do this if the head or tail are not in the circle, + * otherwise there is no way to circle select joints alone */ if ((is_point_done == FALSE) && (points_proj_tot == 2) && edge_inside_circle(mval[0], mval[1], rad, screen_co_a[0], screen_co_a[1], @@ -2497,8 +2527,9 @@ static void armature_circle_select(ViewContext *vc, int select, const int mval[2 * - the call to check also does the selection already */ - /* only if the endpoints didn't get selected, deal with the middle of the bone too */ - /* XXX should we just do this always? */ + /* only if the endpoints didn't get selected, deal with the middle of the bone too + * It works nicer to only do this if the head or tail are not in the circle, + * otherwise there is no way to circle select joints alone */ if ((is_point_done == FALSE) && (points_proj_tot == 2) && edge_inside_circle(mval[0], mval[1], rad, screen_co_a[0], screen_co_a[1], From 456a20ea07258baa01bec53fcb0f8eba59285a33 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 5 Oct 2012 12:18:04 +0000 Subject: [PATCH 105/143] Fix #32735: GLSL shadows not working together with X-ray drawing. --- source/blender/editors/space_view3d/drawobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 6e11df30da0..1d773f5db9e 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -3583,7 +3583,7 @@ static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D } } - if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0) { + if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) { /* GPU_begin_object_materials checked if this is needed */ if (do_alpha_after) { if (ob->dtx & OB_DRAWXRAY) { @@ -6492,7 +6492,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short return; /* xray delay? */ - if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0) { + if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) { /* don't do xray in particle mode, need the z-buffer */ if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) { /* xray and transp are set when it is drawing the 2nd/3rd pass */ From cd19fd6c28bb976fd1ea7448fcde45fc217e004a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 5 Oct 2012 12:18:07 +0000 Subject: [PATCH 106/143] Fix related to #32734: crash saving blend file from render_pre callback. Not sure I want to recommend anyone doing this, but the fix is simple. --- source/blender/windowmanager/intern/wm_files.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index eb6fabd03c6..7b78dbedb31 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -56,6 +56,7 @@ #include "BLI_blenlib.h" #include "BLI_linklist.h" #include "BLI_utildefines.h" +#include "BLI_threads.h" #include "BLI_callbacks.h" #include "BLF_translation.h" @@ -794,7 +795,7 @@ int WM_file_write(bContext *C, const char *target, int fileflags, ReportList *re /* blend file thumbnail */ /* save before exit_editmode, otherwise derivedmeshes for shared data corrupt #27765) */ - if (U.flag & USER_SAVE_PREVIEWS) { + if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) { ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_wm_screen(C), &thumb); } From eb46c080a2d3b71beb626517e30ae2b5f2e60425 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 5 Oct 2012 12:18:09 +0000 Subject: [PATCH 107/143] Fix #32734: Object.to_mesh() gave wrong user count for curves/surface/text objects. --- source/blender/makesrna/intern/rna_object_api.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index b0b76c9e38f..879a77527cd 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -177,6 +177,8 @@ Mesh *rna_Object_to_mesh(Object *ob, ReportList *reports, Scene *sce, int apply_ return NULL; /* only do basis metaball */ tmpmesh = BKE_mesh_add("Mesh"); + /* BKE_mesh_add gives us a user count we don't need */ + tmpmesh->id.us--; if (render) { ListBase disp = {NULL, NULL}; @@ -186,6 +188,7 @@ Mesh *rna_Object_to_mesh(Object *ob, ReportList *reports, Scene *sce, int apply_ } else BKE_mesh_from_metaball(&ob->disp, tmpmesh); + break; } @@ -214,6 +217,9 @@ Mesh *rna_Object_to_mesh(Object *ob, ReportList *reports, Scene *sce, int apply_ dm->release(dm); } + /* BKE_mesh_add/copy gives us a user count we don't need */ + tmpmesh->id.us--; + break; default: BKE_report(reports, RPT_ERROR, "Object does not have geometry data"); @@ -283,9 +289,6 @@ Mesh *rna_Object_to_mesh(Object *ob, ReportList *reports, Scene *sce, int apply_ /* cycles and exporters rely on this still */ BKE_mesh_tessface_ensure(tmpmesh); - /* we don't assign it to anything */ - tmpmesh->id.us--; - /* make sure materials get updated in objects */ test_object_materials(&tmpmesh->id); From 00ce0c9aae04a461d96dc626bc6651a3ba0211cf Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 5 Oct 2012 12:59:09 +0000 Subject: [PATCH 108/143] Clean up in "add object" code: * Get rid of ED_object_add_generic_invoke() and all invoke callbacks using it, it was doing nothing exec() callbacks would not do. In fact, its only action (setting part of common add ops properties, like loc, layers, etc.) was needed too by direct exec call, so it was done twice in case of using invoke()! * Replace custom invoke code for metaballs by WM_menu_invoke helper (as already used by lamps). * Add a new OBJECT_OT_empty_add op, to allow direct addition of empties of a given drawtype. * And some general code cleanup (like trailing spaces, empty lines, ...). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Did quite a bunch of tests/verifications, but obviously could not tackle all possible scenarios... Anyway, if any, bugs should arize quite quickly (but I don’t expect any! :p ). --- release/scripts/startup/bl_ui/space_info.py | 51 ++- source/blender/editors/curve/editcurve.c | 68 ++-- source/blender/editors/include/ED_object.h | 1 - source/blender/editors/mesh/editmesh_add.c | 109 +++---- source/blender/editors/object/object_add.c | 301 +++++++++--------- source/blender/editors/object/object_intern.h | 1 + source/blender/editors/object/object_ops.c | 1 + 7 files changed, 258 insertions(+), 274 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index de58b5d1aaf..9ab2a772df0 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -192,7 +192,7 @@ class INFO_MT_mesh_add(Menu): def draw(self, context): layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("mesh.primitive_plane_add", icon='MESH_PLANE', text="Plane") layout.operator("mesh.primitive_cube_add", icon='MESH_CUBE', text="Cube") layout.operator("mesh.primitive_circle_add", icon='MESH_CIRCLE', text="Circle") @@ -203,7 +203,7 @@ class INFO_MT_mesh_add(Menu): layout.separator() layout.operator("mesh.primitive_grid_add", icon='MESH_GRID', text="Grid") layout.operator("mesh.primitive_monkey_add", icon='MESH_MONKEY', text="Monkey") - layout.operator("mesh.primitive_torus_add", text="Torus", icon='MESH_TORUS') + layout.operator("mesh.primitive_torus_add", icon='MESH_TORUS', text="Torus") class INFO_MT_curve_add(Menu): @@ -213,7 +213,7 @@ class INFO_MT_curve_add(Menu): def draw(self, context): layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("curve.primitive_bezier_curve_add", icon='CURVE_BEZCURVE', text="Bezier") layout.operator("curve.primitive_bezier_circle_add", icon='CURVE_BEZCIRCLE', text="Circle") layout.operator("curve.primitive_nurbs_curve_add", icon='CURVE_NCURVE', text="Nurbs Curve") @@ -221,6 +221,22 @@ class INFO_MT_curve_add(Menu): layout.operator("curve.primitive_nurbs_path_add", icon='CURVE_PATH', text="Path") +class INFO_MT_surface_add(Menu): + bl_idname = "INFO_MT_surface_add" + bl_label = "Surface" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'EXEC_REGION_WIN' + layout.operator("surface.primitive_nurbs_surface_curve_add", icon='SURFACE_NCURVE', text="NURBS Curve") + layout.operator("surface.primitive_nurbs_surface_circle_add", icon='SURFACE_NCIRCLE', text="NURBS Circle") + layout.operator("surface.primitive_nurbs_surface_surface_add", icon='SURFACE_NSURFACE', text="NURBS Surface") + layout.operator("surface.primitive_nurbs_surface_cylinder_add", icon='SURFACE_NCYLINDER', text="NURBS Cylinder") + layout.operator("surface.primitive_nurbs_surface_sphere_add", icon='SURFACE_NSPHERE', text="NURBS Sphere") + layout.operator("surface.primitive_nurbs_surface_torus_add", icon='SURFACE_NTORUS', text="NURBS Torus") + + class INFO_MT_edit_curve_add(Menu): bl_idname = "INFO_MT_edit_curve_add" bl_label = "Add" @@ -229,7 +245,7 @@ class INFO_MT_edit_curve_add(Menu): is_surf = context.active_object.type == 'SURFACE' layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator_context = 'EXEC_REGION_WIN' if is_surf: INFO_MT_surface_add.draw(self, context) @@ -237,22 +253,6 @@ class INFO_MT_edit_curve_add(Menu): INFO_MT_curve_add.draw(self, context) -class INFO_MT_surface_add(Menu): - bl_idname = "INFO_MT_surface_add" - bl_label = "Surface" - - def draw(self, context): - layout = self.layout - - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("surface.primitive_nurbs_surface_curve_add", icon='SURFACE_NCURVE', text="NURBS Curve") - layout.operator("surface.primitive_nurbs_surface_circle_add", icon='SURFACE_NCIRCLE', text="NURBS Circle") - layout.operator("surface.primitive_nurbs_surface_surface_add", icon='SURFACE_NSURFACE', text="NURBS Surface") - layout.operator("surface.primitive_nurbs_surface_cylinder_add", icon='SURFACE_NCYLINDER', text="NURBS Cylinder") - layout.operator("surface.primitive_nurbs_surface_sphere_add", icon='SURFACE_NSPHERE', text="NURBS Sphere") - layout.operator("surface.primitive_nurbs_surface_torus_add", icon='SURFACE_NTORUS', text="NURBS Torus") - - class INFO_MT_armature_add(Menu): bl_idname = "INFO_MT_armature_add" bl_label = "Armature" @@ -260,7 +260,7 @@ class INFO_MT_armature_add(Menu): def draw(self, context): layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA') @@ -284,23 +284,18 @@ class INFO_MT_add(Menu): #layout.operator_menu_enum("object.surface_add", "type", text="Surface", icon='OUTLINER_OB_SURFACE') layout.menu("INFO_MT_surface_add", icon='OUTLINER_OB_SURFACE') layout.operator_menu_enum("object.metaball_add", "type", text="Metaball", icon='OUTLINER_OB_META') -# layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT') layout.separator() layout.menu("INFO_MT_armature_add", icon='OUTLINER_OB_ARMATURE') - # XXX Quick fix for [#32764]. - layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE' - layout.operator("object.add", text="Empty", icon='OUTLINER_OB_EMPTY').type = 'EMPTY' - layout.operator_context = 'EXEC_REGION_WIN' + layout.operator_menu_enum("object.empty_add", "type", text="Empty", icon='OUTLINER_OB_EMPTY') layout.separator() layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER') layout.separator() layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA') -# layout.operator_context = 'EXEC_AREA' layout.operator_menu_enum("object.lamp_add", "type", text="Lamp", icon='OUTLINER_OB_LAMP') layout.separator() @@ -308,7 +303,7 @@ class INFO_MT_add(Menu): layout.separator() if(len(bpy.data.groups) > 10): - layout.operator_context = 'INVOKE_DEFAULT' + layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("object.group_instance_add", text="Group Instance...", icon='OUTLINER_OB_EMPTY') else: layout.operator_menu_enum("object.group_instance_add", "group", text="Group Instance", icon='OUTLINER_OB_EMPTY') diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 9c13f4be6a9..afd6bc4c4b5 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -6567,18 +6567,18 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf) if (!isSurf) { /* adding curve */ if (obedit == NULL || obedit->type != OB_CURVE) { Curve *cu; - + obedit = ED_object_add_type(C, OB_CURVE, loc, rot, TRUE, layer); newob = 1; cu = (Curve *)obedit->data; cu->flag |= CU_DEFORM_FILL; - + if (type & CU_PRIM_PATH) cu->flag |= CU_PATH | CU_3D; - } + } else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); - } + } else { /* adding surface */ if (obedit == NULL || obedit->type != OB_SURF) { obedit = ED_object_add_type(C, OB_SURF, loc, rot, TRUE, layer); @@ -6589,7 +6589,6 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf) /* rename here, the undo stack checks name for valid undo pushes */ if (newob) { - if (obedit->type == OB_CURVE) { rename_id((ID *)obedit, get_curve_defname(type)); rename_id((ID *)obedit->data, get_curve_defname(type)); @@ -6599,11 +6598,11 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf) rename_id((ID *)obedit->data, get_surf_defname(type)); } } - + /* ED_object_add_type doesnt do an undo, is needed for redo operator on primitive */ if (newob && enter_editmode) ED_undo_push(C, "Enter Editmode"); - + ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); nu = add_nurbs_primitive(C, obedit, mat, type, newob); @@ -6643,12 +6642,11 @@ void CURVE_OT_primitive_bezier_curve_add(wmOperatorType *ot) ot->name = "Add Bezier"; ot->description = "Construct a Bezier Curve"; ot->idname = "CURVE_OT_primitive_bezier_curve_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_bezier_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6666,12 +6664,11 @@ void CURVE_OT_primitive_bezier_circle_add(wmOperatorType *ot) ot->name = "Add Bezier Circle"; ot->description = "Construct a Bezier Circle"; ot->idname = "CURVE_OT_primitive_bezier_circle_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_bezier_circle_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6689,12 +6686,11 @@ void CURVE_OT_primitive_nurbs_curve_add(wmOperatorType *ot) ot->name = "Add Nurbs Curve"; ot->description = "Construct a Nurbs Curve"; ot->idname = "CURVE_OT_primitive_nurbs_curve_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_nurbs_curve_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6712,12 +6708,11 @@ void CURVE_OT_primitive_nurbs_circle_add(wmOperatorType *ot) ot->name = "Add Nurbs Circle"; ot->description = "Construct a Nurbs Circle"; ot->idname = "CURVE_OT_primitive_nurbs_circle_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_nurbs_circle_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6735,12 +6730,11 @@ void CURVE_OT_primitive_nurbs_path_add(wmOperatorType *ot) ot->name = "Add Path"; ot->description = "Construct a Path"; ot->idname = "CURVE_OT_primitive_nurbs_path_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_curve_path_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6759,12 +6753,11 @@ void SURFACE_OT_primitive_nurbs_surface_curve_add(wmOperatorType *ot) ot->name = "Add Surface Curve"; ot->description = "Construct a Nurbs surface Curve"; ot->idname = "SURFACE_OT_primitive_nurbs_surface_curve_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_nurbs_surface_curve_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6782,12 +6775,11 @@ void SURFACE_OT_primitive_nurbs_surface_circle_add(wmOperatorType *ot) ot->name = "Add Surface Circle"; ot->description = "Construct a Nurbs surface Circle"; ot->idname = "SURFACE_OT_primitive_nurbs_surface_circle_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_nurbs_surface_circle_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6805,12 +6797,11 @@ void SURFACE_OT_primitive_nurbs_surface_surface_add(wmOperatorType *ot) ot->name = "Add Surface Patch"; ot->description = "Construct a Nurbs surface Patch"; ot->idname = "SURFACE_OT_primitive_nurbs_surface_surface_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_nurbs_surface_surface_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6828,12 +6819,11 @@ void SURFACE_OT_primitive_nurbs_surface_cylinder_add(wmOperatorType *ot) ot->name = "Add Surface Cylinder"; ot->description = "Construct a Nurbs surface Cylinder"; ot->idname = "SURFACE_OT_primitive_nurbs_surface_cylinder_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_nurbs_surface_cylinder_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6851,12 +6841,11 @@ void SURFACE_OT_primitive_nurbs_surface_sphere_add(wmOperatorType *ot) ot->name = "Add Surface Sphere"; ot->description = "Construct a Nurbs surface Sphere"; ot->idname = "SURFACE_OT_primitive_nurbs_surface_sphere_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_nurbs_surface_sphere_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6874,12 +6863,11 @@ void SURFACE_OT_primitive_nurbs_surface_torus_add(wmOperatorType *ot) ot->name = "Add Surface Torus"; ot->description = "Construct a Nurbs surface Torus"; ot->idname = "SURFACE_OT_primitive_nurbs_surface_torus_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_nurbs_surface_torus_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 26c8b865377..9836d690e53 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -126,7 +126,6 @@ float ED_object_new_primitive_matrix(struct bContext *C, struct Object *editob, const float loc[3], const float rot[3], float primmat[][4]); void ED_object_add_generic_props(struct wmOperatorType *ot, int do_editmode); -int ED_object_add_generic_invoke(struct bContext *C, struct wmOperator *op, struct wmEvent *event); int ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, float loc[3], float rot[3], int *enter_editmode, unsigned int *layer, int *is_view_aligned); diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index fdaddec5246..0cf4ac48bf7 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -64,7 +64,7 @@ static Object *make_prim_init(bContext *C, const char *idname, *state = 0; if (obedit == NULL || obedit->type != OB_MESH) { obedit = ED_object_add_type(C, OB_MESH, loc, rot, FALSE, layer); - + rename_id((ID *)obedit, idname); rename_id((ID *)obedit->data, idname); @@ -103,7 +103,7 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op) int enter_editmode; int state; unsigned int layer; - + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, "Plane", &dia, mat, &state, loc, rot, layer); em = BMEdit_FromObject(obedit); @@ -125,12 +125,11 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot) ot->name = "Add Plane"; ot->description = "Construct a filled planar mesh with 4 vertices"; ot->idname = "MESH_OT_primitive_plane_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_plane_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -145,7 +144,7 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op) int enter_editmode; int state; unsigned int layer; - + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, "Cube", &dia, mat, &state, loc, rot, layer); em = BMEdit_FromObject(obedit); @@ -153,7 +152,7 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf(em, op, "vertout", "create_cube mat=%m4 size=%f", mat, dia * 2.0f)) { return OPERATOR_CANCELLED; } - + /* BMESH_TODO make plane side this: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */ make_prim_finish(C, obedit, &state, enter_editmode); @@ -166,12 +165,11 @@ void MESH_OT_primitive_cube_add(wmOperatorType *ot) ot->name = "Add Cube"; ot->description = "Construct a cube mesh"; ot->idname = "MESH_OT_primitive_cube_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_cube_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -192,10 +190,10 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) int enter_editmode; int state, cap_end, cap_tri; unsigned int layer; - + cap_end = RNA_enum_get(op->ptr, "fill_type"); cap_tri = (cap_end == 2); - + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, "Circle", &dia, mat, &state, loc, rot, layer); em = BMEdit_FromObject(obedit); @@ -207,9 +205,9 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) { return OPERATOR_CANCELLED; } - + make_prim_finish(C, obedit, &state, enter_editmode); - + return OPERATOR_FINISHED; } @@ -221,15 +219,14 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot) ot->name = "Add Circle"; ot->description = "Construct a circle mesh"; ot->idname = "MESH_OT_primitive_circle_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_circle_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500); prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); @@ -247,10 +244,10 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) int enter_editmode; int state, cap_end, cap_tri; unsigned int layer; - + cap_end = RNA_enum_get(op->ptr, "end_fill_type"); cap_tri = (cap_end == 2); - + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, "Cylinder", &dia, mat, &state, loc, rot, layer); em = BMEdit_FromObject(obedit); @@ -266,9 +263,9 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) { return OPERATOR_CANCELLED; } - + make_prim_finish(C, obedit, &state, enter_editmode); - + return OPERATOR_FINISHED; } @@ -280,15 +277,14 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) ot->name = "Add Cylinder"; ot->description = "Construct a cylinder mesh"; ot->idname = "MESH_OT_primitive_cylinder_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_cylinder_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500); prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); @@ -308,10 +304,10 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) int enter_editmode; int state, cap_end, cap_tri; unsigned int layer; - + cap_end = RNA_enum_get(op->ptr, "end_fill_type"); cap_tri = (cap_end == 2); - + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, "Cone", &dia, mat, &state, loc, rot, layer); em = BMEdit_FromObject(obedit); @@ -324,7 +320,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) { return OPERATOR_CANCELLED; } - + make_prim_finish(C, obedit, &state, enter_editmode); return OPERATOR_FINISHED; @@ -338,15 +334,14 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot) ot->name = "Add Cone"; ot->description = "Construct a conic mesh"; ot->idname = "MESH_OT_primitive_cone_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_cone_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500); prop = RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, FLT_MAX, "Radius 1", "", 0.001, 100.00); @@ -368,7 +363,7 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op) int enter_editmode; int state; unsigned int layer; - + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, "Grid", &dia, mat, &state, loc, rot, layer); em = BMEdit_FromObject(obedit); @@ -381,8 +376,9 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op) { return OPERATOR_CANCELLED; } - + make_prim_finish(C, obedit, &state, enter_editmode); + return OPERATOR_FINISHED; } @@ -394,15 +390,14 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot) ot->name = "Add Grid"; ot->description = "Construct a grid mesh"; ot->idname = "MESH_OT_primitive_grid_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_grid_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_int(ot->srna, "x_subdivisions", 10, 3, INT_MAX, "X Subdivisions", "", 3, 1000); RNA_def_int(ot->srna, "y_subdivisions", 10, 3, INT_MAX, "Y Subdivisions", "", 3, 1000); @@ -420,19 +415,20 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op) int enter_editmode; int state, view_aligned; unsigned int layer; - + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, &view_aligned); if (!view_aligned) rot[0] += (float)M_PI / 2.0f; - + obedit = make_prim_init(C, "Monkey", &dia, mat, &state, loc, rot, layer); em = BMEdit_FromObject(obedit); if (!EDBM_op_call_and_selectf(em, op, "vertout", "create_monkey mat=%m4", mat)) { return OPERATOR_CANCELLED; } - + make_prim_finish(C, obedit, &state, enter_editmode); + return OPERATOR_FINISHED; } @@ -442,12 +438,11 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot) ot->name = "Add Monkey"; ot->description = "Construct a Suzanne mesh"; ot->idname = "MESH_OT_primitive_monkey_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_monkey_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -462,7 +457,7 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) int enter_editmode; int state; unsigned int layer; - + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, "Sphere", &dia, mat, &state, loc, rot, layer); em = BMEdit_FromObject(obedit); @@ -474,7 +469,7 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) { return OPERATOR_CANCELLED; } - + make_prim_finish(C, obedit, &state, enter_editmode); return OPERATOR_FINISHED; @@ -488,15 +483,14 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) ot->name = "Add UV Sphere"; ot->description = "Construct a UV sphere mesh"; ot->idname = "MESH_OT_primitive_uv_sphere_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_uvsphere_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_int(ot->srna, "segments", 32, 3, INT_MAX, "Segments", "", 3, 500); RNA_def_int(ot->srna, "ring_count", 16, 3, INT_MAX, "Rings", "", 3, 500); @@ -514,7 +508,7 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) int enter_editmode; int state; unsigned int layer; - + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, "Icosphere", &dia, mat, &state, loc, rot, layer); em = BMEdit_FromObject(obedit); @@ -527,10 +521,10 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) { return OPERATOR_CANCELLED; } - + make_prim_finish(C, obedit, &state, enter_editmode); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot) @@ -541,15 +535,14 @@ void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot) ot->name = "Add Ico Sphere"; ot->description = "Construct an Icosphere mesh"; ot->idname = "MESH_OT_primitive_ico_sphere_add"; - + /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = add_primitive_icosphere_exec; ot->poll = ED_operator_scene_editable; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_int(ot->srna, "subdivisions", 2, 1, INT_MAX, "Subdivisions", "", 1, 8); prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0f, FLT_MAX, "Size", "", 0.001f, 100.00); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 102353ce1d1..f6a7a6d6f17 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -43,6 +43,7 @@ #include "DNA_meta_types.h" #include "DNA_object_fluidsim.h" #include "DNA_object_force.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_speaker_types.h" #include "DNA_vfont_types.h" @@ -138,6 +139,19 @@ static EnumPropertyItem field_type_items[] = { {0, NULL, 0, NULL, NULL} }; +/* Copy from rna_object.c */ +static EnumPropertyItem empty_drawtype_items[] = { + {OB_PLAINAXES, "PLAIN_AXES", 0, "Plain Axes", ""}, + {OB_ARROWS, "ARROWS", 0, "Arrows", ""}, + {OB_SINGLE_ARROW, "SINGLE_ARROW", 0, "Single Arrow", ""}, + {OB_CIRCLE, "CIRCLE", 0, "Circle", ""}, + {OB_CUBE, "CUBE", 0, "Cube", ""}, + {OB_EMPTY_SPHERE, "SPHERE", 0, "Sphere", ""}, + {OB_EMPTY_CONE, "CONE", 0, "Cone", ""}, + {OB_EMPTY_IMAGE, "IMAGE", 0, "Image", ""}, + {0, NULL, 0, NULL, NULL} +}; + /************************** Exported *****************************/ void ED_object_location_from_view(bContext *C, float loc[3]) @@ -245,100 +259,100 @@ void ED_object_add_generic_props(wmOperatorType *ot, int do_editmode) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } -static void object_add_generic_invoke_options(bContext *C, wmOperator *op) -{ - if (RNA_struct_find_property(op->ptr, "enter_editmode")) /* optional */ - if (!RNA_struct_property_is_set(op->ptr, "enter_editmode")) - RNA_boolean_set(op->ptr, "enter_editmode", U.flag & USER_ADD_EDITMODE); - - if (!RNA_struct_property_is_set(op->ptr, "location")) { - float loc[3]; - - ED_object_location_from_view(C, loc); - RNA_float_set_array(op->ptr, "location", loc); - } - - if (!RNA_struct_property_is_set(op->ptr, "layers")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - int a, values[20], layer; - - if (v3d) { - layer = (v3d->scenelock && !v3d->localvd) ? scene->layact : v3d->layact; - } - else { - layer = scene->layact; - } - - for (a = 0; a < 20; a++) { - values[a] = (layer & (1 << a)); - } - - RNA_boolean_set_array(op->ptr, "layers", values); - } -} - -int ED_object_add_generic_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) -{ - object_add_generic_invoke_options(C, op); - return op->type->exec(C, op); -} - int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float loc[3], float rot[3], int *enter_editmode, unsigned int *layer, int *is_view_aligned) { View3D *v3d = CTX_wm_view3d(C); - int a, layer_values[20]; - int view_align; - *enter_editmode = FALSE; - if (RNA_struct_find_property(op->ptr, "enter_editmode") && RNA_boolean_get(op->ptr, "enter_editmode")) { - *enter_editmode = TRUE; - } + /* Switch to Edit mode? */ + if (RNA_struct_find_property(op->ptr, "enter_editmode")) { /* optional */ + int _enter_editmode; + if (!enter_editmode) + enter_editmode = &_enter_editmode; - if (RNA_struct_property_is_set(op->ptr, "layers")) { - RNA_boolean_get_array(op->ptr, "layers", layer_values); - *layer = 0; - for (a = 0; a < 20; a++) { - if (layer_values[a]) - *layer |= (1 << a); - else - *layer &= ~(1 << a); + if (RNA_struct_property_is_set(op->ptr, "enter_editmode") && enter_editmode) + *enter_editmode = RNA_boolean_get(op->ptr, "enter_editmode"); + else { + *enter_editmode = U.flag & USER_ADD_EDITMODE; + RNA_boolean_set(op->ptr, "enter_editmode", *enter_editmode); } } - else { - /* not set, use the scenes layers */ - Scene *scene = CTX_data_scene(C); - *layer = scene->layact; + + /* Get layers! */ + { + int a, layer_values[20]; + unsigned int _layer; + if (!layer) + layer = &_layer; + + if (RNA_struct_property_is_set(op->ptr, "layers")) { + RNA_boolean_get_array(op->ptr, "layers", layer_values); + *layer = 0; + for (a = 0; a < 20; a++) { + if (layer_values[a]) + *layer |= (1 << a); + } + } + else { + Scene *scene = CTX_data_scene(C); + if (v3d) + *layer = (v3d->scenelock && !v3d->localvd) ? scene->layact : v3d->layact; + else + *layer = scene->layact; + for (a = 0; a < 20; a++) { + layer_values[a] = *layer & (1 << a); + } + RNA_boolean_set_array(op->ptr, "layers", layer_values); + } + + /* in local view we additionally add local view layers, + * not part of operator properties */ + if (v3d && v3d->localvd) + *layer |= v3d->lay; } - /* in local view we additionally add local view layers, - * not part of operator properties */ - if (v3d && v3d->localvd) - *layer |= v3d->lay; + /* Location! */ + { + float _loc[3]; + if (!loc) + loc = _loc; - if (RNA_struct_property_is_set(op->ptr, "rotation")) - view_align = FALSE; - else if (RNA_struct_property_is_set(op->ptr, "view_align")) - view_align = RNA_boolean_get(op->ptr, "view_align"); - else { - view_align = U.flag & USER_ADD_VIEWALIGNED; - RNA_boolean_set(op->ptr, "view_align", view_align); + if (RNA_struct_property_is_set(op->ptr, "location")) { + RNA_float_get_array(op->ptr, "location", loc); + } + else { + ED_object_location_from_view(C, loc); + RNA_float_set_array(op->ptr, "location", loc); + } } - if (view_align) { - ED_object_rotation_from_view(C, rot); - RNA_float_set_array(op->ptr, "rotation", rot); + /* Rotation! */ + { + int _is_view_aligned; + float _rot[3]; + if (!is_view_aligned) + is_view_aligned = &_is_view_aligned; + if (!rot) + rot = _rot; + + if (RNA_struct_property_is_set(op->ptr, "rotation")) + *is_view_aligned = FALSE; + else if (RNA_struct_property_is_set(op->ptr, "view_align")) + *is_view_aligned = RNA_boolean_get(op->ptr, "view_align"); + else { + *is_view_aligned = U.flag & USER_ADD_VIEWALIGNED; + RNA_boolean_set(op->ptr, "view_align", *is_view_aligned); + } + + if (*is_view_aligned) { + ED_object_rotation_from_view(C, rot); + RNA_float_set_array(op->ptr, "rotation", rot); + } + else + RNA_float_get_array(op->ptr, "rotation", rot); } - else - RNA_float_get_array(op->ptr, "rotation", rot); - if (is_view_aligned) - *is_view_aligned = view_align; - - RNA_float_get_array(op->ptr, "location", loc); - - if (*layer == 0) { + if (layer && *layer == 0) { BKE_report(op->reports, RPT_ERROR, "Property 'layer' has no values set"); return 0; } @@ -405,9 +419,7 @@ void OBJECT_OT_add(wmOperatorType *ot) ot->idname = "OBJECT_OT_add"; /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = object_add_exec; - ot->poll = ED_operator_objectmode; /* flags */ @@ -420,57 +432,47 @@ void OBJECT_OT_add(wmOperatorType *ot) /********************* Add Effector Operator ********************/ -/* for effector add primitive operators */ -static Object *effector_add_type(bContext *C, wmOperator *op, int type) +/* for object add operator */ +static int effector_add_exec(bContext *C, wmOperator *op) { Object *ob; - int enter_editmode; + int type, enter_editmode; unsigned int layer; float loc[3], rot[3]; float mat[4][4]; - object_add_generic_invoke_options(C, op); - if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) - return NULL; + return OPERATOR_CANCELLED; + + type = RNA_enum_get(op->ptr, "type"); if (type == PFIELD_GUIDE) { ob = ED_object_add_type(C, OB_CURVE, loc, rot, FALSE, layer); - rename_id(&ob->id, "CurveGuide"); + if (!ob) + return OPERATOR_CANCELLED; + rename_id(&ob->id, "CurveGuide"); ((Curve *)ob->data)->flag |= CU_PATH | CU_3D; ED_object_enter_editmode(C, 0); ED_object_new_primitive_matrix(C, ob, loc, rot, mat); BLI_addtail(object_editcurve_get(ob), add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, 1)); - if (!enter_editmode) ED_object_exit_editmode(C, EM_FREEDATA); } else { ob = ED_object_add_type(C, OB_EMPTY, loc, rot, FALSE, layer); - rename_id(&ob->id, "Field"); + if (!ob) + return OPERATOR_CANCELLED; - switch (type) { - case PFIELD_WIND: - case PFIELD_VORTEX: - ob->empty_drawtype = OB_SINGLE_ARROW; - break; - } + rename_id(&ob->id, "Field"); + if (ELEM(type, PFIELD_WIND, PFIELD_VORTEX)) + ob->empty_drawtype = OB_SINGLE_ARROW; } ob->pd = object_add_collision_fields(type); DAG_scene_sort(CTX_data_main(C), CTX_data_scene(C)); - return ob; -} - -/* for object add operator */ -static int effector_add_exec(bContext *C, wmOperator *op) -{ - if (effector_add_type(C, op, RNA_enum_get(op->ptr, "type")) == NULL) - return OPERATOR_CANCELLED; - return OPERATOR_FINISHED; } @@ -482,9 +484,7 @@ void OBJECT_OT_effector_add(wmOperatorType *ot) ot->idname = "OBJECT_OT_effector_add"; /* api callbacks */ - ot->invoke = WM_menu_invoke; ot->exec = effector_add_exec; - ot->poll = ED_operator_objectmode; /* flags */ @@ -509,8 +509,6 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) /* force view align for cameras */ RNA_boolean_set(op->ptr, "view_align", TRUE); - object_add_generic_invoke_options(C, op); - if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; @@ -562,8 +560,6 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; float mat[4][4]; - object_add_generic_invoke_options(C, op); /* XXX these props don't get set right when only exec() is called */ - if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; @@ -571,7 +567,8 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) obedit = ED_object_add_type(C, OB_MBALL, loc, rot, TRUE, layer); newob = 1; } - else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + else + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); @@ -587,25 +584,6 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int object_metaball_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) -{ - Object *obedit = CTX_data_edit_object(C); - uiPopupMenu *pup; - uiLayout *layout; - - object_add_generic_invoke_options(C, op); - - pup = uiPupMenuBegin(C, op->type->name, ICON_NONE); - layout = uiPupMenuLayout(pup); - if (!obedit || obedit->type == OB_MBALL) - uiItemsEnumO(layout, op->type->idname, "type"); - else - uiItemsEnumO(layout, "OBJECT_OT_metaball_add", "type"); - uiPupMenuEnd(C, pup); - - return OPERATOR_CANCELLED; -} - void OBJECT_OT_metaball_add(wmOperatorType *ot) { /* identifiers */ @@ -614,14 +592,15 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot) ot->idname = "OBJECT_OT_metaball_add"; /* api callbacks */ - ot->invoke = object_metaball_add_invoke; + ot->invoke = WM_menu_invoke;/* object_metaball_add_invoke; */ ot->exec = object_metaball_add_exec; ot->poll = ED_operator_scene_editable; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_enum(ot->srna, "type", metaelem_type_items, 0, "Primitive", ""); + ot->prop = RNA_def_enum(ot->srna, "type", metaelem_type_items, 0, "Primitive", ""); + ED_object_add_generic_props(ot, TRUE); } @@ -634,7 +613,6 @@ static int object_add_text_exec(bContext *C, wmOperator *op) unsigned int layer; float loc[3], rot[3]; - object_add_generic_invoke_options(C, op); /* XXX these props don't get set right when only exec() is called */ if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; @@ -656,7 +634,6 @@ void OBJECT_OT_text_add(wmOperatorType *ot) ot->idname = "OBJECT_OT_text_add"; /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = object_add_text_exec; ot->poll = ED_operator_objectmode; @@ -677,7 +654,6 @@ static int object_armature_add_exec(bContext *C, wmOperator *op) unsigned int layer; float loc[3], rot[3]; - object_add_generic_invoke_options(C, op); /* XXX these props don't get set right when only exec() is called */ if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; @@ -713,7 +689,6 @@ void OBJECT_OT_armature_add(wmOperatorType *ot) ot->idname = "OBJECT_OT_armature_add"; /* api callbacks */ - ot->invoke = ED_object_add_generic_invoke; ot->exec = object_armature_add_exec; ot->poll = ED_operator_objectmode; @@ -722,6 +697,45 @@ void OBJECT_OT_armature_add(wmOperatorType *ot) ED_object_add_generic_props(ot, TRUE); } +/********************* Add Empty Operator ********************/ + +static int object_empty_add_exec(bContext *C, wmOperator *op) +{ + Object *ob; + int type = RNA_enum_get(op->ptr, "type"); + unsigned int layer; + float loc[3], rot[3]; + + if (!ED_object_add_generic_get_opts(C, op, loc, rot, NULL, &layer, NULL)) + return OPERATOR_CANCELLED; + + ob = ED_object_add_type(C, OB_EMPTY, loc, rot, FALSE, layer); + ob->empty_drawtype = type; + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_empty_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Empty"; + ot->description = "Add an empty object to the scene"; + ot->idname = "OBJECT_OT_empty_add"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_empty_add_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", empty_drawtype_items, 0, "Type", ""); + + ED_object_add_generic_props(ot, FALSE); +} + /********************* Add Lamp Operator ********************/ static const char *get_lamp_defname(int type) @@ -743,12 +757,10 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op) Object *ob; Lamp *la; int type = RNA_enum_get(op->ptr, "type"); - int enter_editmode; unsigned int layer; float loc[3], rot[3]; - object_add_generic_invoke_options(C, op); - if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, loc, rot, NULL, &layer, NULL)) return OPERATOR_CANCELLED; ob = ED_object_add_type(C, OB_LAMP, loc, rot, FALSE, layer); @@ -793,12 +805,10 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) { Group *group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group")); - int enter_editmode; unsigned int layer; float loc[3], rot[3]; - object_add_generic_invoke_options(C, op); - if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, loc, rot, NULL, &layer, NULL)) return OPERATOR_CANCELLED; if (group) { @@ -834,7 +844,6 @@ void OBJECT_OT_group_instance_add(wmOperatorType *ot) /* api callbacks */ ot->invoke = WM_enum_search_invoke; ot->exec = group_instance_add_exec; - ot->poll = ED_operator_objectmode; /* flags */ @@ -852,13 +861,11 @@ void OBJECT_OT_group_instance_add(wmOperatorType *ot) static int object_speaker_add_exec(bContext *C, wmOperator *op) { Object *ob; - int enter_editmode; unsigned int layer; float loc[3], rot[3]; Scene *scene = CTX_data_scene(C); - object_add_generic_invoke_options(C, op); - if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, loc, rot, NULL, &layer, NULL)) return OPERATOR_CANCELLED; ob = ED_object_add_type(C, OB_SPEAKER, loc, rot, FALSE, layer); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index b62ff676066..bb288462f0f 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -112,6 +112,7 @@ void OBJECT_OT_add_named(struct wmOperatorType *ot); void OBJECT_OT_metaball_add(struct wmOperatorType *ot); void OBJECT_OT_text_add(struct wmOperatorType *ot); void OBJECT_OT_armature_add(struct wmOperatorType *ot); +void OBJECT_OT_empty_add(struct wmOperatorType *ot); void OBJECT_OT_lamp_add(struct wmOperatorType *ot); void OBJECT_OT_effector_add(struct wmOperatorType *ot); void OBJECT_OT_camera_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index cec849efca7..181a98a8896 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -113,6 +113,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_delete); WM_operatortype_append(OBJECT_OT_text_add); WM_operatortype_append(OBJECT_OT_armature_add); + WM_operatortype_append(OBJECT_OT_empty_add); WM_operatortype_append(OBJECT_OT_lamp_add); WM_operatortype_append(OBJECT_OT_camera_add); WM_operatortype_append(OBJECT_OT_speaker_add); From 7e0d1cf65263f1906252fce3a9cd2618e9130920 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 5 Oct 2012 13:06:36 +0000 Subject: [PATCH 109/143] Typo fix: Tooltip for "Offset Factor" for FollowPath constraint referred to "bone" instead of "curve" --- source/blender/makesrna/intern/rna_constraint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 770bdb68e38..f2454a2dcfb 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -1243,7 +1243,7 @@ static void rna_def_constraint_follow_path(BlenderRNA *brna) prop = RNA_def_property(srna, "offset_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "offset_fac"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Offset Factor", "Percentage value defining target position along length of bone"); + RNA_def_property_ui_text(prop, "Offset Factor", "Percentage value defining target position along length of curve"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); prop = RNA_def_property(srna, "forward_axis", PROP_ENUM, PROP_NONE); From 72da7722dd25a8b4d2697cd4c6c3489a872c36a0 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 5 Oct 2012 13:11:16 +0000 Subject: [PATCH 110/143] Fix #32770: iTaSC IK solver not working correct with bones that have stretch with have all rotation axes disabled. --- source/blender/ikplugin/intern/itasc_plugin.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index d88f954345f..c929c97a040 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -1172,10 +1172,8 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) switch (ikchan->jointType & ~IK_TRANSY) { case 0: // fixed bone - if (!(ikchan->jointType & IK_TRANSY)) { - joint += ":F"; - ret = arm->addSegment(joint, parent, KDL::Joint::None, 0.0, tip); - } + joint += ":F"; + ret = arm->addSegment(joint, parent, KDL::Joint::None, 0.0, tip); break; case IK_XDOF: // RX only, get the X rotation From 5baa587a12d7f726b5ec3d937a3196fdb687b976 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 5 Oct 2012 13:22:09 +0000 Subject: [PATCH 111/143] Warning indicators for animators when Auto Keying is enabled during transform Recently on the bf-funboard list, there have been some requests for clearer indications for animators that autokeying has been enabled when transforming so that corrective action can be taken sooner if this wasn't expected. This is especially important in distributed+collaborative environments where multiple artists may work on a single shot file: someone working on a shot from another animator may not be aware that autokeying was enabled, thus accidentally setting a whole bunch of extra keyframes. In this current incarnation, we display using red (not hardcoded, but using an existing theme color) a solid 1px border around the 3D view while transforming with autokeying enabled. In addition to the border, a blinking indicator (record icon + "Auto Keying On" text) appear in the top right corner, as inspired by the traditional recording indicator icons on camcorders. --- source/blender/editors/transform/transform.c | 78 +++++++++++++++++--- source/blender/editors/transform/transform.h | 2 + 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 631418598e5..2bcbbc3a8a2 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -57,6 +57,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "BLF_api.h" + #include "BKE_nla.h" #include "BKE_bmesh.h" #include "BKE_context.h" @@ -88,12 +90,14 @@ #include "BLI_linklist.h" #include "BLI_smallhash.h" #include "BLI_array.h" +#include "PIL_time.h" +#include "UI_interface_icons.h" #include "UI_resources.h" #include "transform.h" -#include +#include // XXX: duplicated??? static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg); static int doEdgeSlide(TransInfo *t, float perc); @@ -827,7 +831,7 @@ int transformEvent(TransInfo *t, wmEvent *event) float mati[3][3] = MAT3_UNITY; char cmode = constraintModeToChar(t); int handled = 1; - + t->redraw |= handleMouseInput(t, &t->mouse, event); if (event->type == MOUSEMOVE) { @@ -1271,10 +1275,13 @@ int transformEvent(TransInfo *t, wmEvent *event) if (t->handleEvent) t->redraw |= t->handleEvent(t, event); - if (handled || t->redraw) + if (handled || t->redraw) { + t->last_update = PIL_check_seconds_timer(); return 0; - else + } + else { return OPERATOR_PASS_THROUGH; + } } int calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], int cent2d[2]) @@ -1557,14 +1564,63 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi drawNonPropEdge(C, t); } -#if 0 -static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *UNUSED(arg)) +/* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */ +static void drawAutoKeyWarning(const struct bContext *C, TransInfo *t, ARegion *ar) { -// TransInfo *t = arg; -// -// drawHelpline(C, t->mval[0], t->mval[1], t); + int show_warning; + + /* red border around the viewport */ + UI_ThemeColor(TH_REDALERT); + + glBegin(GL_LINE_LOOP); + glVertex2f(1, 1); + glVertex2f(1, ar->winy-1); + glVertex2f(ar->winx-1, ar->winy-1); + glVertex2f(ar->winx-1, 1); + glEnd(); + + /* Entire warning should "blink" to catch periphery attention without being overly distracting + * much like how a traditional recording sign in the corner of a camcorder works + * + * - Blink frequency here is 0.5 secs (i.e. a compromise between epilepsy-inducing flicker + too slow to notice). + * We multiply by two to speed up the odd/even time-in-seconds = on/off toggle. + * - Always start with warning shown so that animators are more likely to notice when starting to transform + */ + show_warning = (int)(t->last_update * 2.0) & 1; + + if ((show_warning) || (t->state == TRANS_STARTING)) { + const char printable[] = "Auto Keying On"; + int xco, yco; + + xco = ar->winx - BLF_width_default(printable) - 10; + yco = ar->winy - BLF_height_default(printable) - 10; + + /* red warning text */ + UI_ThemeColor(TH_REDALERT); + BLF_draw_default_ascii(xco, ar->winy - 17, 0.0f, printable, sizeof(printable)); + + /* autokey recording icon... */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + xco -= (ICON_DEFAULT_WIDTH + 2); + UI_icon_draw(xco, yco, ICON_REC); + + glDisable(GL_BLEND); + } +} + +static void drawTransformPixel(const struct bContext *C, ARegion *ar, void *arg) +{ + TransInfo *t = arg; + Scene *scene = t->scene; + Object *ob = OBACT; + + /* draw autokeyframing hint in the corner */ + if (ob && autokeyframe_cfra_can_key(scene, &ob->id)) { + drawAutoKeyWarning(C, t, ar); + } } -#endif void saveTransform(bContext *C, TransInfo *t, wmOperator *op) { @@ -1734,7 +1790,7 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW); t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); - //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL); + t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t); } else if (t->spacetype == SPACE_IMAGE) { diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index e645cb2fed6..40f53423d37 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -322,6 +322,8 @@ typedef struct TransInfo { float auto_values[4]; float axis[3]; float axis_orig[3]; /* TransCon can change 'axis', store the original value here */ + + double last_update; /* Time of last update (in seconds) */ void *view; struct bContext *context; /* Only valid (non null) during an operator called function. */ From b7bb1ef9b95068599d2db9f6b04222ebab788cdf Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 5 Oct 2012 14:05:49 +0000 Subject: [PATCH 112/143] Whitespace edits --- source/blender/editors/animation/keyframing.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index fc2647a51f4..0454e88e320 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1587,7 +1587,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) PointerRNA ptr = {{NULL}}; PropertyRNA *prop = NULL; char *path; - float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap + float cfra = (float)CFRA; short success = 0; int a, index, length, all = RNA_boolean_get(op->ptr, "all"); short flag = 0; @@ -1758,20 +1758,20 @@ static int clear_key_button_exec(bContext *C, wmOperator *op) if (ptr.id.data && ptr.data && prop) { path = RNA_path_from_ID_to_property(&ptr, prop); - + if (path) { if (all) { length = RNA_property_array_length(&ptr, prop); - + if (length) index = 0; else length = 1; } else length = 1; - + for (a = 0; a < length; a++) success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, 0); - + MEM_freeN(path); } else if (G.debug & G_DEBUG) @@ -1785,9 +1785,9 @@ static int clear_key_button_exec(bContext *C, wmOperator *op) if (success) { /* send updates */ uiContextAnimUpdate(C); - + DAG_ids_flush_update(bmain, 0); - + /* send notifiers that keyframes have been changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } From b2a5f28421b73949b3267f2779bdcc72cd39d639 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 5 Oct 2012 14:51:35 +0000 Subject: [PATCH 113/143] Follow Path Constraint - "Animate Path" Operator Added a convenience operator to the Follow Path constraint which adds a F-Curve for the path (or the operator's "fixed position" value if no path is assigned), with options for setting the start frame and length of motion. This makes it easier for common users to just set up a quick follow-path animation where the camera (e.g. flying around a set over certain number of frames). A key advantage of this is that it takes care of the underlying math required for setting up the generator curve accordingly (I've got some plans for making this a bit friendlier to use later). Now, animating the paths is a one-click operation, with the start and length properties able to be controlled using the operator properties. --- .../bl_ui/properties_object_constraint.py | 1 + .../editors/object/object_constraint.c | 127 ++++++++++++++++++ source/blender/editors/object/object_intern.h | 1 + source/blender/editors/object/object_ops.c | 1 + 4 files changed, 130 insertions(+) diff --git a/release/scripts/startup/bl_ui/properties_object_constraint.py b/release/scripts/startup/bl_ui/properties_object_constraint.py index 3d671a0d1b7..fba7bd8712a 100644 --- a/release/scripts/startup/bl_ui/properties_object_constraint.py +++ b/release/scripts/startup/bl_ui/properties_object_constraint.py @@ -212,6 +212,7 @@ class ConstraintButtonsPanel(): def FOLLOW_PATH(self, context, layout, con): self.target_template(layout, con) + layout.operator("constraint.followpath_path_animate", text="Animate Path", icon='ANIM_DATA') split = layout.split() diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 1ef7c12b409..b7aadd3cc74 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -40,6 +40,7 @@ #include "BLI_dynstr.h" #include "BLI_utildefines.h" +#include "DNA_anim_types.h" #include "DNA_constraint_types.h" #include "DNA_curve_types.h" #include "DNA_scene_types.h" @@ -51,6 +52,7 @@ #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_object.h" @@ -71,6 +73,7 @@ #include "ED_object.h" #include "ED_armature.h" +#include "ED_keyframing.h" #include "ED_screen.h" #include "UI_interface.h" @@ -877,6 +880,130 @@ void CONSTRAINT_OT_childof_clear_inverse(wmOperatorType *ot) edit_constraint_properties(ot); } +/* --------------- Follow Path Constraint ------------------ */ + +static int followpath_path_animate_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_FOLLOWPATH); + bFollowPathConstraint *data = (con) ? (bFollowPathConstraint *)con->data : NULL; + + bAction *act = NULL; + FCurve *fcu = NULL; + int sfra = RNA_int_get(op->ptr, "frame_start"); + int len = RNA_int_get(op->ptr, "length"); + float standardRange = 1.0; + + /* nearly impossible sanity check */ + if (data == NULL) { + BKE_report(op->reports, RPT_ERROR, "Follow Path constraint not found"); + return OPERATOR_CANCELLED; + } + + /* add F-Curve as appropriate */ + if (data->tar) { + Curve *cu = (Curve *)data->tar->data; + + if ( ELEM(NULL, cu->adt, cu->adt->action) || + (list_find_fcurve(&cu->adt->action->curves, "eval_time", 0) == NULL)) + { + /* create F-Curve for path animation */ + act = verify_adt_action(&cu->id, 1); + fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1); + + /* standard vertical range - 1:1 = 100 frames */ + standardRange = 100.0f; + } + else { + /* path anim exists already - abort for now as this may well be what was intended */ + BKE_report(op->reports, RPT_WARNING, "Path is already animated"); + return OPERATOR_CANCELLED; + } + } + else { + /* animate constraint's "fixed offset" */ + PointerRNA ptr; + PropertyRNA *prop; + char *path; + + /* get RNA pointer to constraint's "offset_factor" property - to build RNA path */ + RNA_pointer_create(&ob->id, &RNA_FollowPathConstraint, con, &ptr); + prop = RNA_struct_find_property(&ptr, "offset_factor"); + + path = RNA_path_from_ID_to_property(&ptr, prop); + + /* create F-Curve for constraint */ + act = verify_adt_action(&ob->id, 1); + fcu = verify_fcurve(act, NULL, NULL, path, 0, 1); + + /* standard vertical range - 0.0 to 1.0 */ + standardRange = 1.0f; + + /* enable "Use Fixed Position" so that animating this has effect */ + data->followflag |= FOLLOWPATH_STATIC; + + /* path needs to be freed */ + if (path) + MEM_freeN(path); + } + + /* setup dummy 'generator' modifier here to get 1-1 correspondence still working + * and define basic slope of this curve based on the properties + */ + if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) { + FModifier *fcm = add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); + FMod_Generator *gen = fcm->data; + + /* Assume that we have the following equation: + * y = Ax + B + * 1 0 <-- coefficients array indices + */ + float A = standardRange / (float)(len); + float B = (float)(-sfra) * A; + + gen->coefficients[1] = A; + gen->coefficients[0] = B; + } + + /* updates... */ + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + return OPERATOR_FINISHED; +} + +static int followpath_path_animate_invoke(bContext *C, wmOperator *op, wmEvent *evt) +{ + /* hook up invoke properties for figuring out which constraint we're dealing with */ + if (edit_constraint_invoke_properties(C, op)) { + return followpath_path_animate_exec(C, op); + } + else { + return OPERATOR_CANCELLED; + } +} + +void CONSTRAINT_OT_followpath_path_animate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Auto Animate Path"; + ot->idname = "CONSTRAINT_OT_followpath_path_animate"; + ot->description = "Add default animation for path used by constraint if it isn't animated already"; + + /* callbacks */ + ot->invoke = followpath_path_animate_invoke; + ot->exec = followpath_path_animate_exec; + ot->poll = edit_constraint_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + edit_constraint_properties(ot); + RNA_def_int(ot->srna, "frame_start", 1, MINAFRAME, MAXFRAME, "Start Frame", + "First frame of path animation", MINAFRAME, MAXFRAME); + RNA_def_int(ot->srna, "length", 100, 0, MAXFRAME, "Length", + "Number of frames that path animation should take", 0, MAXFRAME); +} + /* ------------- Object Solver Constraint ------------------ */ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index bb288462f0f..4c83f6ef2ce 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -194,6 +194,7 @@ void CONSTRAINT_OT_childof_set_inverse(struct wmOperatorType *ot); void CONSTRAINT_OT_childof_clear_inverse(struct wmOperatorType *ot); void CONSTRAINT_OT_objectsolver_set_inverse(struct wmOperatorType *ot); void CONSTRAINT_OT_objectsolver_clear_inverse(struct wmOperatorType *ot); +void CONSTRAINT_OT_followpath_path_animate(struct wmOperatorType *ot); /* object_vgroup.c */ void OBJECT_OT_vertex_group_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 181a98a8896..fa40d579e2b 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -169,6 +169,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(CONSTRAINT_OT_childof_clear_inverse); WM_operatortype_append(CONSTRAINT_OT_objectsolver_set_inverse); WM_operatortype_append(CONSTRAINT_OT_objectsolver_clear_inverse); + WM_operatortype_append(CONSTRAINT_OT_followpath_path_animate); WM_operatortype_append(OBJECT_OT_vertex_group_add); WM_operatortype_append(OBJECT_OT_vertex_group_remove); From b67d75fad29ce2dfa4ef0aee271b6e86518a3d6b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 5 Oct 2012 14:54:32 +0000 Subject: [PATCH 114/143] Fix generated texture coordinate issue after "from dupli" option was added. --- intern/cycles/render/nodes.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index b878bdee3c7..8173f5d0af2 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1644,6 +1644,8 @@ TextureCoordinateNode::TextureCoordinateNode() add_output("Camera", SHADER_SOCKET_POINT); add_output("Window", SHADER_SOCKET_POINT); add_output("Reflection", SHADER_SOCKET_NORMAL); + + from_dupli = false; } void TextureCoordinateNode::attributes(AttributeRequestSet *attributes) From d3cdaca648740ec6e11aebecc243442aa5ae7142 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 5 Oct 2012 14:56:04 +0000 Subject: [PATCH 115/143] Code cleanup * Added/fixed some comments * Swapped order that invoke/exec calls are defined in the operator definitions to reflect flow better --- .../editors/object/object_constraint.c | 52 +++++++++++++------ 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index b7aadd3cc74..6acb5c63365 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -658,12 +658,15 @@ void CONSTRAINT_OT_stretchto_reset(wmOperatorType *ot) ot->idname = "CONSTRAINT_OT_stretchto_reset"; ot->description = "Reset original length of bone for Stretch To Constraint"; - ot->exec = stretchto_reset_exec; + /* callbacks */ ot->invoke = stretchto_reset_invoke; + ot->exec = stretchto_reset_exec; ot->poll = edit_constraint_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ edit_constraint_properties(ot); } @@ -701,12 +704,15 @@ void CONSTRAINT_OT_limitdistance_reset(wmOperatorType *ot) ot->idname = "CONSTRAINT_OT_limitdistance_reset"; ot->description = "Reset limiting distance for Limit Distance Constraint"; - ot->exec = limitdistance_reset_exec; + /* callbacks */ ot->invoke = limitdistance_reset_invoke; + ot->exec = limitdistance_reset_exec; ot->poll = edit_constraint_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ edit_constraint_properties(ot); } @@ -827,12 +833,15 @@ void CONSTRAINT_OT_childof_set_inverse(wmOperatorType *ot) ot->idname = "CONSTRAINT_OT_childof_set_inverse"; ot->description = "Set inverse correction for ChildOf constraint"; - ot->exec = childof_set_inverse_exec; + /* callbacks */ ot->invoke = childof_set_inverse_invoke; + ot->exec = childof_set_inverse_exec; ot->poll = edit_constraint_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ edit_constraint_properties(ot); } @@ -871,12 +880,15 @@ void CONSTRAINT_OT_childof_clear_inverse(wmOperatorType *ot) ot->idname = "CONSTRAINT_OT_childof_clear_inverse"; ot->description = "Clear inverse correction for ChildOf constraint"; - ot->exec = childof_clear_inverse_exec; + /* callbacks */ ot->invoke = childof_clear_inverse_invoke; + ot->exec = childof_clear_inverse_exec; ot->poll = edit_constraint_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ edit_constraint_properties(ot); } @@ -1041,13 +1053,16 @@ void CONSTRAINT_OT_objectsolver_set_inverse(wmOperatorType *ot) ot->name = "Set Inverse"; ot->idname = "CONSTRAINT_OT_objectsolver_set_inverse"; ot->description = "Set inverse correction for ObjectSolver constraint"; - - ot->exec = objectsolver_set_inverse_exec; + + /* callbacks */ ot->invoke = objectsolver_set_inverse_invoke; + ot->exec = objectsolver_set_inverse_exec; ot->poll = edit_constraint_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ edit_constraint_properties(ot); } @@ -1084,13 +1099,16 @@ void CONSTRAINT_OT_objectsolver_clear_inverse(wmOperatorType *ot) ot->name = "Clear Inverse"; ot->idname = "CONSTRAINT_OT_objectsolver_clear_inverse"; ot->description = "Clear inverse correction for ObjectSolver constraint"; - - ot->exec = objectsolver_clear_inverse_exec; + + /* callbacks */ ot->invoke = objectsolver_clear_inverse_invoke; + ot->exec = objectsolver_clear_inverse_exec; ot->poll = edit_constraint_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ edit_constraint_properties(ot); } @@ -1110,13 +1128,14 @@ void ED_object_constraint_set_active(Object *ob, bConstraint *con) void ED_object_constraint_update(Object *ob) { - if (ob->pose) BKE_pose_update_constraint_flags(ob->pose); object_test_constraints(ob); - if (ob->type == OB_ARMATURE) DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB); - else DAG_id_tag_update(&ob->id, OB_RECALC_OB); + if (ob->type == OB_ARMATURE) + DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB); + else + DAG_id_tag_update(&ob->id, OB_RECALC_OB); } void ED_object_constraint_dependency_update(Main *bmain, Scene *scene, Object *ob) @@ -1133,6 +1152,7 @@ static int constraint_poll(bContext *C) return (ptr.id.data && ptr.data); } + static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) { PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); @@ -1147,12 +1167,12 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) constraints_set_active(lb, NULL); ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */ - + /* ITASC needs to be rebuilt once a constraint is removed [#26920] */ if (is_ik) { BIK_clear_data(ob->pose); } - + /* notifiers */ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); @@ -1179,6 +1199,7 @@ void CONSTRAINT_OT_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + static int constraint_move_down_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_active_context(C); @@ -1208,7 +1229,6 @@ static int constraint_move_down_invoke(bContext *C, wmOperator *op, wmEvent *UNU return OPERATOR_CANCELLED; } - void CONSTRAINT_OT_move_down(wmOperatorType *ot) { /* identifiers */ @@ -1217,12 +1237,14 @@ void CONSTRAINT_OT_move_down(wmOperatorType *ot) ot->description = "Move constraint down in constraint stack"; /* callbacks */ - ot->exec = constraint_move_down_exec; ot->invoke = constraint_move_down_invoke; + ot->exec = constraint_move_down_exec; ot->poll = edit_constraint_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ edit_constraint_properties(ot); } From db70bfc206538a9582e17a3eedcd1923e3f8d2c8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 15:44:11 +0000 Subject: [PATCH 116/143] code cleanup: use functions to initialize selection user data structs, use radius-squared for circle select comparisons. edge_fully_inside_rect() & edge_inside_rect() args were shorts when all callers were passing ints. --- source/blender/blenlib/BLI_lasso.h | 6 +- source/blender/blenlib/intern/lasso.c | 8 +- source/blender/editors/include/ED_mesh.h | 2 +- source/blender/editors/include/ED_particle.h | 2 +- source/blender/editors/include/ED_view3d.h | 3 + source/blender/editors/mask/mask_select.c | 4 +- source/blender/editors/mesh/editmesh_select.c | 4 +- .../editors/object/object_constraint.c | 2 +- .../blender/editors/physics/particle_edit.c | 2 +- .../editors/space_clip/tracking_select.c | 4 +- .../blender/editors/space_node/node_select.c | 4 +- .../editors/space_view3d/view3d_select.c | 228 ++++++++++-------- source/blender/editors/transform/transform.c | 6 +- source/blender/editors/uvedit/uvedit_ops.c | 4 +- source/blender/windowmanager/WM_api.h | 2 +- .../windowmanager/intern/wm_operators.c | 5 +- 16 files changed, 156 insertions(+), 130 deletions(-) diff --git a/source/blender/blenlib/BLI_lasso.h b/source/blender/blenlib/BLI_lasso.h index 85a000b000c..a7e90a51e86 100644 --- a/source/blender/blenlib/BLI_lasso.h +++ b/source/blender/blenlib/BLI_lasso.h @@ -34,8 +34,8 @@ struct rcti; -void BLI_lasso_boundbox(struct rcti *rect, int mcords[][2], short moves); -int BLI_lasso_is_point_inside(int mcords[][2], short moves, const int sx, const int sy, const int error_value); -int BLI_lasso_is_edge_inside(int mcords[][2], short moves, int x0, int y0, int x1, int y1, const int error_value); +void BLI_lasso_boundbox(struct rcti *rect, const int mcords[][2], const short moves); +int BLI_lasso_is_point_inside(const int mcords[][2], const short moves, const int sx, const int sy, const int error_value); +int BLI_lasso_is_edge_inside(const int mcords[][2], const short moves, int x0, int y0, int x1, int y1, const int error_value); #endif diff --git a/source/blender/blenlib/intern/lasso.c b/source/blender/blenlib/intern/lasso.c index 7df4da80e16..5cd8bb813a1 100644 --- a/source/blender/blenlib/intern/lasso.c +++ b/source/blender/blenlib/intern/lasso.c @@ -37,7 +37,7 @@ #include "BLI_lasso.h" /* own include */ -void BLI_lasso_boundbox(rcti *rect, int mcords[][2], short moves) +void BLI_lasso_boundbox(rcti *rect, const int mcords[][2], const short moves) { short a; @@ -53,14 +53,14 @@ void BLI_lasso_boundbox(rcti *rect, int mcords[][2], short moves) } -int BLI_lasso_is_point_inside(int mcords[][2], short moves, +int BLI_lasso_is_point_inside(const int mcords[][2], const short moves, const int sx, const int sy, const int error_value) { /* we do the angle rule, define that all added angles should be about zero or (2 * PI) */ float angletot = 0.0, dot, ang, cross, fp1[2], fp2[2]; int a; - int *p1, *p2; + const int *p1, *p2; if (sx == error_value) { return 0; @@ -100,7 +100,7 @@ int BLI_lasso_is_point_inside(int mcords[][2], short moves, } /* edge version for lasso select. we assume boundbox check was done */ -int BLI_lasso_is_edge_inside(int mcords[][2], short moves, +int BLI_lasso_is_edge_inside(const int mcords[][2], const short moves, int x0, int y0, int x1, int y1, const int error_value) { diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 62818612509..028b5db6beb 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -138,7 +138,7 @@ int EDBM_backbuf_border_init(struct ViewContext *vc, short xmin, short ymin, sh int EDBM_backbuf_check(unsigned int index); void EDBM_backbuf_free(void); -int EDBM_backbuf_border_mask_init(struct ViewContext *vc, int mcords[][2], short tot, +int EDBM_backbuf_border_mask_init(struct ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax); int EDBM_backbuf_circle_init(struct ViewContext *vc, short xs, short ys, short rads); diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index 0076b08da99..dee97c7882a 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -61,7 +61,7 @@ void PE_update_object(struct Scene *scene, struct Object *ob, int useflag); int PE_mouse_particles(struct bContext *C, const int mval[2], int extend, int deselect, int toggle); int PE_border_select(struct bContext *C, struct rcti *rect, int select, int extend); int PE_circle_select(struct bContext *C, int selecting, const int mval[2], float rad); -int PE_lasso_select(struct bContext *C, int mcords[][2], short moves, short extend, short select); +int PE_lasso_select(struct bContext *C, const int mcords[][2], const short moves, short extend, short select); void PE_deselect_all_visible(struct PTCacheEdit *edit); /* undo */ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index acc53861e95..8161dd23b8e 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -40,6 +40,7 @@ struct BPoint; struct BezTriple; struct BezTriple; struct BoundBox; +struct EditBone; struct ImBuf; struct MVert; struct Main; @@ -170,6 +171,8 @@ void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct BMFace *efa, int x, int y, int index), void *userData); void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData); void lattice_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData); +void armature_foreachScreenBone(struct ViewContext *vc, void (*func)(void *userData, struct EditBone *ebone, int x0, int y0, int x1, int y1), void *userData); + void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, const struct rcti *rect); void ED_view3d_clipping_local(struct RegionView3D *rv3d, float mat[][4]); diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index 55bad39f4f2..69cfdf4e51b 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -485,7 +485,7 @@ void MASK_OT_select_border(wmOperatorType *ot) WM_operator_properties_gesture_border(ot, TRUE); } -static int do_lasso_select_mask(bContext *C, int mcords[][2], short moves, short select) +static int do_lasso_select_mask(bContext *C, const int mcords[][2], short moves, short select) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); @@ -549,7 +549,7 @@ static int do_lasso_select_mask(bContext *C, int mcords[][2], short moves, short static int clip_lasso_select_exec(bContext *C, wmOperator *op) { int mcords_tot; - int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); if (mcords) { short select; diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index abc8cb6b327..801c9382c26 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -131,7 +131,7 @@ unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0; /* set in dr static char *selbuf = NULL; /* opengl doesn't support concave... */ -static void draw_triangulated(int mcords[][2], short tot) +static void draw_triangulated(const int mcords[][2], const short tot) { ListBase lb = {NULL, NULL}; DispList *dl; @@ -227,7 +227,7 @@ void EDBM_backbuf_free(void) * - grab again and compare * returns 'OK' */ -int EDBM_backbuf_border_mask_init(ViewContext *vc, int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax) +int EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax) { unsigned int *dr, *drm; struct ImBuf *buf, *bufmask; diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 6acb5c63365..56f2426b1b0 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -982,7 +982,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int followpath_path_animate_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int followpath_path_animate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) { /* hook up invoke properties for figuring out which constraint we're dealing with */ if (edit_constraint_invoke_properties(C, op)) { diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index b03c637e67c..ee2b5e08520 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -1633,7 +1633,7 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad) /************************ lasso select operator ************************/ -int PE_lasso_select(bContext *C, int mcords[][2], short moves, short extend, short select) +int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, short extend, short select) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index 507e492497d..4f62d3fdc2f 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -413,7 +413,7 @@ void CLIP_OT_select_border(wmOperatorType *ot) /********************** lasso select operator *********************/ -static int do_lasso_select_marker(bContext *C, int mcords[][2], short moves, short select) +static int do_lasso_select_marker(bContext *C, const int mcords[][2], const short moves, short select) { SpaceClip *sc = CTX_wm_space_clip(C); ARegion *ar = CTX_wm_region(C); @@ -469,7 +469,7 @@ static int do_lasso_select_marker(bContext *C, int mcords[][2], short moves, sho static int clip_lasso_select_exec(bContext *C, wmOperator *op) { int mcords_tot; - int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); if (mcords) { short select; diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index f7757ce49b4..b0916a50c37 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -539,7 +539,7 @@ void NODE_OT_select_border(wmOperatorType *ot) /* ****** Lasso Select ****** */ -static int do_lasso_select_node(bContext *C, int mcords[][2], short moves, short select) +static int do_lasso_select_node(bContext *C, const int mcords[][2], short moves, short select) { SpaceNode *snode = CTX_wm_space_node(C); bNode *node; @@ -585,7 +585,7 @@ static int do_lasso_select_node(bContext *C, int mcords[][2], short moves, short static int node_lasso_select_exec(bContext *C, wmOperator *op) { int mcords_tot; - int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); if (mcords) { short select; diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 926c19df95a..a9eee92c442 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -256,10 +256,33 @@ static void edbm_backbuf_check_and_select_tfaces(Mesh *me, int select) typedef struct LassoSelectUserData { ViewContext *vc; - rcti *rect; - int (*mcords)[2], moves, select, pass, done; + const rcti *rect; + const int (*mcords)[2]; + int moves; + int select; + + /* runtime */ + int pass; + int is_done; + int is_change; } LassoSelectUserData; +static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, + ViewContext *vc, const rcti *rect, const int (*mcords)[2], + const int moves, const int select) +{ + r_data->vc = vc; + r_data->rect = rect; + r_data->mcords = mcords; + r_data->moves = moves; + r_data->select = select; + + /* runtime */ + r_data->pass = 0; + r_data->is_done = FALSE; + r_data->is_change = FALSE; +} + static int view3d_selectable_data(bContext *C) { Object *ob = CTX_data_active_object(C); @@ -290,12 +313,12 @@ static int view3d_selectable_data(bContext *C) /* helper also for borderselect */ -static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2) +static int edge_fully_inside_rect(const rcti *rect, int x1, int y1, int x2, int y2) { return BLI_rcti_isect_pt(rect, x1, y1) && BLI_rcti_isect_pt(rect, x2, y2); } -static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2) +static int edge_inside_rect(const rcti *rect, int x1, int y1, int x2, int y2) { int d1, d2, d3, d4; @@ -323,7 +346,7 @@ static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2) /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) * and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK */ -static void do_lasso_select_pose(ViewContext *vc, Object *ob, int mcords[][2], short moves, short select) +static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves, short select) { bPoseChannel *pchan; bArmature *arm = ob->data; @@ -390,7 +413,7 @@ static void object_deselect_all_visible(Scene *scene, View3D *v3d) } } -static void do_lasso_select_objects(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_objects(ViewContext *vc, const int mcords[][2], const short moves, short extend, short select) { Base *base; @@ -434,7 +457,7 @@ static void do_lasso_select_mesh__doSelectEdge(void *userData, BMEdge *eed, int BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, IS_CLIPPED)) { BM_edge_select_set(data->vc->em->bm, eed, data->select); - data->done = TRUE; + data->is_done = TRUE; } } else { @@ -455,7 +478,7 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, int } } -static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { LassoSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; @@ -467,13 +490,7 @@ static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, /* set editmesh */ vc->em = BMEdit_FromObject(vc->obedit); - data.vc = vc; - data.rect = ▭ - data.mcords = mcords; - data.moves = moves; - data.select = select; - data.done = FALSE; - data.pass = 0; + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); if (extend == 0 && select) EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT); @@ -497,7 +514,7 @@ static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, data.pass = 0; mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_CLIP_TEST_OFF); - if (data.done == 0) { + if (data.is_done == 0) { data.pass = 1; mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_CLIP_TEST_OFF); } @@ -549,15 +566,11 @@ static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BP } } -static void do_lasso_select_curve(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { LassoSelectUserData data; - /* set vc->editnurb */ - data.vc = vc; - data.mcords = mcords; - data.moves = moves; - data.select = select; + view3d_userdata_lassoselect_init(&data, vc, NULL, mcords, moves, select); if (extend == 0 && select) CU_deselect_all(vc->obedit); @@ -574,14 +587,11 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); } } -static void do_lasso_select_lattice(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { LassoSelectUserData data; - /* set editdata in vc */ - data.mcords = mcords; - data.moves = moves; - data.select = select; + view3d_userdata_lassoselect_init(&data, vc, NULL, mcords, moves, select); if (extend == 0 && select) ED_setflagsLatt(vc->obedit, 0); @@ -590,7 +600,7 @@ static void do_lasso_select_lattice(ViewContext *vc, int mcords[][2], short move lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data); } -static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { bArmature *arm = vc->obedit->data; EditBone *ebone; @@ -656,7 +666,7 @@ static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short mov } -static void do_lasso_select_meta(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { MetaBall *mb = (MetaBall *)vc->obedit->data; MetaElem *ml; @@ -742,7 +752,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int return OPERATOR_FINISHED; } -static void do_lasso_select_paintvert(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { Object *ob = vc->obact; Mesh *me = ob ? ob->data : NULL; @@ -764,7 +774,7 @@ static void do_lasso_select_paintvert(ViewContext *vc, int mcords[][2], short mo paintvert_flush_flags(ob); } -static void do_lasso_select_paintface(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { Object *ob = vc->obact; Mesh *me = ob ? ob->data : NULL; @@ -819,7 +829,9 @@ static void do_lasso_select_node(int mcords[][2], short moves, short select) } #endif -static void view3d_lasso_select(bContext *C, ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void view3d_lasso_select(bContext *C, ViewContext *vc, + const int mcords[][2], short moves, + short extend, short select) { Object *ob = CTX_data_active_object(C); @@ -870,7 +882,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) { ViewContext vc; int mcords_tot; - int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); if (mcords) { short extend, select; @@ -1553,19 +1565,37 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese typedef struct BoxSelectUserData { ViewContext *vc; - rcti *rect; - int select, pass, done; + const rcti *rect; + int select; + + /* runtime */ + int pass; + int is_done; + int is_change; } BoxSelectUserData; -int edge_inside_circle(int centx, int centy, int rad, int x1, int y1, int x2, int y2) +static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, + ViewContext *vc, const rcti *rect, const int select) { - int radsq = rad * rad; + r_data->vc = vc; + r_data->rect = rect; + r_data->select = select; + + /* runtime */ + r_data->pass = 0; + r_data->is_done = FALSE; + r_data->is_change = FALSE; +} + +int edge_inside_circle(int centx, int centy, int radius, int x1, int y1, int x2, int y2) +{ + int radius_squared = radius * radius; /* check points in circle itself */ - if ((x1 - centx) * (x1 - centx) + (y1 - centy) * (y1 - centy) <= radsq) { + if ((x1 - centx) * (x1 - centx) + (y1 - centy) * (y1 - centy) <= radius_squared) { return TRUE; } - else if ((x2 - centx) * (x2 - centx) + (y2 - centy) * (y2 - centy) <= radsq) { + else if ((x2 - centx) * (x2 - centx) + (y2 - centy) * (y2 - centy) <= radius_squared) { return TRUE; } else { @@ -1573,7 +1603,7 @@ int edge_inside_circle(int centx, int centy, int rad, int x1, int y1, int x2, in const float v1[2] = {x1, y1}; const float v2[2] = {x2, y2}; /* pointdistline */ - if (dist_squared_to_line_segment_v2(cent, v1, v2) < (float)radsq) { + if (dist_squared_to_line_segment_v2(cent, v1, v2) < (float)radius_squared) { return TRUE; } } @@ -1617,9 +1647,7 @@ static int do_nurbs_box_select(ViewContext *vc, rcti *rect, int select, int exte { BoxSelectUserData data; - data.vc = vc; - data.rect = rect; - data.select = select; + view3d_userdata_boxselect_init(&data, vc, rect, select); if (extend == 0 && select) CU_deselect_all(vc->obedit); @@ -1642,9 +1670,7 @@ static int do_lattice_box_select(ViewContext *vc, rcti *rect, int select, int ex { BoxSelectUserData data; - data.vc = vc; - data.rect = rect; - data.select = select; + view3d_userdata_boxselect_init(&data, vc, rect, select); if (extend == 0 && select) ED_setflagsLatt(vc->obedit, 0); @@ -1671,7 +1697,7 @@ static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, int x0 if (data->pass == 0) { if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) { BM_edge_select_set(data->vc->em->bm, eed, data->select); - data->done = TRUE; + data->is_done = TRUE; } } else { @@ -1695,11 +1721,7 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int exten ToolSettings *ts = vc->scene->toolsettings; int bbsel; - data.vc = vc; - data.rect = rect; - data.select = select; - data.pass = 0; - data.done = FALSE; + view3d_userdata_boxselect_init(&data, vc, rect, select); if (extend == 0 && select) EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT); @@ -1724,7 +1746,7 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int exten data.pass = 0; mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_CLIP_TEST_OFF); - if (data.done == 0) { + if (data.is_done == 0) { data.pass = 1; mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_CLIP_TEST_OFF); } @@ -2182,15 +2204,32 @@ typedef struct CircleSelectUserData { short select; int mval[2]; float radius; + float radius_squared; + + /* runtime */ + int is_change; } CircleSelectUserData; +static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, + ViewContext *vc, const int select, const int mval[2], const float rad) +{ + r_data->vc = vc; + r_data->select = select; + copy_v2_v2_int(r_data->mval, mval); + r_data->radius = rad; + r_data->radius_squared = rad * rad; + + /* runtime */ + r_data->is_change = FALSE; +} + static void mesh_circle_doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index)) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; - if (r <= data->radius) { + if (len_squared_v2(delta) <= data->radius_squared) { BM_vert_select_set(data->vc->em->bm, eve, data->select); } } @@ -2205,10 +2244,10 @@ static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, int x0, int y0 static void mesh_circle_doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index)) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); - - if (r <= data->radius) { + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; + + if (len_squared_v2(delta) <= data->radius_squared) { BM_face_select_set(data->vc->em->bm, efa, data->select); } } @@ -2224,11 +2263,7 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f vc->em = BMEdit_FromObject(vc->obedit); - data.vc = vc; - data.select = select; - data.mval[0] = mval[0]; - data.mval[1] = mval[1]; - data.radius = rad; + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); if (ts->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { @@ -2299,12 +2334,13 @@ static void paint_vertsel_circle_select(ViewContext *vc, int select, const int m static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); Object *obedit = data->vc->obedit; Curve *cu = (Curve *)obedit->data; - if (r <= data->radius) { + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; + + if (len_squared_v2(delta) <= data->radius_squared) { if (bp) { bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); @@ -2342,6 +2378,7 @@ static void nurbscurve_circle_select(ViewContext *vc, int select, const int mval data.mval[1] = mval[1]; data.radius = rad; data.vc = vc; + data.is_change = FALSE; ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data); @@ -2351,10 +2388,10 @@ static void nurbscurve_circle_select(ViewContext *vc, int select, const int mval static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; - if (r <= data->radius) { + if (len_squared_v2(delta) <= data->radius_squared) { bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); } } @@ -2362,12 +2399,7 @@ static void lattice_circle_select(ViewContext *vc, int select, const int mval[2] { CircleSelectUserData data; - /* set vc-> edit data */ - - data.select = select; - data.mval[0] = mval[0]; - data.mval[1] = mval[1]; - data.radius = rad; + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data); @@ -2378,10 +2410,10 @@ static void lattice_circle_select(ViewContext *vc, int select, const int mval[2] static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, int x, int y) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); - - if (r <= data->radius) { + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; + + if (len_squared_v2(delta) <= data->radius_squared) { if (data->select) pchan->bone->flag |= BONE_SELECTED; else @@ -2396,13 +2428,8 @@ static void pose_circle_select(ViewContext *vc, int select, const int mval[2], f bArmature *arm = vc->obact->data; bPose *pose = vc->obact->pose; bPoseChannel *pchan; - int change = FALSE; - /* set vc->edit data */ - data.select = select; - data.mval[0] = mval[0]; - data.mval[1] = mval[1]; - data.radius = rad; + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */ @@ -2446,14 +2473,14 @@ static void pose_circle_select(ViewContext *vc, int select, const int mval[2], f pchan->bone->flag |= BONE_SELECTED; else pchan->bone->flag &= ~BONE_SELECTED; - change = TRUE; + data.is_change = TRUE; } - change |= is_point_done; + data.is_change |= is_point_done; } } - if (change) { + if (data.is_change) { WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obact); } } @@ -2461,10 +2488,10 @@ static void pose_circle_select(ViewContext *vc, int select, const int mval[2], f static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, int x, int y, short head) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; - if (r <= data->radius) { + if (len_squared_v2(delta) <= data->radius_squared) { if (head) { if (data->select) ebone->flag |= BONE_ROOTSEL; @@ -2486,13 +2513,8 @@ static void armature_circle_select(ViewContext *vc, int select, const int mval[2 CircleSelectUserData data; bArmature *arm = vc->obedit->data; EditBone *ebone; - int change = FALSE; - - /* set vc->edit data */ - data.select = select; - data.mval[0] = mval[0]; - data.mval[1] = mval[1]; - data.radius = rad; + + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ @@ -2539,14 +2561,14 @@ static void armature_circle_select(ViewContext *vc, int select, const int mval[2 ebone->flag |= BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED; else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - change = TRUE; + data.is_change = TRUE; } - change |= is_point_done; + data.is_change |= is_point_done; } } - if (change) { + if (data.is_change) { ED_armature_sync_selection(arm->edbo); ED_armature_validate_active(arm); WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obedit); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 2bcbbc3a8a2..be568fcb9d8 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1565,7 +1565,7 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi } /* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */ -static void drawAutoKeyWarning(const struct bContext *C, TransInfo *t, ARegion *ar) +static void drawAutoKeyWarning(TransInfo *t, ARegion *ar) { int show_warning; @@ -1610,7 +1610,7 @@ static void drawAutoKeyWarning(const struct bContext *C, TransInfo *t, ARegion * } } -static void drawTransformPixel(const struct bContext *C, ARegion *ar, void *arg) +static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, void *arg) { TransInfo *t = arg; Scene *scene = t->scene; @@ -1618,7 +1618,7 @@ static void drawTransformPixel(const struct bContext *C, ARegion *ar, void *arg) /* draw autokeyframing hint in the corner */ if (ob && autokeyframe_cfra_can_key(scene, &ob->id)) { - drawAutoKeyWarning(C, t, ar); + drawAutoKeyWarning(t, ar); } } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 70f2bf70ec8..f732808fa59 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -2745,7 +2745,7 @@ static void UV_OT_circle_select(wmOperatorType *ot) /* ******************** lasso select operator **************** */ -static int do_lasso_select_mesh_uv(bContext *C, int mcords[][2], short moves, short select) +static int do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves, short select) { Image *ima = CTX_data_edit_image(C); ARegion *ar = CTX_wm_region(C); @@ -2819,7 +2819,7 @@ static int do_lasso_select_mesh_uv(bContext *C, int mcords[][2], short moves, sh static int uv_lasso_select_exec(bContext *C, wmOperator *op) { int mcords_tot; - int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); if (mcords) { short select; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index ac05331095b..e7b7f679ce3 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -273,7 +273,7 @@ int WM_gesture_lines_cancel(struct bContext *C, struct wmOperator *op); int WM_gesture_lasso_invoke(struct bContext *C, struct wmOperator *op, struct wmEvent *event); int WM_gesture_lasso_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event); int WM_gesture_lasso_cancel(struct bContext *C, struct wmOperator *op); -int (*WM_gesture_lasso_path_to_array(struct bContext *C, struct wmOperator *op, int *mcords_tot))[2]; +const int (*WM_gesture_lasso_path_to_array(struct bContext *C, struct wmOperator *op, int *mcords_tot))[2]; int WM_gesture_straightline_invoke(struct bContext *C, struct wmOperator *op, struct wmEvent *event); int WM_gesture_straightline_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event); int WM_gesture_straightline_cancel(struct bContext *C, struct wmOperator *op); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 313fc0a819e..9de3c15d70f 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -2727,7 +2727,7 @@ int WM_gesture_lines_cancel(bContext *C, wmOperator *op) * * caller must free. */ -int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, int *mcords_tot))[2] +const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, int *mcords_tot))[2] { PropertyRNA *prop = RNA_struct_find_property(op->ptr, "path"); int (*mcords)[2] = NULL; @@ -2757,7 +2757,8 @@ int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, int *m *mcords_tot = 0; } - return mcords; + /* cast for 'const' */ + return (const int (*)[2])mcords; } #if 0 From 657fc4f4742bf7b01d613ac8a5989eddadc151a4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 15:48:39 +0000 Subject: [PATCH 117/143] code cleanup: de-duplicate enum. --- source/blender/editors/object/object_add.c | 15 +---------- source/blender/makesrna/RNA_enum_types.h | 1 + source/blender/makesrna/intern/rna_object.c | 29 +++++++++++---------- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index f6a7a6d6f17..43a32cd662e 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -139,19 +139,6 @@ static EnumPropertyItem field_type_items[] = { {0, NULL, 0, NULL, NULL} }; -/* Copy from rna_object.c */ -static EnumPropertyItem empty_drawtype_items[] = { - {OB_PLAINAXES, "PLAIN_AXES", 0, "Plain Axes", ""}, - {OB_ARROWS, "ARROWS", 0, "Arrows", ""}, - {OB_SINGLE_ARROW, "SINGLE_ARROW", 0, "Single Arrow", ""}, - {OB_CIRCLE, "CIRCLE", 0, "Circle", ""}, - {OB_CUBE, "CUBE", 0, "Cube", ""}, - {OB_EMPTY_SPHERE, "SPHERE", 0, "Sphere", ""}, - {OB_EMPTY_CONE, "CONE", 0, "Cone", ""}, - {OB_EMPTY_IMAGE, "IMAGE", 0, "Image", ""}, - {0, NULL, 0, NULL, NULL} -}; - /************************** Exported *****************************/ void ED_object_location_from_view(bContext *C, float loc[3]) @@ -731,7 +718,7 @@ void OBJECT_OT_empty_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", empty_drawtype_items, 0, "Type", ""); + ot->prop = RNA_def_enum(ot->srna, "type", object_empty_drawtype_items, 0, "Type", ""); ED_object_add_generic_props(ot, FALSE); } diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index b651d4d5e5c..0f9a00de7b6 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -38,6 +38,7 @@ extern EnumPropertyItem DummyRNA_NULL_items[]; extern EnumPropertyItem DummyRNA_DEFAULT_items[]; extern EnumPropertyItem object_mode_items[]; +extern EnumPropertyItem object_empty_drawtype_items[]; extern EnumPropertyItem metaelem_type_items[]; extern EnumPropertyItem proportional_falloff_items[]; diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 758b433b1cb..0b8afef0364 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -69,6 +69,19 @@ EnumPropertyItem object_mode_items[] = { {0, NULL, 0, NULL, NULL} }; +EnumPropertyItem object_empty_drawtype_items[] = { + {OB_PLAINAXES, "PLAIN_AXES", 0, "Plain Axes", ""}, + {OB_ARROWS, "ARROWS", 0, "Arrows", ""}, + {OB_SINGLE_ARROW, "SINGLE_ARROW", 0, "Single Arrow", ""}, + {OB_CIRCLE, "CIRCLE", 0, "Circle", ""}, + {OB_CUBE, "CUBE", 0, "Cube", ""}, + {OB_EMPTY_SPHERE, "SPHERE", 0, "Sphere", ""}, + {OB_EMPTY_CONE, "CONE", 0, "Cone", ""}, + {OB_EMPTY_IMAGE, "IMAGE", 0, "Image", ""}, + {0, NULL, 0, NULL, NULL} +}; + + static EnumPropertyItem parent_type_items[] = { {PAROBJECT, "OBJECT", 0, "Object", "The object is parented to an object"}, {PARCURVE, "CURVE", 0, "Curve", "The object is parented to a curve"}, @@ -80,7 +93,7 @@ static EnumPropertyItem parent_type_items[] = { {PARBONE, "BONE", 0, "Bone", "The object is parented to a bone"}, {0, NULL, 0, NULL, NULL} }; - + static EnumPropertyItem collision_bounds_items[] = { {OB_BOUND_BOX, "BOX", 0, "Box", ""}, {OB_BOUND_SPHERE, "SPHERE", 0, "Sphere", ""}, @@ -1874,18 +1887,6 @@ static void rna_def_object(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - - static EnumPropertyItem empty_drawtype_items[] = { - {OB_PLAINAXES, "PLAIN_AXES", 0, "Plain Axes", ""}, - {OB_ARROWS, "ARROWS", 0, "Arrows", ""}, - {OB_SINGLE_ARROW, "SINGLE_ARROW", 0, "Single Arrow", ""}, - {OB_CIRCLE, "CIRCLE", 0, "Circle", ""}, - {OB_CUBE, "CUBE", 0, "Cube", ""}, - {OB_EMPTY_SPHERE, "SPHERE", 0, "Sphere", ""}, - {OB_EMPTY_CONE, "CONE", 0, "Cone", ""}, - {OB_EMPTY_IMAGE, "IMAGE", 0, "Image", ""}, - {0, NULL, 0, NULL, NULL} - }; static EnumPropertyItem track_items[] = { {OB_POSX, "POS_X", 0, "+X", ""}, @@ -2267,7 +2268,7 @@ static void rna_def_object(BlenderRNA *brna) /* empty */ prop = RNA_def_property(srna, "empty_draw_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "empty_drawtype"); - RNA_def_property_enum_items(prop, empty_drawtype_items); + RNA_def_property_enum_items(prop, object_empty_drawtype_items); RNA_def_property_ui_text(prop, "Empty Display Type", "Viewport display style for empties"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); From 292e8e7e00af8c3efb9498d45c275ce9b90dca69 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 17:07:02 +0000 Subject: [PATCH 118/143] add armature_foreachScreenBone(), use for lasso and circle select. also add boundbox checking for lasso select. --- .../blender/editors/space_view3d/drawobject.c | 46 ++++ .../editors/space_view3d/view3d_select.c | 205 +++++++++--------- 2 files changed, 148 insertions(+), 103 deletions(-) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 1d773f5db9e..5ea0413ef71 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -101,6 +101,7 @@ #include "ED_sculpt.h" #include "ED_types.h" #include "ED_curve.h" /* for curve_editnurbs */ +#include "ED_armature.h" #include "UI_resources.h" @@ -2219,6 +2220,51 @@ void nurbs_foreachScreenVert( } } +/* ED_view3d_init_mats_rv3d must be called first */ +void armature_foreachScreenBone( + struct ViewContext *vc, + void (*func)(void *userData, struct EditBone *ebone, int x0, int y0, int x1, int y1), + void *userData) +{ + bArmature *arm = vc->obedit->data; + EditBone *ebone; + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (EBONE_VISIBLE(arm, ebone)) { + int screen_co_a[2], screen_co_b[2]; + int points_proj_tot = 0; + + /* project head location to screenspace */ + if (ED_view3d_project_int_object(vc->ar, ebone->head, screen_co_a, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + } + else { + screen_co_a[0] = IS_CLIPPED; /* weak */ + /* screen_co_a[1]: intentionally dont set this so we get errors on misuse */ + } + + /* project tail location to screenspace */ + if (ED_view3d_project_int_object(vc->ar, ebone->tail, screen_co_b, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + } + else { + screen_co_b[0] = IS_CLIPPED; /* weak */ + /* screen_co_b[1]: intentionally dont set this so we get errors on misuse */ + } + + if (points_proj_tot) { /* at least one point's projection worked */ + func(userData, ebone, + screen_co_a[0], screen_co_a[1], + screen_co_b[0], screen_co_b[1]); + } + } + } +} + /* ************** DRAW MESH ****************** */ /* First section is all the "simple" draw routines, diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index a9eee92c442..ab0c6a2edc8 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -600,65 +600,70 @@ static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], shor lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data); } +static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBone *ebone, int x0, int y0, int x1, int y1) +{ + LassoSelectUserData *data = userData; + bArmature *arm = data->vc->obedit->data; + + if (EBONE_SELECTABLE(arm, ebone)) { + int is_point_done = FALSE; + int points_proj_tot = 0; + + /* project head location to screenspace */ + if (x0 != IS_CLIPPED) { + points_proj_tot++; + if (BLI_rcti_isect_pt(data->rect, x0, y0) && + BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX)) + { + is_point_done = TRUE; + if (data->select) ebone->flag |= BONE_ROOTSEL; + else ebone->flag &= ~BONE_ROOTSEL; + } + } + + /* project tail location to screenspace */ + if (x1 != IS_CLIPPED) { + points_proj_tot++; + if (BLI_rcti_isect_pt(data->rect, x1, y1) && + BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX)) + { + is_point_done = TRUE; + if (data->select) ebone->flag |= BONE_TIPSEL; + else ebone->flag &= ~BONE_TIPSEL; + } + } + + /* if one of points selected, we skip the bone itself */ + if ((is_point_done == FALSE) && (points_proj_tot == 2) && + BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX)) + { + if (data->select) ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + data->is_change = TRUE; + } + + data->is_change |= is_point_done; + } +} + static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { - bArmature *arm = vc->obedit->data; - EditBone *ebone; - int change = FALSE; + LassoSelectUserData data; + rcti rect; + + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + + BLI_lasso_boundbox(&rect, mcords, moves); if (extend == 0 && select) ED_armature_deselect_all_visible(vc->obedit); - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + armature_foreachScreenBone(vc, do_lasso_select_armature__doSelectBone, &data); - /* set editdata in vc */ - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - int screen_co_a[2], screen_co_b[2]; - int is_point_done = FALSE; - int points_proj_tot = 0; - - /* project head location to screenspace */ - if (ED_view3d_project_int_object(vc->ar, ebone->head, screen_co_a, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) - { - points_proj_tot++; - if (BLI_lasso_is_point_inside(mcords, moves, screen_co_a[0], screen_co_a[1], INT_MAX)) { - is_point_done = TRUE; - if (select) ebone->flag |= BONE_ROOTSEL; - else ebone->flag &= ~BONE_ROOTSEL; - } - } - - /* project tail location to screenspace */ - if (ED_view3d_project_int_object(vc->ar, ebone->tail, screen_co_b, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) - { - points_proj_tot++; - if (BLI_lasso_is_point_inside(mcords, moves, screen_co_b[0], screen_co_b[1], INT_MAX)) { - is_point_done = TRUE; - if (select) ebone->flag |= BONE_TIPSEL; - else ebone->flag &= ~BONE_TIPSEL; - } - } - - /* if one of points selected, we skip the bone itself */ - if ((is_point_done == FALSE) && (points_proj_tot == 2) && - BLI_lasso_is_edge_inside(mcords, moves, - screen_co_a[0], screen_co_a[1], - screen_co_b[0], screen_co_b[1], INT_MAX)) - { - if (select) ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - change = TRUE; - } - - change |= is_point_done; - } - } - - if (change) { + if (data.is_change) { + bArmature *arm = vc->obedit->data; ED_armature_sync_selection(arm->edbo); ED_armature_validate_active(arm); WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obedit); @@ -2508,65 +2513,59 @@ static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, int } return 0; } +static void do_circle_select_armature__doSelectBone(void *userData, struct EditBone *ebone, int x0, int y0, int x1, int y1) +{ + CircleSelectUserData *data = userData; + bArmature *arm = data->vc->obedit->data; + + if (EBONE_SELECTABLE(arm, ebone)) { + int is_point_done = FALSE; + int points_proj_tot = 0; + + /* project head location to screenspace */ + if (x0 != IS_CLIPPED) { + points_proj_tot++; + if (armature_circle_doSelectJoint(data, ebone, x0, y0, TRUE)) { + is_point_done = TRUE; + } + } + + /* project tail location to screenspace */ + if (x1 != IS_CLIPPED) { + points_proj_tot++; + if (armature_circle_doSelectJoint(data, ebone, x1, y1, FALSE)) { + is_point_done = TRUE; + } + } + + /* check if the head and/or tail is in the circle + * - the call to check also does the selection already + */ + + /* only if the endpoints didn't get selected, deal with the middle of the bone too + * It works nicer to only do this if the head or tail are not in the circle, + * otherwise there is no way to circle select joints alone */ + if ((is_point_done == FALSE) && (points_proj_tot == 2) && + edge_inside_circle(data->mval[0], data->mval[1], data->radius, x0, y0, x1, y1)) + { + if (data->select) ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + data->is_change = TRUE; + } + + data->is_change |= is_point_done; + } +} static void armature_circle_select(ViewContext *vc, int select, const int mval[2], float rad) { CircleSelectUserData data; bArmature *arm = vc->obedit->data; - EditBone *ebone; view3d_userdata_circleselect_init(&data, vc, select, mval, rad); - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ - - /* check each EditBone... */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - int screen_co_a[2], screen_co_b[2]; - int is_point_done = FALSE; - int points_proj_tot = 0; + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - /* project head location to screenspace */ - if (ED_view3d_project_int_object(vc->ar, ebone->head, screen_co_a, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) - { - points_proj_tot++; - if (armature_circle_doSelectJoint(&data, ebone, screen_co_a[0], screen_co_a[1], TRUE)) { - is_point_done = TRUE; - } - } - - /* project tail location to screenspace */ - if (ED_view3d_project_int_object(vc->ar, ebone->tail, screen_co_b, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) - { - points_proj_tot++; - if (armature_circle_doSelectJoint(&data, ebone, screen_co_b[0], screen_co_b[1], FALSE)) { - is_point_done = TRUE; - } - } - - /* check if the head and/or tail is in the circle - * - the call to check also does the selection already - */ - - /* only if the endpoints didn't get selected, deal with the middle of the bone too - * It works nicer to only do this if the head or tail are not in the circle, - * otherwise there is no way to circle select joints alone */ - if ((is_point_done == FALSE) && (points_proj_tot == 2) && - edge_inside_circle(mval[0], mval[1], rad, - screen_co_a[0], screen_co_a[1], - screen_co_b[0], screen_co_b[1])) - { - if (select) - ebone->flag |= BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED; - else - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - data.is_change = TRUE; - } - - data.is_change |= is_point_done; - } - } + armature_foreachScreenBone(vc, do_circle_select_armature__doSelectBone, &data); if (data.is_change) { ED_armature_sync_selection(arm->edbo); From e23b202693bcd64341b04a3bd3d9f0654dc25dff Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 5 Oct 2012 17:17:19 +0000 Subject: [PATCH 119/143] Fix part of cycles/osl light pass rendering, transmission still not correct. --- intern/cycles/kernel/osl/osl_shader.cpp | 20 ++++++++++++++++---- intern/cycles/kernel/svm/svm_types.h | 8 +++++--- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index 98ede0e4f60..ea508dcb660 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -139,15 +139,27 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy, float sample_weight = fabsf(average(weight)) * albedo; sc.sample_weight = sample_weight; - sc.type = CLOSURE_BSDF_ID; /* scattering flags */ - if (scattering == OSL::Labels::DIFFUSE) + if (scattering == OSL::Labels::DIFFUSE) { sd->flag |= SD_BSDF | SD_BSDF_HAS_EVAL; - else if (scattering == OSL::Labels::GLOSSY) + sc.type = CLOSURE_BSDF_DIFFUSE_ID; + } + else if (scattering == OSL::Labels::GLOSSY) { sd->flag |= SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_GLOSSY; - else + sc.type = CLOSURE_BSDF_GLOSSY_ID; + } + else if (scattering == OSL::Labels::STRAIGHT) { sd->flag |= SD_BSDF; + sc.type = CLOSURE_BSDF_TRANSPARENT_ID; + } + else { + /* todo: we don't actually have a way to determine if + * this closure will reflect/transmit. could add our own + * own scattering flag that do give this info */ + sd->flag |= SD_BSDF; + sc.type = CLOSURE_BSDF_GLOSSY_ID; + } /* add */ sd->closure[sd->num_closure++] = sc; diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index 3cf44a3409a..ee423573cdf 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -287,16 +287,18 @@ typedef enum ClosureType { CLOSURE_BSDF_DIFFUSE_ID, CLOSURE_BSDF_OREN_NAYAR_ID, + CLOSURE_BSDF_GLOSSY_ID, CLOSURE_BSDF_REFLECTION_ID, CLOSURE_BSDF_MICROFACET_GGX_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ID, CLOSURE_BSDF_WARD_ID, + CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, CLOSURE_BSDF_WESTIN_SHEEN_ID, + CLOSURE_BSDF_TRANSMISSION_ID, CLOSURE_BSDF_TRANSLUCENT_ID, CLOSURE_BSDF_REFRACTION_ID, CLOSURE_BSDF_WESTIN_BACKSCATTER_ID, - CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, CLOSURE_BSDF_GLASS_ID, @@ -320,8 +322,8 @@ typedef enum ClosureType { /* watch this, being lazy with memory usage */ #define CLOSURE_IS_BSDF(type) (type <= CLOSURE_BSDF_TRANSPARENT_ID) #define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_OREN_NAYAR_ID) -#define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_WESTIN_SHEEN_ID) -#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSLUCENT_ID && type <= CLOSURE_BSDF_GLASS_ID) +#define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_GLOSSY_ID && type <= CLOSURE_BSDF_WESTIN_SHEEN_ID) +#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_GLASS_ID) #define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID) #define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID) #define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID) From db5682ac8c53377e819fd50357de580c02405fca Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 5 Oct 2012 17:51:44 +0000 Subject: [PATCH 120/143] use pose_foreachScreenBone for pose lasso and circle select --- source/blender/editors/include/ED_view3d.h | 1 + .../blender/editors/space_view3d/drawobject.c | 47 +++++ .../editors/space_view3d/view3d_select.c | 196 +++++++++--------- 3 files changed, 151 insertions(+), 93 deletions(-) diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 8161dd23b8e..ebf93baeabc 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -172,6 +172,7 @@ void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData); void lattice_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData); void armature_foreachScreenBone(struct ViewContext *vc, void (*func)(void *userData, struct EditBone *ebone, int x0, int y0, int x1, int y1), void *userData); +void pose_foreachScreenBone(struct ViewContext *vc, void (*func)(void *userData, struct bPoseChannel *pchan, int x0, int y0, int x1, int y1), void *userData); void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, const struct rcti *rect); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 5ea0413ef71..40207ce806c 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -2265,6 +2265,53 @@ void armature_foreachScreenBone( } } +/* ED_view3d_init_mats_rv3d must be called first */ +/* almost _exact_ copy of #armature_foreachScreenBone */ +void pose_foreachScreenBone( + struct ViewContext *vc, + void (*func)(void *userData, struct bPoseChannel *pchan, int x0, int y0, int x1, int y1), + void *userData) +{ + bArmature *arm = vc->obact->data; + bPose *pose = vc->obact->pose; + bPoseChannel *pchan; + + for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + if (PBONE_VISIBLE(arm, pchan->bone)) { + int screen_co_a[2], screen_co_b[2]; + int points_proj_tot = 0; + + /* project head location to screenspace */ + if (ED_view3d_project_int_object(vc->ar, pchan->pose_head, screen_co_a, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + } + else { + screen_co_a[0] = IS_CLIPPED; /* weak */ + /* screen_co_a[1]: intentionally dont set this so we get errors on misuse */ + } + + /* project tail location to screenspace */ + if (ED_view3d_project_int_object(vc->ar, pchan->pose_tail, screen_co_b, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + points_proj_tot++; + } + else { + screen_co_b[0] = IS_CLIPPED; /* weak */ + /* screen_co_b[1]: intentionally dont set this so we get errors on misuse */ + } + + if (points_proj_tot) { /* at least one point's projection worked */ + func(userData, pchan, + screen_co_a[0], screen_co_a[1], + screen_co_b[0], screen_co_b[1]); + } + } + } +} + /* ************** DRAW MESH ****************** */ /* First section is all the "simple" draw routines, diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index ab0c6a2edc8..36a2927cb44 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -343,63 +343,71 @@ static int edge_inside_rect(const rcti *rect, int x1, int y1, int x2, int y2) return 1; } -/* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) - * and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK - */ +static void do_lasso_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, int x0, int y0, int x1, int y1) +{ + LassoSelectUserData *data = userData; + bArmature *arm = data->vc->obact->data; + + if (PBONE_SELECTABLE(arm, pchan->bone)) { + int is_point_done = FALSE; + int points_proj_tot = 0; + + /* project head location to screenspace */ + if (x0 != IS_CLIPPED) { + points_proj_tot++; + if (BLI_rcti_isect_pt(data->rect, x0, y0) && + BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX)) + { + is_point_done = TRUE; + } + } + + /* project tail location to screenspace */ + if (x1 != IS_CLIPPED) { + points_proj_tot++; + if (BLI_rcti_isect_pt(data->rect, x1, y1) && + BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX)) + { + is_point_done = TRUE; + } + } + + /* if one of points selected, we skip the bone itself */ + if ((is_point_done == TRUE) || + ((is_point_done == FALSE) && (points_proj_tot == 2) && + BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX))) + { + if (data->select) pchan->bone->flag |= BONE_SELECTED; + else pchan->bone->flag &= ~BONE_SELECTED; + data->is_change = TRUE; + } + data->is_change |= is_point_done; + } +} static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves, short select) { - bPoseChannel *pchan; - bArmature *arm = ob->data; + LassoSelectUserData data; + rcti rect; if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) { return; } + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (PBONE_SELECTABLE(arm, pchan->bone)) { - int screen_co_a[2], screen_co_b[2]; - int is_point_done = FALSE; - int points_proj_tot = 0; + BLI_lasso_boundbox(&rect, mcords, moves); - /* project head location to screenspace */ - if (ED_view3d_project_int_object(vc->ar, pchan->pose_head, screen_co_a, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) - { - points_proj_tot++; - if (BLI_lasso_is_point_inside(mcords, moves, screen_co_a[0], screen_co_a[1], INT_MAX)) { - is_point_done = TRUE; - } - } + pose_foreachScreenBone(vc, do_lasso_select_pose__doSelectBone, &data); - /* project tail location to screenspace */ - if (ED_view3d_project_int_object(vc->ar, pchan->pose_tail, screen_co_b, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) - { - points_proj_tot++; - if (BLI_lasso_is_point_inside(mcords, moves, screen_co_b[0], screen_co_b[1], INT_MAX)) { - is_point_done = TRUE; - } - } - - /* if one of points selected, we skip the bone itself */ - if ((is_point_done == TRUE) || - ((is_point_done == FALSE) && (points_proj_tot == 2) && - BLI_lasso_is_edge_inside(mcords, moves, - screen_co_a[0], screen_co_a[1], - screen_co_b[0], screen_co_b[1], INT_MAX))) - { - if (select) pchan->bone->flag |= BONE_SELECTED; - else pchan->bone->flag &= ~BONE_SELECTED; - } + if (data.is_change) { + bArmature *arm = ob->data; + if (arm->flag & ARM_HAS_VIZ_DEPS) { + /* mask modifier ('armature' mode), etc. */ + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } } - - if (arm->flag & ARM_HAS_VIZ_DEPS) { - /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } } static void object_deselect_all_visible(Scene *scene, View3D *v3d) @@ -2427,66 +2435,68 @@ static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, int } return 0; } +static void do_circle_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, int x0, int y0, int x1, int y1) +{ + CircleSelectUserData *data = userData; + bArmature *arm = data->vc->obact->data; + + if (PBONE_SELECTABLE(arm, pchan->bone)) { + int is_point_done = FALSE; + int points_proj_tot = 0; + + /* project head location to screenspace */ + if (x0 != IS_CLIPPED) { + points_proj_tot++; + if (pchan_circle_doSelectJoint(data, pchan, x0, y0)) { + is_point_done = TRUE; + } + } + + /* project tail location to screenspace */ + if (x1 != IS_CLIPPED) { + points_proj_tot++; + if (pchan_circle_doSelectJoint(data, pchan, x1, y1)) { + is_point_done = TRUE; + } + } + + /* check if the head and/or tail is in the circle + * - the call to check also does the selection already + */ + + /* only if the endpoints didn't get selected, deal with the middle of the bone too + * It works nicer to only do this if the head or tail are not in the circle, + * otherwise there is no way to circle select joints alone */ + if ((is_point_done == FALSE) && (points_proj_tot == 2) && + edge_inside_circle(data->mval[0], data->mval[1], data->radius, x0, y0, x1, y1)) + { + if (data->select) pchan->bone->flag |= BONE_SELECTED; + else pchan->bone->flag &= ~BONE_SELECTED; + data->is_change = TRUE; + } + + data->is_change |= is_point_done; + } +} static void pose_circle_select(ViewContext *vc, int select, const int mval[2], float rad) { CircleSelectUserData data; - bArmature *arm = vc->obact->data; - bPose *pose = vc->obact->pose; - bPoseChannel *pchan; view3d_userdata_circleselect_init(&data, vc, select, mval, rad); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */ - /* check each PoseChannel... */ - /* TODO: could be optimized at some point */ - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - if (PBONE_SELECTABLE(arm, pchan->bone)) { - int screen_co_a[2], screen_co_b[2]; - int is_point_done = FALSE; - int points_proj_tot = 0; - - /* project head location to screenspace */ - if (ED_view3d_project_int_object(vc->ar, pchan->pose_head, screen_co_a, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) - { - points_proj_tot++; - if (pchan_circle_doSelectJoint(&data, pchan, screen_co_a[0], screen_co_a[1])) { - is_point_done = TRUE; - } - } - - /* project tail location to screenspace */ - if (ED_view3d_project_int_object(vc->ar, pchan->pose_tail, screen_co_b, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) - { - points_proj_tot++; - if (pchan_circle_doSelectJoint(&data, pchan, screen_co_b[0], screen_co_b[1])) { - is_point_done = TRUE; - } - } - - /* only if the endpoints didn't get selected, deal with the middle of the bone too - * It works nicer to only do this if the head or tail are not in the circle, - * otherwise there is no way to circle select joints alone */ - if ((is_point_done == FALSE) && (points_proj_tot == 2) && - edge_inside_circle(mval[0], mval[1], rad, - screen_co_a[0], screen_co_a[1], - screen_co_b[0], screen_co_b[1])) - { - if (select) - pchan->bone->flag |= BONE_SELECTED; - else - pchan->bone->flag &= ~BONE_SELECTED; - data.is_change = TRUE; - } - - data.is_change |= is_point_done; - } - } + pose_foreachScreenBone(vc, do_circle_select_pose__doSelectBone, &data); if (data.is_change) { + bArmature *arm = vc->obact->data; + WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obact); + + if (arm->flag & ARM_HAS_VIZ_DEPS) { + /* mask modifier ('armature' mode), etc. */ + DAG_id_tag_update(&vc->obact->id, OB_RECALC_DATA); + } } } From ba470956274cc4086ee153e4f9bdda9d2ff714f5 Mon Sep 17 00:00:00 2001 From: Dan Eicher Date: Fri, 5 Oct 2012 19:51:11 +0000 Subject: [PATCH 121/143] Grease Pencil notifier/listener cleanup As suggested by Campbell on the IRC gave grease pencil its own notifier type (NC_GPENCIL) and made the makesrna notifier functions actually update properly. Also got the #ifdef'd GreasePencil.layers.[new/remove] functions working. --- source/blender/blenkernel/BKE_gpencil.h | 4 +- source/blender/blenkernel/intern/gpencil.c | 11 +-- .../blender/editors/gpencil/gpencil_buttons.c | 8 +- source/blender/editors/gpencil/gpencil_edit.c | 10 +- .../blender/editors/gpencil/gpencil_paint.c | 10 +- source/blender/editors/gpencil/gpencil_undo.c | 2 +- .../editors/space_action/space_action.c | 4 +- .../blender/editors/space_clip/space_clip.c | 20 ++-- .../blender/editors/space_image/space_image.c | 8 +- .../blender/editors/space_node/space_node.c | 7 +- .../editors/space_sequencer/space_sequencer.c | 8 +- .../editors/space_view3d/space_view3d.c | 9 +- source/blender/makesrna/intern/rna_gpencil.c | 92 +++++++++++++------ source/blender/windowmanager/WM_types.h | 1 + 14 files changed, 120 insertions(+), 74 deletions(-) diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index f3223fb4af1..3cb20ead39e 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -44,7 +44,7 @@ void free_gpencil_layers(struct ListBase *list); void BKE_gpencil_free(struct bGPdata *gpd); struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe); -struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd); +struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd, const char *name, int setactive); struct bGPdata *gpencil_data_addnew(const char name[]); struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src); @@ -62,6 +62,6 @@ struct bGPDframe *gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, shor void gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf); struct bGPDlayer *gpencil_layer_getactive(struct bGPdata *gpd); void gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active); -void gpencil_layer_delactive(struct bGPdata *gpd); +void gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl); #endif /* __BKE_GPENCIL_H__ */ diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 2ec5801746c..84871375788 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -163,7 +163,7 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe) } /* add a new gp-layer and make it the active layer */ -bGPDlayer *gpencil_layer_addnew(bGPdata *gpd) +bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, int setactive) { bGPDlayer *gpl; @@ -182,11 +182,12 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd) gpl->thickness = 3; /* auto-name */ - strcpy(gpl->info, "GP_Layer"); + strcpy(gpl->info, name); BLI_uniquename(&gpd->layers, gpl, "GP_Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); /* make this one the active one */ - gpencil_layer_setactive(gpd, gpl); + if (setactive) + gpencil_layer_setactive(gpd, gpl); /* return layer */ return gpl; @@ -509,10 +510,8 @@ void gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active) } /* delete the active gp-layer */ -void gpencil_layer_delactive(bGPdata *gpd) +void gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl) { - bGPDlayer *gpl = gpencil_layer_getactive(gpd); - /* error checking */ if (ELEM(NULL, gpd, gpl)) return; diff --git a/source/blender/editors/gpencil/gpencil_buttons.c b/source/blender/editors/gpencil/gpencil_buttons.c index d90ec02b0c1..8a3c996a481 100644 --- a/source/blender/editors/gpencil/gpencil_buttons.c +++ b/source/blender/editors/gpencil/gpencil_buttons.c @@ -75,17 +75,15 @@ static void gp_ui_activelayer_cb(bContext *C, void *gpd, void *gpl) /* make sure the layer we want to remove is the active one */ gpencil_layer_setactive(gpd, gpl); - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL | NA_EDITED, NULL); /* XXX please work! */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } /* delete 'active' layer */ static void gp_ui_dellayer_cb(bContext *C, void *gpd, void *gpl) { - /* make sure the layer we want to remove is the active one */ - gpencil_layer_setactive(gpd, gpl); - gpencil_layer_delactive(gpd); + gpencil_layer_delete((bGPdata *)gpd, (bGPDlayer *)gpl); - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL | NA_EDITED, NULL); /* XXX please work! */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 659e99607f0..46df8ba5fac 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -224,7 +224,7 @@ static int gp_data_add_exec(bContext *C, wmOperator *op) } /* notifiers */ - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL | NA_EDITED, NULL); // XXX need a nicer one that will work + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -272,7 +272,7 @@ static int gp_data_unlink_exec(bContext *C, wmOperator *op) } /* notifiers */ - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL | NA_EDITED, NULL); // XXX need a nicer one that will work + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -306,10 +306,10 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op) *gpd_ptr = gpencil_data_addnew("GPencil"); /* add new layer now */ - gpencil_layer_addnew(*gpd_ptr); + gpencil_layer_addnew(*gpd_ptr, "GP_Layer", 1); /* notifiers */ - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL | NA_EDITED, NULL); // XXX please work! + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -360,7 +360,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op) gpencil_layer_delframe(gpl, gpf); /* notifiers */ - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL | NA_EDITED, NULL); // XXX please work! + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 0595f4e18bd..de7c2c41a6d 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1143,7 +1143,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode) /* get active layer (or add a new one if non-existent) */ p->gpl = gpencil_layer_getactive(p->gpd); if (p->gpl == NULL) { - p->gpl = gpencil_layer_addnew(p->gpd); + p->gpl = gpencil_layer_addnew(p->gpd, "GP_Layer", 1); if (p->custom_color[3]) copy_v3_v3(p->gpl->color, p->custom_color); @@ -1616,7 +1616,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) gpencil_draw_exit(C, op); /* refreshes */ - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL | NA_EDITED, NULL); // XXX need a nicer one that will work + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* done */ return OPERATOR_FINISHED; @@ -1677,7 +1677,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, wmEvent *event) //printf("\tGP - hotkey invoked... waiting for click-drag\n"); } - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL, NULL); + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* add a modal handler for this operator, so that we can then draw continuous strokes */ WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; @@ -1790,7 +1790,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) estate = OPERATOR_RUNNING_MODAL; /* stroke could be smoothed, send notifier to refresh screen */ - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); } else { //printf("\t\tGP - end of stroke + op\n"); @@ -1880,7 +1880,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) case OPERATOR_FINISHED: /* one last flush before we're done */ gpencil_draw_exit(C, op); - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL | NA_EDITED, NULL); // XXX need a nicer one that will work + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); break; case OPERATOR_CANCELLED: diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index fa9f5196866..3d2cd260fb9 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -111,7 +111,7 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name) } } - WM_event_add_notifier(C, NC_SCREEN | ND_GPENCIL | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 92b6517cbd9..2e92b1eea6f 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -357,8 +357,8 @@ static void action_listener(ScrArea *sa, wmNotifier *wmn) /* context changes */ switch (wmn->category) { - case NC_SCREEN: - if (wmn->data == ND_GPENCIL) { + case NC_GPENCIL: + if (wmn->action == NA_EDITED) { /* only handle this event in GPencil mode for performance considerations */ if (saction->mode == SACTCONT_GPENCIL) ED_area_tag_redraw(sa); diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 3f925df30c7..ffe4762ad15 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -407,8 +407,6 @@ static void clip_listener(ScrArea *sa, wmNotifier *wmn) case NC_SCREEN: switch (wmn->data) { case ND_ANIMPLAY: - case ND_GPENCIL: - clip_scopes_check_gpencil_change(sa); ED_area_tag_redraw(sa); break; } @@ -420,6 +418,12 @@ static void clip_listener(ScrArea *sa, wmNotifier *wmn) ED_area_tag_redraw(sa); } break; + case NC_GPENCIL: + if (wmn->action == NA_EDITED) { + clip_scopes_check_gpencil_change(sa); + ED_area_tag_redraw(sa); + } + break; } } @@ -1159,8 +1163,8 @@ static void clip_main_area_listener(ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { - case NC_SCREEN: - if (wmn->data == ND_GPENCIL) + case NC_GPENCIL: + if (wmn->action == NA_EDITED) ED_region_tag_redraw(ar); break; } @@ -1373,8 +1377,8 @@ static void clip_props_area_listener(ARegion *ar, wmNotifier *wmn) if (wmn->data == ND_SPACE_CLIP) ED_region_tag_redraw(ar); break; - case NC_SCREEN: - if (wmn->data == ND_GPENCIL) + case NC_GPENCIL: + if (wmn->action == NA_EDITED) ED_region_tag_redraw(ar); break; } @@ -1406,8 +1410,8 @@ static void clip_properties_area_listener(ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { - case NC_SCREEN: - if (wmn->data == ND_GPENCIL) + case NC_GPENCIL: + if (wmn->data == ND_DATA) ED_region_tag_redraw(ar); break; case NC_BRUSH: diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index dbad6e8bb24..31cb6d91889 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -708,8 +708,8 @@ static void image_main_area_listener(ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { - case NC_SCREEN: - if (wmn->data == ND_GPENCIL) + case NC_GPENCIL: + if (wmn->action == NA_EDITED) ED_region_tag_redraw(ar); break; } @@ -737,8 +737,8 @@ static void image_buttons_area_listener(ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { - case NC_SCREEN: - if (wmn->data == ND_GPENCIL) + case NC_GPENCIL: + if (wmn->data == ND_DATA) ED_region_tag_redraw(ar); break; case NC_BRUSH: diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 0601d7c105f..b70d66f60b4 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -440,9 +440,6 @@ static void node_region_listener(ARegion *ar, wmNotifier *wmn) break; case NC_SCREEN: switch (wmn->data) { - case ND_GPENCIL: - ED_region_tag_redraw(ar); - break; case ND_SCREENCAST: case ND_ANIMPLAY: ED_region_tag_redraw(ar); @@ -463,6 +460,10 @@ static void node_region_listener(ARegion *ar, wmNotifier *wmn) if (wmn->action == NA_RENAME) ED_region_tag_redraw(ar); break; + case NC_GPENCIL: + if (wmn->action == NA_EDITED) + ED_region_tag_redraw(ar); + break; } } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 21c70a5b4a9..7bfe58cb50a 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -556,8 +556,8 @@ static void sequencer_preview_area_listener(ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { - case NC_SCREEN: - if (wmn->data == ND_GPENCIL) { + case NC_GPENCIL: + if (wmn->action == NA_EDITED) { ED_region_tag_redraw(ar); } break; @@ -610,8 +610,8 @@ static void sequencer_buttons_area_listener(ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { - case NC_SCREEN: - if (wmn->data == ND_GPENCIL) { + case NC_GPENCIL: + if (wmn->data == ND_DATA) { ED_region_tag_redraw(ar); } break; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 1e371cb074d..236cbb86724 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -776,7 +776,6 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn) break; case NC_SCREEN: switch (wmn->data) { - case ND_GPENCIL: case ND_ANIMPLAY: case ND_SKETCH: ED_region_tag_redraw(ar); @@ -793,6 +792,10 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn) } break; + case NC_GPENCIL: + if (wmn->action == NA_EDITED) + ED_region_tag_redraw(ar); + break; } } @@ -941,8 +944,8 @@ static void view3d_buttons_area_listener(ARegion *ar, wmNotifier *wmn) if (wmn->action == NA_RENAME) ED_region_tag_redraw(ar); break; - case NC_SCREEN: - if (wmn->data == ND_GPENCIL) + case NC_GPENCIL: + if (wmn->data == ND_DATA) ED_region_tag_redraw(ar); break; } diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 131611d3002..bf7f4984ea1 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -40,6 +40,15 @@ #ifdef RNA_RUNTIME +#include "WM_api.h" + +#include "BKE_gpencil.h" + +static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +{ + WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); +} + static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr) { bGPDlayer *gpl = (bGPDlayer *)ptr->data; @@ -53,6 +62,7 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr) static PointerRNA rna_GPencil_active_layer_get(PointerRNA *ptr) { + bGPdata *gpd = ptr->id.data; if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */ @@ -101,6 +111,34 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value) BLI_uniquename(&gpd->layers, gpl, "GP_Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); } +static bGPDlayer *rna_GPencil_layer_new(bGPdata *gpd, const char *name, int setactive) +{ + bGPDlayer *gl = gpencil_layer_addnew(gpd, name, setactive); + + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return gl; +} + +static void rna_GPencil_layer_remove(bGPdata *gpd, ReportList *reports, bGPDlayer *layer) +{ + bGPDlayer *gl; + + for (gl = gpd->layers.first; gl; gl = gl->next) { + if (gl == layer) + break; + } + + if (gl == NULL) { + BKE_reportf(reports, RPT_ERROR, "Layer not found in grease pencil data"); + return; + } + + gpencil_layer_delete(gpd, layer); + + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); +} + #else static void rna_def_gpencil_stroke_point(BlenderRNA *brna) @@ -116,13 +154,13 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "x"); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Coordinates", ""); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); prop = RNA_def_property(srna, "pressure", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "pressure"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Pressure", "Pressure of tablet at point when drawing it"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); } static void rna_def_gpencil_stroke(BlenderRNA *brna) @@ -189,7 +227,8 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Info", "Layer name"); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilLayer_info_set"); RNA_def_struct_name_property(srna, prop); - + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + /* Frames */ prop = RNA_def_property(srna, "frames", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "frames", NULL); @@ -201,32 +240,33 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "actframe"); RNA_def_property_ui_text(prop, "Active Frame", "Frame currently being displayed for this layer"); RNA_def_property_editable_func(prop, "rna_GPencilLayer_active_frame_editable"); - + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + /* Drawing Color */ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Color", "Color for all strokes in this layer"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "color[3]"); RNA_def_property_range(prop, 0.3, 1.0f); RNA_def_property_ui_text(prop, "Opacity", "Layer Opacity"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Line Thickness */ prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "thickness"); RNA_def_property_range(prop, 1, 10); RNA_def_property_ui_text(prop, "Thickness", "Thickness of strokes (in pixels)"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Onion-Skinning */ prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ONIONSKIN); RNA_def_property_ui_text(prop, "Onion Skinning", "Ghost frames on either side of frame"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "ghost_range_max", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "gstep"); @@ -234,23 +274,23 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Max Ghost Range", "Maximum number of frames on either side of the active frame to show " "(0 = show the 'first' available sketch on either side)"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Flags */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE); RNA_def_property_ui_text(prop, "Hide", "Set layer Visibility"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_LOCKED); RNA_def_property_ui_text(prop, "Locked", "Protect layer from further editing and/or frame changes"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); prop = RNA_def_property(srna, "lock_frame", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_FRAMELOCK); RNA_def_property_ui_text(prop, "Frame Locked", "Lock current frame displayed by layer"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); /* expose as layers.active */ #if 0 @@ -258,25 +298,25 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ACTIVE); RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencilLayer_active_set"); RNA_def_property_ui_text(prop, "Active", "Set active layer for editing"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); #endif prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_SELECT); RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the DopeSheet"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); /* XXX keep this option? */ prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_DRAWDEBUG); RNA_def_property_ui_text(prop, "Show Points", "Draw the points which make up the strokes (for debugging purposes)"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update_runtime(prop, "rna_GPencil_update"); /* X-Ray */ prop = RNA_def_property(srna, "show_x_ray", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_LAYER_NO_XRAY); RNA_def_property_ui_text(prop, "X Ray", "Make the layer draw in front of objects"); - RNA_def_property_update(prop, NC_SCREEN | ND_GPENCIL, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); } static void rna_def_gpencil_layers(BlenderRNA *brna, PropertyRNA *cprop) @@ -284,28 +324,27 @@ static void rna_def_gpencil_layers(BlenderRNA *brna, PropertyRNA *cprop) StructRNA *srna; PropertyRNA *prop; -/* FunctionRNA *func; */ -/* PropertyRNA *parm; */ + FunctionRNA *func; + PropertyRNA *parm; RNA_def_property_srna(cprop, "GreasePencilLayers"); srna = RNA_def_struct(brna, "GreasePencilLayers", NULL); RNA_def_struct_sdna(srna, "bGPdata"); RNA_def_struct_ui_text(srna, "Grease Pencil Layers", "Collection of grease pencil layers"); -#if 0 func = RNA_def_function(srna, "new", "rna_GPencil_layer_new"); - RNA_def_function_ui_description(func, "Add a new spline to the curve"); - parm = RNA_def_enum(func, "type", curve_type_items, CU_POLY, "", "type for the new spline"); + RNA_def_function_ui_description(func, "Add a new grease pencil layer"); + parm = RNA_def_string(func, "name", "GPencilLayer", MAX_NAME, "Name", "Name of the layer"); RNA_def_property_flag(parm, PROP_REQUIRED); - parm = RNA_def_pointer(func, "spline", "Spline", "", "The newly created spline"); + RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created layer to the active layer"); + parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "The newly created layer"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_GPencil_layer_remove"); - RNA_def_function_ui_description(func, "Remove a spline from a curve"); + RNA_def_function_ui_description(func, "Remove a grease pencil layer"); RNA_def_function_flag(func, FUNC_USE_REPORTS); - parm = RNA_def_pointer(func, "spline", "Spline", "", "The spline to remove"); + parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "The layer to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); -#endif prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "GreasePencil"); @@ -344,11 +383,12 @@ static void rna_def_gpencil_data(BlenderRNA *brna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, draw_mode_items); RNA_def_property_ui_text(prop, "Draw Mode", ""); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); prop = RNA_def_property(srna, "use_stroke_endpoints", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_DEPTH_STROKE_ENDPOINTS); RNA_def_property_ui_text(prop, "Only Endpoints", "Only use the first and last parts of the stroke for snapping"); - + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); } diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index f9b22331f37..2aa0d83f234 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -238,6 +238,7 @@ typedef struct wmNotifier { #define NC_LOGIC (19<<24) #define NC_MOVIECLIP (20<<24) #define NC_MASK (21<<24) +#define NC_GPENCIL (22<<24) /* data type, 256 entries is enough, it can overlap */ #define NOTE_DATA 0x00FF0000 From 39a96e9e3fab5347497da004e71227c651e8604e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Oct 2012 00:42:30 +0000 Subject: [PATCH 122/143] disable padding warning for DNA, gave problems with struct bounds padding which DNA ignores. tag operator callbacks as needing their return values used. These are not directly called in many places so the inconvenience is minimal. --- .../editors/sculpt_paint/paint_vertex.c | 14 ++++++++--- source/blender/editors/sculpt_paint/sculpt.c | 5 +++- source/blender/makesdna/intern/makesdna.c | 5 ++++ source/blender/windowmanager/WM_types.h | 18 ++++++++++--- .../windowmanager/intern/wm_operators.c | 25 +++++++++++++------ 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index f1ee8f522d9..5a79368ac49 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -2372,7 +2372,8 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) { - + int retval; + op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start, wpaint_stroke_update_step, wpaint_stroke_done, event->type); @@ -2380,7 +2381,9 @@ static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) /* add modal handler */ WM_event_add_modal_handler(C, op); - op->type->modal(C, op, event); + retval = op->type->modal(C, op, event); + OPERATOR_RETVAL_CHECK(retval); + BLI_assert(retval == OPERATOR_RUNNING_MODAL); return OPERATOR_RUNNING_MODAL; } @@ -2816,7 +2819,8 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) { - + int retval; + op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start, vpaint_stroke_update_step, vpaint_stroke_done, event->type); @@ -2824,7 +2828,9 @@ static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) /* add modal handler */ WM_event_add_modal_handler(C, op); - op->type->modal(C, op, event); + retval = op->type->modal(C, op, event); + OPERATOR_RETVAL_CHECK(retval); + BLI_assert(retval == OPERATOR_RUNNING_MODAL); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index ec0478d128f..3d3e86d2acb 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -3998,6 +3998,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even { struct PaintStroke *stroke; int ignore_background_click; + int retval; if (!sculpt_brush_stroke_init(C, op)) return OPERATOR_CANCELLED; @@ -4021,7 +4022,9 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even /* add modal handler */ WM_event_add_modal_handler(C, op); - op->type->modal(C, op, event); + retval = op->type->modal(C, op, event); + OPERATOR_RETVAL_CHECK(retval); + BLI_assert(retval == OPERATOR_RUNNING_MODAL); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 88c5ea3e910..494cb875169 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -1186,6 +1186,9 @@ int main(int argc, char **argv) return(return_status); } +/* handy but fails on struct bounds which makesdna doesnt care about + * unless structs are nested */ +#if 0 /* include files for automatic dependencies */ /* extra safety check that we are aligned, @@ -1194,6 +1197,8 @@ int main(int argc, char **argv) # pragma GCC diagnostic error "-Wpadded" #endif +#endif /* if 0 */ + #include "DNA_listBase.h" #include "DNA_vec_types.h" #include "DNA_ID.h" diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 2aa0d83f234..ad828cef6d5 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -509,7 +509,11 @@ typedef struct wmOperatorType { * parameters may be provided through operator properties. cannot use * any interface code or input device state. * - see defines below for return values */ - int (*exec)(struct bContext *, struct wmOperator *); + int (*exec)(struct bContext *, struct wmOperator *) +#ifdef __GNUC__ + __attribute__((warn_unused_result)) +#endif + ; /* this callback executes on a running operator whenever as property * is changed. It can correct its own properties or report errors for @@ -521,9 +525,17 @@ typedef struct wmOperatorType { * any further events are handled in modal. if the operation is * canceled due to some external reason, cancel is called * - see defines below for return values */ - int (*invoke)(struct bContext *, struct wmOperator *, struct wmEvent *); + int (*invoke)(struct bContext *, struct wmOperator *, struct wmEvent *) +#ifdef __GNUC__ + __attribute__((warn_unused_result)) +#endif + ; int (*cancel)(struct bContext *, struct wmOperator *); - int (*modal)(struct bContext *, struct wmOperator *, struct wmEvent *); + int (*modal)(struct bContext *, struct wmOperator *, struct wmEvent *) +#ifdef __GNUC__ + __attribute__((warn_unused_result)) +#endif + ; /* verify if the operator can be executed in the current context, note * that the operator might still fail to execute even if this return true */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 9de3c15d70f..e4d6b3dd465 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -2289,6 +2289,8 @@ static int border_apply_rect(wmOperator *op) static int border_apply(bContext *C, wmOperator *op, int gesture_mode) { + int retval; + if (!border_apply_rect(op)) return 0; @@ -2296,7 +2298,9 @@ static int border_apply(bContext *C, wmOperator *op, int gesture_mode) if (RNA_struct_find_property(op->ptr, "gesture_mode") ) RNA_int_set(op->ptr, "gesture_mode", gesture_mode); - op->type->exec(C, op); + retval = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(retval); + return 1; } @@ -2422,8 +2426,11 @@ static void gesture_circle_apply(bContext *C, wmOperator *op) RNA_int_set(op->ptr, "y", rect->ymin); RNA_int_set(op->ptr, "radius", rect->xmax); - if (op->type->exec) - op->type->exec(C, op); + if (op->type->exec) { + int retval; + retval = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(retval); + } #ifdef GESTURE_MEMORY circle_select_size = rect->xmax; #endif @@ -2643,8 +2650,10 @@ static void gesture_lasso_apply(bContext *C, wmOperator *op) wm_gesture_end(C, op); - if (op->type->exec) - op->type->exec(C, op); + if (op->type->exec) { + int retval = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(retval); + } } int WM_gesture_lasso_modal(bContext *C, wmOperator *op, wmEvent *event) @@ -2813,8 +2822,10 @@ static int straightline_apply(bContext *C, wmOperator *op) RNA_int_set(op->ptr, "xend", rect->xmax); RNA_int_set(op->ptr, "yend", rect->ymax); - if (op->type->exec) - op->type->exec(C, op); + if (op->type->exec) { + int retval = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(retval); + } return 1; } From f84f2c703378284cb72de3bb07b7a8f4b5de31c9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Oct 2012 01:30:49 +0000 Subject: [PATCH 123/143] add circle select for metaballs --- .../editors/space_view3d/view3d_select.c | 102 +++++++++++------- 1 file changed, 66 insertions(+), 36 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 36a2927cb44..c4639fc2c56 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -550,7 +550,7 @@ static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BP if (BLI_lasso_is_point_inside(data->mcords, data->moves, x, y, IS_CLIPPED)) { if (bp) { bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); - if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL; + if (bp == cu->lastsel && !(bp->f1 & SELECT)) cu->lastsel = NULL; } else { if (cu->drawflag & CU_HIDE_HANDLES) { @@ -569,7 +569,7 @@ static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BP } } - if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL; + if (bezt == cu->lastsel && !(bezt->f2 & SELECT)) cu->lastsel = NULL; } } } @@ -1633,7 +1633,7 @@ static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoi if (BLI_rcti_isect_pt(data->rect, x, y)) { if (bp) { bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); - if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL; + if (bp == cu->lastsel && !(bp->f1 & SELECT)) cu->lastsel = NULL; } else { if (cu->drawflag & CU_HIDE_HANDLES) { @@ -1652,7 +1652,7 @@ static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoi } } - if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL; + if (bezt == cu->lastsel && !(bezt->f2 & SELECT)) cu->lastsel = NULL; } } } @@ -2357,7 +2357,7 @@ static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint if (bp) { bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); - if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL; + if (bp == cu->lastsel && !(bp->f1 & SELECT)) cu->lastsel = NULL; } else { if (cu->drawflag & CU_HIDE_HANDLES) { @@ -2376,7 +2376,7 @@ static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint } } - if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL; + if (bezt == cu->lastsel && !(bezt->f2 & SELECT)) cu->lastsel = NULL; } } } @@ -2384,14 +2384,7 @@ static void nurbscurve_circle_select(ViewContext *vc, int select, const int mval { CircleSelectUserData data; - /* set vc-> edit data */ - - data.select = select; - data.mval[0] = mval[0]; - data.mval[1] = mval[1]; - data.radius = rad; - data.vc = vc; - data.is_change = FALSE; + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data); @@ -2584,6 +2577,29 @@ static void armature_circle_select(ViewContext *vc, int select, const int mval[2 } } +static void mball_circle_select(ViewContext *vc, int select, const int mval[2], float rad) +{ + const float radius_squared = rad * rad; + const float mval_fl[2] = {mval[0], mval[1]}; + + MetaBall *mb = (MetaBall *)vc->obedit->data; + MetaElem *ml; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + + for (ml = mb->editelems->first; ml; ml = ml->next) { + float screen_co[2]; + if (ED_view3d_project_float_object(vc->ar, &ml->x, screen_co, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) { + if (select) ml->flag |= SELECT; + else ml->flag &= ~SELECT; + } + } + } +} + /** Callbacks for circle selection in Editmode */ static void obedit_circle_select(ViewContext *vc, short select, const int mval[2], float rad) @@ -2602,24 +2618,50 @@ static void obedit_circle_select(ViewContext *vc, short select, const int mval[2 case OB_ARMATURE: armature_circle_select(vc, select, mval, rad); break; + case OB_MBALL: + mball_circle_select(vc, select, mval, rad); + break; default: return; } } +static int object_circle_select(ViewContext *vc, int select, const int mval[2], float rad) +{ + Scene *scene = vc->scene; + const float radius_squared = rad * rad; + const float mval_fl[2] = {mval[0], mval[1]}; + int is_change = FALSE; + + Base *base; + select = select ? BA_SELECT : BA_DESELECT; + for (base = FIRSTBASE; base; base = base->next) { + if (((base->flag & SELECT) == 0) && BASE_SELECTABLE(vc->v3d, base)) { + float screen_co[2]; + if (ED_view3d_project_float_global(vc->ar, base->object->obmat[3], screen_co, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) { + ED_base_object_select(base, select); + is_change = TRUE; + } + } + } + } + + return is_change; +} + /* not a real operator, only for circle test */ static int view3d_circle_select_exec(bContext *C, wmOperator *op) { - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); - View3D *v3d = sa->spacedata.first; - int x = RNA_int_get(op->ptr, "x"); - int y = RNA_int_get(op->ptr, "y"); int radius = RNA_int_get(op->ptr, "radius"); int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); int select; + const int mval[2] = {RNA_int_get(op->ptr, "x"), + RNA_int_get(op->ptr, "y")}; select = (gesture_mode == GESTURE_MODAL_SELECT); @@ -2627,13 +2669,10 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) ) { ViewContext vc; - int mval[2]; view3d_operator_needs_opengl(C); view3d_set_viewcontext(C, &vc); - mval[0] = x; - mval[1] = y; if (CTX_data_edit_object(C)) { obedit_circle_select(&vc, select, mval, (float)radius); @@ -2656,21 +2695,12 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } else { - Base *base; - select = select ? BA_SELECT : BA_DESELECT; - for (base = FIRSTBASE; base; base = base->next) { - if (BASE_SELECTABLE(v3d, base)) { - ED_view3d_project_base(ar, base); - if (base->sx != IS_CLIPPED) { - int dx = base->sx - x; - int dy = base->sy - y; - if (dx * dx + dy * dy < radius * radius) - ED_base_object_select(base, select); - } - } + ViewContext vc; + view3d_set_viewcontext(C, &vc); + + if (object_circle_select(&vc, select, mval, (float)radius)) { + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } - - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); } return OPERATOR_FINISHED; From c4472bbab678cfc826fc40fe9272db38cbb6a1cd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Oct 2012 03:02:14 +0000 Subject: [PATCH 124/143] add mball_foreachScreenElem() and use for lasso & circle selection, also utility metaball functions to (de)select all. --- source/blender/blenkernel/BKE_mball.h | 4 + source/blender/blenkernel/intern/mball.c | 29 +++++++ source/blender/editors/include/ED_view3d.h | 2 + source/blender/editors/metaball/mball_edit.c | 79 ++++++++--------- .../blender/editors/space_view3d/drawobject.c | 19 +++++ .../editors/space_view3d/view3d_select.c | 84 +++++++++---------- 6 files changed, 132 insertions(+), 85 deletions(-) diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 913e8653b9b..d591b44e489 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -63,4 +63,8 @@ void BKE_mball_translate(struct MetaBall *mb, float offset[3]); struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type); +void BKE_mball_select_all(struct MetaBall *mb); +void BKE_mball_deselect_all(struct MetaBall *mb); +void BKE_mball_select_swap(struct MetaBall *mb); + #endif diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 2030ab0f552..de7fdece7dd 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -2396,3 +2396,32 @@ void BKE_mball_translate(MetaBall *mb, float offset[3]) add_v3_v3(&ml->x, offset); } } + +/* *** select funcs *** */ +void BKE_mball_select_all(struct MetaBall *mb) +{ + MetaElem *ml; + + for (ml = mb->editelems->first; ml; ml = ml->next) { + ml->flag |= SELECT; + } +} + +void BKE_mball_deselect_all(MetaBall *mb) +{ + MetaElem *ml; + + for (ml = mb->editelems->first; ml; ml = ml->next) { + ml->flag &= ~SELECT; + } +} + +void BKE_mball_select_swap(struct MetaBall *mb) +{ + MetaElem *ml; + + for (ml = mb->editelems->first; ml; ml = ml->next) { + ml->flag ^= SELECT; + } +} + diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index ebf93baeabc..b81e08ed7ef 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -44,6 +44,7 @@ struct EditBone; struct ImBuf; struct MVert; struct Main; +struct MetaElem; struct Nurb; struct Nurb; struct Object; @@ -170,6 +171,7 @@ void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, eV3DClipTest clipVerts); void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct BMFace *efa, int x, int y, int index), void *userData); void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData); +void mball_foreachScreenElem(struct ViewContext *vc, void (*func)(void *userData, struct MetaElem *ml, int x, int y), void *userData); void lattice_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData); void armature_foreachScreenBone(struct ViewContext *vc, void (*func)(void *userData, struct EditBone *ebone, int x0, int y0, int x1, int y1), void *userData); void pose_foreachScreenBone(struct ViewContext *vc, void (*func)(void *userData, struct bPoseChannel *pchan, int x0, int y0, int x1, int y1), void *userData); diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 22ccd7bbed8..e9063687506 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -129,37 +129,33 @@ static int mball_select_all_exec(bContext *C, wmOperator *op) MetaElem *ml; int action = RNA_enum_get(op->ptr, "action"); - ml = mb->editelems->first; - if (ml) { - if (action == SEL_TOGGLE) { - action = SEL_SELECT; - while (ml) { - if (ml->flag & SELECT) { - action = SEL_DESELECT; - break; - } - ml = ml->next; - } - } + if (mb->editelems->first == NULL) + return OPERATOR_CANCELLED; - ml = mb->editelems->first; - while (ml) { - switch (action) { - case SEL_SELECT: - ml->flag |= SELECT; - break; - case SEL_DESELECT: - ml->flag &= ~SELECT; - break; - case SEL_INVERT: - ml->flag ^= SELECT; - break; + if (action == SEL_TOGGLE) { + action = SEL_SELECT; + for (ml = mb->editelems->first; ml; ml = ml->next) { + if (ml->flag & SELECT) { + action = SEL_DESELECT; + break; } - ml = ml->next; } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb); } + switch (action) { + case SEL_SELECT: + BKE_mball_select_all(mb); + break; + case SEL_DESELECT: + BKE_mball_deselect_all(mb); + break; + case SEL_INVERT: + BKE_mball_select_swap(mb); + break; + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb); + return OPERATOR_FINISHED; } @@ -421,7 +417,7 @@ int mouse_mball(bContext *C, const int mval[2], int extend, int deselect, int to Object *obedit = CTX_data_edit_object(C); ViewContext vc; MetaBall *mb = (MetaBall *)obedit->data; - MetaElem *ml, *act = NULL; + MetaElem *ml, *ml_act = NULL; int a, hits; unsigned int buffer[4 * MAXPICKBUF]; rcti rect; @@ -451,14 +447,14 @@ int mouse_mball(bContext *C, const int mval[2], int extend, int deselect, int to /* index converted for gl stuff */ if (ml->selcol1 == buffer[4 * a + 3]) { ml->flag |= MB_SCALE_RAD; - act = ml; + ml_act = ml; } if (ml->selcol2 == buffer[4 * a + 3]) { ml->flag &= ~MB_SCALE_RAD; - act = ml; + ml_act = ml; } } - if (act) break; + if (ml_act) break; ml = ml->next; if (ml == NULL) ml = mb->editelems->first; if (ml == startelem) break; @@ -466,31 +462,28 @@ int mouse_mball(bContext *C, const int mval[2], int extend, int deselect, int to /* When some metaelem was found, then it is necessary to select or * deselect it. */ - if (act) { + if (ml_act) { if (extend) { - act->flag |= SELECT; + ml_act->flag |= SELECT; } else if (deselect) { - act->flag &= ~SELECT; + ml_act->flag &= ~SELECT; } else if (toggle) { - if (act->flag & SELECT) - act->flag &= ~SELECT; + if (ml_act->flag & SELECT) + ml_act->flag &= ~SELECT; else - act->flag |= SELECT; + ml_act->flag |= SELECT; } else { /* Deselect all existing metaelems */ - ml = mb->editelems->first; - while (ml) { - ml->flag &= ~SELECT; - ml = ml->next; - } + BKE_mball_deselect_all(mb); + /* Select only metaelem clicked on */ - act->flag |= SELECT; + ml_act->flag |= SELECT; } - mb->lastelem = act; + mb->lastelem = ml_act; WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 40207ce806c..a6f4527cf98 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -2220,6 +2220,25 @@ void nurbs_foreachScreenVert( } } +/* ED_view3d_init_mats_rv3d must be called first */ +void mball_foreachScreenElem( + struct ViewContext *vc, + void (*func)(void *userData, struct MetaElem *ml, int x, int y), + void *userData) +{ + MetaBall *mb = (MetaBall *)vc->obedit->data; + MetaElem *ml; + + for (ml = mb->editelems->first; ml; ml = ml->next) { + int screen_co[2]; + if (ED_view3d_project_int_object(vc->ar, &ml->x, screen_co, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + func(userData, ml, screen_co[0], screen_co[1]); + } + } +} + /* ED_view3d_init_mats_rv3d must be called first */ void armature_foreachScreenBone( struct ViewContext *vc, diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index c4639fc2c56..53f2c2e9f5e 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -61,13 +61,14 @@ #include "IMB_imbuf.h" #include "BKE_global.h" -#include "BKE_context.h" -#include "BKE_paint.h" #include "BKE_armature.h" +#include "BKE_context.h" #include "BKE_depsgraph.h" -#include "BKE_tessmesh.h" +#include "BKE_mball.h" #include "BKE_movieclip.h" #include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_tessmesh.h" #include "BKE_tracking.h" @@ -678,32 +679,34 @@ static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], sho } } +static void do_lasso_select_mball__doSelectElem(void *userData, struct MetaElem *ml, int x, int y) +{ + LassoSelectUserData *data = userData; + if (BLI_rcti_isect_pt(data->rect, x, y) && + BLI_lasso_is_point_inside(data->mcords, data->moves, x, y, INT_MAX)) { + if (data->select) ml->flag |= SELECT; + else ml->flag &= ~SELECT; + data->is_change = TRUE; + } +} static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { - MetaBall *mb = (MetaBall *)vc->obedit->data; - MetaElem *ml; + LassoSelectUserData data; + rcti rect; - if (extend == 0 && select) { - /* XXX, make an editor function as is done elsewhere */ - for (ml = mb->editelems->first; ml; ml = ml->next) { - ml->flag &= ~SELECT; - } - } + MetaBall *mb = (MetaBall *)vc->obedit->data; + + if (extend == 0 && select) + BKE_mball_deselect_all(mb); + + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - for (ml = mb->editelems->first; ml; ml = ml->next) { - int screen_co[2]; - if (ED_view3d_project_int_object(vc->ar, &ml->x, screen_co, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) - { - if (BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) { - if (select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; - } - } - } + BLI_lasso_boundbox(&rect, mcords, moves); + + mball_foreachScreenElem(vc, do_lasso_select_mball__doSelectElem, &data); } static int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int extend) @@ -1792,11 +1795,8 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, int select, int exten hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect); - if (extend == 0 && select) { - for (ml = mb->editelems->first; ml; ml = ml->next) { - ml->flag &= ~SELECT; - } - } + if (extend == 0 && select) + BKE_mball_deselect_all(mb); for (ml = mb->editelems->first; ml; ml = ml->next) { for (a = 0; a < hits; a++) { @@ -2577,27 +2577,27 @@ static void armature_circle_select(ViewContext *vc, int select, const int mval[2 } } +static void do_circle_select_mball__doSelectElem(void *userData, struct MetaElem *ml, int x, int y) +{ + CircleSelectUserData *data = userData; + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; + + if (len_squared_v2(delta) <= data->radius_squared) { + if (data->select) ml->flag |= SELECT; + else ml->flag &= ~SELECT; + data->is_change = TRUE; + } +} static void mball_circle_select(ViewContext *vc, int select, const int mval[2], float rad) { - const float radius_squared = rad * rad; - const float mval_fl[2] = {mval[0], mval[1]}; + CircleSelectUserData data; - MetaBall *mb = (MetaBall *)vc->obedit->data; - MetaElem *ml; + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - for (ml = mb->editelems->first; ml; ml = ml->next) { - float screen_co[2]; - if (ED_view3d_project_float_object(vc->ar, &ml->x, screen_co, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) - { - if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) { - if (select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; - } - } - } + mball_foreachScreenElem(vc, do_circle_select_mball__doSelectElem, &data); } /** Callbacks for circle selection in Editmode */ From 6a164c7f72e679985e78f92b635426db73a93022 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Oct 2012 03:33:11 +0000 Subject: [PATCH 125/143] fix [#32779] Bmesh module: assigning to bm.select_mode crashes Blender if bmesh is empty was missing set typecheck --- source/blender/python/generic/py_capi_utils.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index a2521484c88..2b4dcf93b66 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -760,7 +760,6 @@ int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *valu return 0; } -/* 'value' _must_ be a set type, error check before calling */ int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix) { /* set of enum items, concatenate all values with OR */ @@ -771,6 +770,15 @@ int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, co Py_ssize_t hash = 0; PyObject *key; + PyC_ObSpit("", value); + + if (!PySet_Check(value)) { + PyErr_Format(PyExc_TypeError, + "%.200s expected a set, not %.200s", + error_prefix, Py_TYPE(value)->tp_name); + return -1; + } + *r_value = 0; while (_PySet_NextEntry(value, &pos, &key, &hash)) { @@ -778,7 +786,7 @@ int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, co if (param == NULL) { PyErr_Format(PyExc_TypeError, - "%.200s expected a string, not %.200s", + "%.200s set must contain strings, not %.200s", error_prefix, Py_TYPE(key)->tp_name); return -1; } From b26ccf0aff3ab8871923ade7993b8f8d3a3f75f5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Oct 2012 03:34:52 +0000 Subject: [PATCH 126/143] toggle cut through in the knife tool now refreshes (before you had to wave the mouse about to see the result). also remove print from last commit. --- source/blender/blenkernel/BKE_mball.h | 2 +- source/blender/blenkernel/intern/mball.c | 2 +- source/blender/editors/mesh/editmesh_knife.c | 1 + source/blender/python/generic/py_capi_utils.c | 2 -- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index d591b44e489..7a0eea1b009 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -59,7 +59,7 @@ void BKE_mball_properties_copy(struct Scene *scene, struct Object *active_object int BKE_mball_minmax(struct MetaBall *mb, float min[3], float max[3]); int BKE_mball_center_median(struct MetaBall *mb, float r_cent[3]); int BKE_mball_center_bounds(struct MetaBall *mb, float r_cent[3]); -void BKE_mball_translate(struct MetaBall *mb, float offset[3]); +void BKE_mball_translate(struct MetaBall *mb, const float offset[3]); struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type); diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index de7fdece7dd..592101fbd31 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -2388,7 +2388,7 @@ int BKE_mball_center_bounds(MetaBall *mb, float r_cent[3]) return 0; } -void BKE_mball_translate(MetaBall *mb, float offset[3]) +void BKE_mball_translate(MetaBall *mb, const float offset[3]) { MetaElem *ml; diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 969f185810e..4f4fc27582c 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -3130,6 +3130,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) break; case KNF_MODAL_CUT_THROUGH_TOGGLE: kcd->cut_through = !kcd->cut_through; + knifetool_update_mval(kcd, event->mval); /* refresh knife path */ knife_update_header(C, kcd); break; case KNF_MODAL_NEW_CUT: diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 2b4dcf93b66..9492c8384dc 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -770,8 +770,6 @@ int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, co Py_ssize_t hash = 0; PyObject *key; - PyC_ObSpit("", value); - if (!PySet_Check(value)) { PyErr_Format(PyExc_TypeError, "%.200s expected a set, not %.200s", From 950ac472507432339ac0d4b126ac48137bf39e9c Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sat, 6 Oct 2012 03:56:09 +0000 Subject: [PATCH 127/143] Bugfix [#32789] (Minor) Different types used between func declaration and definition (EDBM_selectmode_convert()) Cheers to Sebastian Nell (codemanx) for catching this. --- source/blender/editors/include/ED_mesh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 028b5db6beb..093872c79f6 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -149,7 +149,7 @@ struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, int *dist); int EDBM_select_pick(struct bContext *C, const int mval[2], short extend, short deselect, short toggle); void EDBM_selectmode_set(struct BMEditMesh *em); -void EDBM_selectmode_convert(struct BMEditMesh *em, short selectmode_old, const short selectmode_new); +void EDBM_selectmode_convert(struct BMEditMesh *em, const short selectmode_old, const short selectmode_new); void EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const short select); From c001bd81a75b60a491ae30947736eea78260827a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Sat, 6 Oct 2012 07:03:03 +0000 Subject: [PATCH 128/143] Color Management: fixed loading configuration from non-ascii paths Used the same hack as BLI gzip is using -- calculate short path and send it to OCIO library. --- source/blender/blenlib/BLI_fileops.h | 2 ++ source/blender/blenlib/intern/fileops.c | 28 +++++++++++-------- source/blender/imbuf/intern/colormanagement.c | 13 ++++++++- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index e8d6336a994..c278370d211 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -96,6 +96,8 @@ void BLI_file_free_lines(struct LinkNode *lines); # ifndef O_BINARY # define O_BINARY 0 # endif +#else +void BLI_get_short_name(char short_name[256], const char *filename); #endif #ifdef __cplusplus diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index 453463beaa8..1df904f617a 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -210,6 +210,22 @@ FILE *BLI_fopen(const char *filename, const char *mode) return ufopen(filename, mode); } +void BLI_get_short_name(char short_name[256], const char *filename) +{ + wchar_t short_name_16[256]; + int i = 0; + + UTF16_ENCODE(filename); + + GetShortPathNameW(filename_16, short_name_16, 256); + + for (i = 0; i < 256; i++) { + short_name[i] = (char)short_name_16[i]; + } + + UTF16_UN_ENCODE(filename); +} + void *BLI_gzopen(const char *filename, const char *mode) { gzFile gzfile; @@ -218,25 +234,15 @@ void *BLI_gzopen(const char *filename, const char *mode) return 0; } else { - wchar_t short_name_16[256]; char short_name[256]; - int i = 0; /* xxx Creates file before transcribing the path */ if (mode[0] == 'w') fclose(ufopen(filename, "a")); - UTF16_ENCODE(filename); - - GetShortPathNameW(filename_16, short_name_16, 256); - - for (i = 0; i < 256; i++) { - short_name[i] = (char)short_name_16[i]; - } + BLI_get_short_name(short_name, filename); gzfile = gzopen(short_name, mode); - - UTF16_UN_ENCODE(filename); } return gzfile; diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index c7bdd532bb9..37510c10e9a 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -51,6 +51,7 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_fileops.h" #include "BLI_math.h" #include "BLI_math_color.h" #include "BLI_path_util.h" @@ -574,10 +575,20 @@ void colormanagement_init(void) if (config == NULL) { configdir = BLI_get_folder(BLENDER_DATAFILES, "colormanagement"); - if (configdir) { + if (configdir) { BLI_join_dirfile(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE); +#ifdef WIN32 + { + /* quite a hack to support loading configuration from path with non-acii symbols */ + + char short_name[256]; + BLI_get_short_name(short_name, configfile); + config = OCIO_configCreateFromFile(short_name); + } +#else config = OCIO_configCreateFromFile(configfile); +#endif } } From a2d8cf333fb61de97270c1dce732a72915f20dd4 Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Sat, 6 Oct 2012 11:00:45 +0000 Subject: [PATCH 129/143] Better support for LLVM linking, needed for static OSL library. This adds cmake code for LLVM on linux and updates the cmake code used for OSX. LLVM is linked like other external libraries now, by using the setup_liblinks and setup_libdirs macros instead of the PLATFORM_LINKFLAGS variable. The use of llvm-config for getting a list of libraries can also be simplified quite a bit. Caching the LLVM_DIRECTORY and LLVM_VERSION strings could be nicer though. --- CMakeLists.txt | 174 +++++++++++++++++++++------------ build_files/cmake/macros.cmake | 6 ++ 2 files changed, 120 insertions(+), 60 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a91b5a3bdac..9e031d0358e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -254,6 +254,9 @@ set(CYCLES_CUDA_BINARIES_ARCH sm_13 sm_20 sm_21 sm_30 CACHE STRING "CUDA archite mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH) unset(PLATFORM_DEFAULT) +# LLVM +option(WITH_LLVM "Use LLVM" OFF) + # disable for now, but plan to support on all platforms eventually option(WITH_MEM_JEMALLOC "Enable malloc replacement (http://www.canonware.com/jemalloc)" OFF) mark_as_advanced(WITH_MEM_JEMALLOC) @@ -371,6 +374,11 @@ if(WITH_CYCLES OR WITH_MOD_BOOLEAN) set(WITH_BOOST ON) endif() +# auto enable llvm for cycles_osl +if(WITH_CYCLES_OSL) + set(WITH_LLVM ON) +endif() + # don't store paths to libs for portable distribution if(WITH_INSTALL_PORTABLE) set(CMAKE_SKIP_BUILD_RPATH TRUE) @@ -704,6 +712,56 @@ if(UNIX AND NOT APPLE) endif() endif() + if(WITH_LLVM) + set(LLVM_DIRECTORY ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation") + set(LLVM_VERSION "3.0" CACHE STRING "Version of LLVM to use" "") + set(LLVM_STATIC YES) + if(LLVM_DIRECTORY) + set(LLVM_CONFIG "${LLVM_DIRECTORY}/bin/llvm-config") + else() + set(LLVM_CONFIG llvm-config) + endif() + execute_process(COMMAND ${LLVM_CONFIG} --version + OUTPUT_VARIABLE LLVM_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${LLVM_CONFIG} --prefix + OUTPUT_VARIABLE LLVM_DIRECTORY + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${LLVM_CONFIG} --libdir + OUTPUT_VARIABLE LLVM_LIB_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${LLVM_CONFIG} --includedir + OUTPUT_VARIABLE LLVM_INCLUDES + OUTPUT_STRIP_TRAILING_WHITESPACE) + find_library(LLVM_LIBRARY + NAMES libLLVMAnalysis.a # first of a whole bunch of libs to get + PATHS ${LLVM_LIB_DIR}) + message(STATUS "LLVM version = ${LLVM_VERSION}") + message(STATUS "LLVM dir = ${LLVM_DIRECTORY}") + message(STATUS "LLVM includes = ${LLVM_INCLUDES}") + message(STATUS "LLVM lib dir = ${LLVM_LIB_DIR}") + + if(LLVM_LIBRARY AND LLVM_INCLUDES AND LLVM_DIRECTORY AND LLVM_LIB_DIR) + # ensure include directory is added (in case of non-standard locations + include_directories(BEFORE "${LLVM_INCLUDES}") + string(REGEX REPLACE "\\." "" OSL_LLVM_VERSION ${LLVM_VERSION}) + message(STATUS "LLVM OSL_LLVM_VERSION = ${OSL_LLVM_VERSION}") + add_definitions("-DOSL_LLVM_VERSION=${OSL_LLVM_VERSION}") + if(LLVM_STATIC) + # if static LLVM libraries were requested, use llvm-config to generate + # the list of what libraries we need, and substitute that in the right + # way for LLVM_LIBRARY. + execute_process(COMMAND ${LLVM_CONFIG} --libfiles + OUTPUT_VARIABLE LLVM_LIBRARY + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REPLACE " " ";" LLVM_LIBRARY ${LLVM_LIBRARY}) + endif() + message(STATUS "LLVM library = ${LLVM_LIBRARY}") + else() + message(FATAL_ERROR "LLVM not found.") + endif() + endif() + if(WITH_CYCLES_OSL) set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation") @@ -1559,6 +1617,56 @@ elseif(APPLE) set(OPENCOLORIO_DEFINITIONS "-DOCIO_STATIC_BUILD") endif() + if(WITH_LLVM) + set(LLVM_DIRECTORY ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation") + set(LLVM_VERSION "3.1" CACHE STRING "Version of LLVM to use" "") + set(LLVM_STATIC YES) + if(LLVM_DIRECTORY) + set(LLVM_CONFIG "${LLVM_DIRECTORY}/bin/llvm-config") + else() + set(LLVM_CONFIG llvm-config) + endif() + execute_process(COMMAND ${LLVM_CONFIG} --version + OUTPUT_VARIABLE LLVM_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${LLVM_CONFIG} --prefix + OUTPUT_VARIABLE LLVM_DIRECTORY + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${LLVM_CONFIG} --libdir + OUTPUT_VARIABLE LLVM_LIB_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${LLVM_CONFIG} --includedir + OUTPUT_VARIABLE LLVM_INCLUDES + OUTPUT_STRIP_TRAILING_WHITESPACE) + find_library(LLVM_LIBRARY + NAMES libLLVMAnalysis.a # first of a whole bunch of libs to get + PATHS ${LLVM_LIB_DIR}) + message(STATUS "LLVM version = ${LLVM_VERSION}") + message(STATUS "LLVM dir = ${LLVM_DIRECTORY}") + message(STATUS "LLVM includes = ${LLVM_INCLUDES}") + message(STATUS "LLVM lib dir = ${LLVM_LIB_DIR}") + + if(LLVM_LIBRARY AND LLVM_INCLUDES AND LLVM_DIRECTORY AND LLVM_LIB_DIR) + # ensure include directory is added (in case of non-standard locations + include_directories(BEFORE "${LLVM_INCLUDES}") + string(REGEX REPLACE "\\." "" OSL_LLVM_VERSION ${LLVM_VERSION}) + message(STATUS "LLVM OSL_LLVM_VERSION = ${OSL_LLVM_VERSION}") + add_definitions("-DOSL_LLVM_VERSION=${OSL_LLVM_VERSION}") + if(LLVM_STATIC) + # if static LLVM libraries were requested, use llvm-config to generate + # the list of what libraries we need, and substitute that in the right + # way for LLVM_LIBRARY. + execute_process(COMMAND ${LLVM_CONFIG} --libfiles + OUTPUT_VARIABLE LLVM_LIBRARY + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REPLACE " " ";" LLVM_LIBRARY ${LLVM_LIBRARY}) + endif() + message(STATUS "LLVM library = ${LLVM_LIBRARY}") + else() + message(FATAL_ERROR "LLVM not found.") + endif() + endif() + if(WITH_CYCLES_OSL) set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation") @@ -1582,66 +1690,6 @@ elseif(APPLE) endif() include_directories(${OSL_INCLUDES}) - - - # LLVM library setup, needed for osl - - set(LLVM_DIRECTORY "${LIBDIR}/llvm") - set(LLVM_STATIC YES) - if (LLVM_DIRECTORY) - set (LLVM_CONFIG "${LLVM_DIRECTORY}/bin/llvm-config") - else () - set (LLVM_CONFIG llvm-config) - endif () - execute_process (COMMAND ${LLVM_CONFIG} --version - OUTPUT_VARIABLE LLVM_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process (COMMAND ${LLVM_CONFIG} --prefix - OUTPUT_VARIABLE LLVM_DIRECTORY - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process (COMMAND ${LLVM_CONFIG} --libdir - OUTPUT_VARIABLE LLVM_LIB_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process (COMMAND ${LLVM_CONFIG} --includedir - OUTPUT_VARIABLE LLVM_INCLUDES - OUTPUT_STRIP_TRAILING_WHITESPACE) - find_library ( LLVM_LIBRARY - NAMES libLLVMAnalysis.a # first of a whole bunch of libs to get - PATHS ${LLVM_LIB_DIR}) - message (STATUS "LLVM version = ${LLVM_VERSION}") - message (STATUS "LLVM dir = ${LLVM_DIRECTORY}") - message (STATUS "LLVM includes = ${LLVM_INCLUDES}") - message (STATUS "LLVM lib dir = ${LLVM_LIB_DIR}") - - if (LLVM_LIBRARY AND LLVM_INCLUDES AND LLVM_DIRECTORY AND LLVM_LIB_DIR) - # ensure include directory is added (in case of non-standard locations - include_directories (BEFORE "${LLVM_INCLUDES}") - string (REGEX REPLACE "\\." "" OSL_LLVM_VERSION ${LLVM_VERSION}) - message (STATUS "LLVM OSL_LLVM_VERSION = ${OSL_LLVM_VERSION}") - add_definitions ("-DOSL_LLVM_VERSION=${OSL_LLVM_VERSION}") - if (LLVM_STATIC) - # if static LLVM libraries were requested, use llvm-config to generate - # the list of what libraries we need, and substitute that in the right - # way for LLVM_LIBRARY. - set (LLVM_LIBRARY "") - execute_process (COMMAND ${LLVM_CONFIG} --libs - OUTPUT_VARIABLE llvm_library_list - OUTPUT_STRIP_TRAILING_WHITESPACE) - string (REPLACE "-l" "" llvm_library_list ${llvm_library_list}) - string (REPLACE " " ";" llvm_library_list ${llvm_library_list}) - foreach (f ${llvm_library_list}) - list (APPEND LLVM_LIBRARY "${LLVM_LIB_DIR}/lib${f}.a") - endforeach () - endif () - string (REPLACE ";" " " LLVM_LIBRARY "${LLVM_LIBRARY}") - message (STATUS "LLVM library = ${LLVM_LIBRARY}") - else () - message (FATAL_ERROR "LLVM not found.") - endif () - set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} ${LLVM_LIBRARY}") - - # end LLVM library setup - endif() set(EXETYPE MACOSX_BUNDLE) @@ -1677,6 +1725,12 @@ if(WITH_CYCLES) if(NOT WITH_BOOST) message(FATAL_ERROR "Cycles reqires WITH_BOOST, the library may not have been found. Configure BOOST or disable WITH_CYCLES") endif() + + if(WITH_CYCLES_OSL) + if(NOT WITH_LLVM) + message(FATAL_ERROR "Cycles OSL reqires WITH_LLVM, the library may not have been found. Configure LLVM or disable WITH_CYCLES_OSL") + endif() + endif() endif() diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 43cfb31c03c..750903b12d7 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -244,6 +244,9 @@ macro(SETUP_LIBDIRS) link_directories(${PCRE_LIBPATH}) link_directories(${EXPAT_LIBPATH}) endif() + if(WITH_LLVM) + link_directories(${LLVM_LIB_DIR}) + endif() if(WITH_MEM_JEMALLOC) link_directories(${JEMALLOC_LIBPATH}) endif() @@ -382,6 +385,9 @@ macro(setup_liblinks if(WITH_CYCLES_OSL) target_link_libraries(${target} ${OSL_LIBRARIES}) endif() + if(WITH_LLVM) + target_link_libraries(${target} ${LLVM_LIBRARY}) + endif() if(WIN32 AND NOT UNIX) target_link_libraries(${target} ${PTHREADS_LIBRARIES}) endif() From 098d611c7b8dc5178c5dd89fc02148ab2ed5b983 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 6 Oct 2012 11:52:54 +0000 Subject: [PATCH 130/143] Fix for UV texture coordinate problem in cycles, after recent fix. --- intern/cycles/render/nodes.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 8173f5d0af2..4e16eea2774 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1650,10 +1650,12 @@ TextureCoordinateNode::TextureCoordinateNode() void TextureCoordinateNode::attributes(AttributeRequestSet *attributes) { - if(!output("Generated")->links.empty()) - attributes->add(ATTR_STD_GENERATED); - if(!output("UV")->links.empty()) - attributes->add(ATTR_STD_UV); + if(!from_dupli) { + if(!output("Generated")->links.empty()) + attributes->add(ATTR_STD_GENERATED); + if(!output("UV")->links.empty()) + attributes->add(ATTR_STD_UV); + } ShaderNode::attributes(attributes); } @@ -1704,14 +1706,14 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler) out = output("UV"); if(!out->links.empty()) { if(from_dupli) { + compiler.stack_assign(out); + compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, out->stack_offset); + } + else { int attr = compiler.attribute(ATTR_STD_UV); compiler.stack_assign(out); compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3); } - else { - compiler.stack_assign(out); - compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, out->stack_offset); - } } out = output("Object"); From b6a803fb368953bca1a7480694a7ab6d97439fad Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Oct 2012 12:00:54 +0000 Subject: [PATCH 131/143] fix reading past array bounds for nearest_uv_between() and draw_tracking_tracks(). --- source/blender/editors/space_clip/clip_draw.c | 2 +- source/blender/editors/uvedit/uvedit_ops.c | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index b22c9a60bdc..5e940df2a30 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -1126,7 +1126,7 @@ static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip, if (MARKER_VISIBLE(sc, track, marker)) { float npos[2]; - copy_v4_v4(vec, track->bundle_pos); + copy_v3_v3(vec, track->bundle_pos); vec[3] = 1; mul_v4_m4v4(pos, mat, vec); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index f732808fa59..6e655faf35f 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -759,14 +759,13 @@ static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int UNUSED(nverts), i BMLoop *l; MLoopUV *luv; BMIter iter; - float m[3], v1[3], v2[3], c1, c2, *uv1 = NULL, /* *uv2, */ /* UNUSED */ *uv3 = NULL; + float m[2], v1[2], v2[2], c1, c2, *uv1 = NULL, /* *uv2, */ /* UNUSED */ *uv3 = NULL; int id1, id2, i; id1 = (id + efa->len - 1) % efa->len; id2 = (id + efa->len + 1) % efa->len; - m[0] = co[0] - uv[0]; - m[1] = co[1] - uv[1]; + sub_v2_v2v2(m, co, uv); i = 0; BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) { @@ -782,8 +781,8 @@ static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int UNUSED(nverts), i i++; } - sub_v3_v3v3(v1, uv1, uv); - sub_v3_v3v3(v2, uv3, uv); + sub_v2_v2v2(v1, uv1, uv); + sub_v2_v2v2(v2, uv3, uv); /* m and v2 on same side of v-v1? */ c1 = v1[0] * m[1] - v1[1] * m[0]; From 4cc29110aa8c2f351f357859752342af28dc8fd5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Oct 2012 12:04:09 +0000 Subject: [PATCH 132/143] fix writing past array bounds in imagewraposa(). also correct array sizes in othere areas. --- source/blender/blenlib/intern/math_vector_inline.c | 2 +- source/blender/editors/mesh/editmesh_rip.c | 2 +- source/blender/editors/mesh/editmesh_select.c | 2 +- source/blender/editors/sculpt_paint/paint_utils.c | 2 +- source/blender/editors/space_view3d/drawobject.c | 4 ++-- source/blender/render/intern/include/texture.h | 2 +- source/blender/render/intern/source/imagetexture.c | 10 +++++----- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index c409e536b45..2cfe999e032 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -689,7 +689,7 @@ MINLINE void normal_float_to_short_v3(short out[3], const float in[3]) /********************************* Comparison ********************************/ -MINLINE int is_zero_v2(const float v[3]) +MINLINE int is_zero_v2(const float v[2]) { return (v[0] == 0 && v[1] == 0); } diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 53b877f2a6e..001d584416f 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -57,7 +57,7 @@ /* helper to find edge for edge_rip */ static float edbm_rip_rip_edgedist(ARegion *ar, float mat[][4], - const float co1[3], const float co2[2], const float mvalf[2]) + const float co1[3], const float co2[3], const float mvalf[2]) { float vec1[3], vec2[3]; diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 801c9382c26..da87767e492 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -448,7 +448,7 @@ BMVert *EDBM_vert_find_nearest(ViewContext *vc, int *dist, short sel, short stri } /* returns labda for closest distance v1 to line-piece v2 - v3 */ -float labda_PdistVL2Dfl(const float v1[3], const float v2[3], const float v3[3]) +float labda_PdistVL2Dfl(const float v1[2], const float v2[2], const float v3[2]) { float rc[2], len; diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 29a59651cf7..b3679516fff 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -201,7 +201,7 @@ static void imapaint_project(Object *ob, float model[][4], float proj[][4], cons static void imapaint_tri_weights(Object *ob, const float v1[3], const float v2[3], const float v3[3], - const float co[3], float w[3]) + const float co[2], float w[3]) { float pv1[4], pv2[4], pv3[4], h[3], divw; float model[4][4], proj[4][4], wmat[3][3], invwmat[3][3]; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index a6f4527cf98..84a69b811ca 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -5945,8 +5945,8 @@ static int drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if (mb->editelems) { if ((G.f & G_PICKSEL) == 0) { - unsigned char wire_col[3]; - UI_GetThemeColor3ubv(TH_WIRE, wire_col); + unsigned char wire_col[4]; + UI_GetThemeColor4ubv(TH_WIRE, wire_col); glColor3ubv(wire_col); drawDispList(scene, v3d, rv3d, base, dt, dflag, wire_col); diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h index e8f171fe383..4b9fa2d2042 100644 --- a/source/blender/render/intern/include/texture.h +++ b/source/blender/render/intern/include/texture.h @@ -76,7 +76,7 @@ void render_realtime_texture(struct ShadeInput *shi, struct Image *ima); /* imagetexture.h */ -int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], const float dxt[3], const float dyt[3], struct TexResult *texres); +int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], const float dxt[2], const float dyt[2], struct TexResult *texres); int imagewrap(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], struct TexResult *texres); void image_sample(struct Image *ima, float fx, float fy, float dx, float dy, float result[4]); diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index f62ed909094..6c86f2a2999 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -1018,7 +1018,7 @@ static void image_mipmap_test(Tex *tex, ImBuf *ibuf) } -static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[3], float dyt[3], TexResult *texres) +static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres) { TexResult texr; float fx, fy, minx, maxx, miny, maxy; @@ -1412,17 +1412,17 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex } -int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[3], const float DYT[3], TexResult *texres) +int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[2], const float DYT[2], TexResult *texres) { TexResult texr; - float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[3], dyt[3]; + float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[2], dyt[2]; float maxd, pixsize, val1, val2, val3; int curmap, retval, imaprepeat, imapextend; /* TXF: since dxt/dyt might be modified here and since they might be needed after imagewraposa() call, * make a local copy here so that original vecs remain untouched */ - copy_v3_v3(dxt, DXT); - copy_v3_v3(dyt, DYT); + copy_v2_v2(dxt, DXT); + copy_v2_v2(dyt, DYT); /* anisotropic filtering */ if (tex->texfilter != TXF_BOX) From 1e2f475512e5d5614078a6154cfd38a0e05fa6ea Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Oct 2012 12:36:21 +0000 Subject: [PATCH 133/143] added simple checker for array sizes, uses clang to parse C/C++, Warns if an array is passed to a function where the array is declared larger, eg float[2] argument is passed function defined as float[3], (or a greater size). Existing free static checkers dont do this from what I can tell. --- GNUmakefile | 5 + build_files/cmake/clang_array_check.py | 337 ++++++++++++++++++ .../cmake/cmake_static_check_clang_array.py | 76 ++++ 3 files changed, 418 insertions(+) create mode 100644 build_files/cmake/clang_array_check.py create mode 100644 build_files/cmake/cmake_static_check_clang_array.py diff --git a/GNUmakefile b/GNUmakefile index 7b333a5fc77..90d76dfe432 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -171,6 +171,7 @@ help: @echo "" @echo "Static Source Code Checking (not associated with building blender)" @echo " * check_cppcheck - run blender source through cppcheck (C & C++)" + @echo " * check_clang_array - run blender source through clang array checking script (C & C++)" @echo " * check_splint - run blenders source through splint (C only)" @echo " * check_sparse - run blenders source through sparse (C only)" @echo " * check_smatch - run blenders source through smatch (C only)" @@ -244,6 +245,10 @@ check_cppcheck: $(CMAKE_CONFIG) cd $(BUILD_DIR) ; python3.2 $(BLENDER_DIR)/build_files/cmake/cmake_static_check_cppcheck.py +check_clang_array: + $(CMAKE_CONFIG) + cd $(BUILD_DIR) ; python3.2 $(BLENDER_DIR)/build_files/cmake/cmake_static_check_clang_array.py + check_splint: $(CMAKE_CONFIG) cd $(BUILD_DIR) ; python3.2 $(BLENDER_DIR)/build_files/cmake/cmake_static_check_splint.py diff --git a/build_files/cmake/clang_array_check.py b/build_files/cmake/clang_array_check.py new file mode 100644 index 00000000000..df45648f975 --- /dev/null +++ b/build_files/cmake/clang_array_check.py @@ -0,0 +1,337 @@ +# --- +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# --- +# by Campbell Barton + +""" +Invocation: + + export CLANG_BIND_DIR="/dsk/src/llvm/tools/clang/bindings/python" + export CLANG_LIB_DIR="/opt/llvm/lib" + + python2 clang_array_check.py somefile.c -DSOME_DEFINE -I/some/include + +... defines and includes are optional + +""" + +# ----------------------------------------------------------------------------- +# predefined function/arg sizes, handy sometimes, but not complete... + +defs_precalc = { + "glColor3bv": {0: 3}, + "glColor4bv": {0: 4}, + + "glColor3ubv": {0: 3}, + "glColor4ubv": {0: 4}, + + "glColor4usv": {0: 3}, + "glColor4usv": {0: 4}, + + "glColor3fv": {0: 3}, + "glColor4fv": {0: 4}, + + "glColor3dv": {0: 3}, + "glColor4dv": {0: 4}, + + "glVertex2fv": {0: 2}, + "glVertex3fv": {0: 3}, + "glVertex4fv": {0: 4}, + + "glEvalCoord1fv": {0: 1}, + "glEvalCoord1dv": {0: 1}, + "glEvalCoord2fv": {0: 2}, + "glEvalCoord2dv": {0: 2}, + + "glRasterPos2dv": {0: 2}, + "glRasterPos3dv": {0: 3}, + "glRasterPos4dv": {0: 4}, + + "glRasterPos2fv": {0: 2}, + "glRasterPos3fv": {0: 3}, + "glRasterPos4fv": {0: 4}, + + "glRasterPos2sv": {0: 2}, + "glRasterPos3sv": {0: 3}, + "glRasterPos4sv": {0: 4}, + + "glTexCoord2fv": {0: 2}, + "glTexCoord3fv": {0: 3}, + "glTexCoord4fv": {0: 4}, + + "glTexCoord2dv": {0: 2}, + "glTexCoord3dv": {0: 3}, + "glTexCoord4dv": {0: 4}, + + "glNormal3fv": {0: 3}, + "glNormal3dv": {0: 3}, + "glNormal3bv": {0: 3}, + "glNormal3iv": {0: 3}, + "glNormal3sv": {0: 3}, +} + +# ----------------------------------------------------------------------------- + +import sys + +if 0: + # Examples with LLVM as the root dir: '/dsk/src/llvm' + + # path containing 'clang/__init__.py' + CLANG_BIND_DIR = "/dsk/src/llvm/tools/clang/bindings/python" + + # path containing libclang.so + CLANG_LIB_DIR = "/opt/llvm/lib" +else: + import os + CLANG_BIND_DIR = os.environ.get("CLANG_BIND_DIR") + CLANG_LIB_DIR = os.environ.get("CLANG_LIB_DIR") + + if CLANG_BIND_DIR is None: + print("$CLANG_BIND_DIR python binding dir not set") + if CLANG_LIB_DIR is None: + print("$CLANG_LIB_DIR clang lib dir not set") + +sys.path.append(CLANG_BIND_DIR) + +import clang +import clang.cindex +from clang.cindex import (CursorKind, + TypeKind, + TokenKind) + +clang.cindex.Config.set_library_path(CLANG_LIB_DIR) + +index = clang.cindex.Index.create() + +args = sys.argv[2:] +# print(args) + +tu = index.parse(sys.argv[1], args) +print 'Translation unit:', tu.spelling + +# ----------------------------------------------------------------------------- + +def function_parm_wash_tokens(parm): + # print(parm.kind) + assert parm.kind in (CursorKind.PARM_DECL, + CursorKind.VAR_DECL, # XXX, double check this + CursorKind.FIELD_DECL, + ) + + """ + Return tolens without trailing commads and 'const' + """ + + tokens = [t for t in parm.get_tokens()] + if not tokens: + return tokens + + #if tokens[-1].kind == To + # remove trailing char + if tokens[-1].kind == TokenKind.PUNCTUATION: + if tokens[-1].spelling in (",", ")", ";"): + tokens.pop() + #else: + # print(tokens[-1].spelling) + + t_new = [] + for t in tokens: + t_kind = t.kind + t_spelling = t.spelling + ok = True + if t_kind == TokenKind.KEYWORD: + if t_spelling in ("const", "restrict", "volatile"): + ok = False + elif t_spelling.startswith("__"): + ok = False # __restrict + elif t_kind in (TokenKind.COMMENT, ): + ok = False + + # Use these + elif t_kind in (TokenKind.LITERAL, + TokenKind.PUNCTUATION, + TokenKind.IDENTIFIER): + # use but ignore + pass + + else: + print("Unknown!", t_kind, t_spelling) + + # if its OK we will add + if ok: + t_new.append(t) + return t_new + + +def parm_size(node_child): + tokens = function_parm_wash_tokens(node_child) + + # print(" ".join([t.spelling for t in tokens])) + + # NOT PERFECT CODE, EXTRACT SIZE FROM TOKENS + if len(tokens) >= 3: # foo [ 1 ] + if ((tokens[-3].kind == TokenKind.PUNCTUATION and tokens[-3].spelling == "[") and + (tokens[-2].kind == TokenKind.LITERAL and tokens[-2].spelling.isdigit()) and + (tokens[-1].kind == TokenKind.PUNCTUATION and tokens[-1].spelling == "]")): + # --- + return int(tokens[-2].spelling) + return -1 + + + +def function_get_arg_sizes(node): + # Return a dict if (index: size) items + # {arg_indx: arg_array_size, ... ] + arg_sizes = {} + + if node.spelling == "BM_vert_create" or 1: + node_parms = [node_child for node_child in node.get_children() + if node_child.kind == CursorKind.PARM_DECL] + + for i, node_child in enumerate(node_parms): + + # print(node_child.kind, node_child.spelling) + #print(node_child.type.kind, node_child.spelling) # TypeKind.POINTER + + if node_child.type.kind == TypeKind.POINTER: + pointee = node_child.type.get_pointee() + if pointee.is_pod(): + size = parm_size(node_child) + if size != -1: + arg_sizes[i] = size + + return arg_sizes + + +# ----------------------------------------------------------------------------- +_defs = {} + +def lookup_function_size_def(func_id): + return _defs.get(func_id, ()) + +# ----------------------------------------------------------------------------- + +def file_check_arg_sizes(tu): + + # main checking function + def validate_arg_size(node): + """ + Loop over args and validate sizes for args we KNOW the size of. + """ + assert node.kind == CursorKind.CALL_EXPR + # print("---", " <~> ".join([" ".join([t.spelling for t in C.get_tokens()]) for C in node.get_children()])) + # print(node.location) + + # first child is the function call, skip that. + children = list(node.get_children()) + + if not children: + return # XXX, look into this, happens on C++ + + func = children[0] + + # get the func declaration! + # works but we can better scan for functions ahead of time. + if 0: + func_dec = func.get_definition() + if func_dec: + print("FD", " ".join([t.spelling for t in func_dec.get_tokens()])) + else: + # HRMP'f - why does this fail? + print("AA", " ".join([t.spelling for t in node.get_tokens()])) + else: + args_size_definition = () # dummy + + # get the key + tok = list(func.get_tokens()) + if tok: + func_id = tok[0].spelling + args_size_definition = lookup_function_size_def(func_id) + + if not args_size_definition: + return + + children = children[1:] + for i, node_child in enumerate(children): + children = list(node_child.get_children()) + + # skip if we dont have an index... + size_def = args_size_definition.get(i, -1) + + if size_def == -1: + continue + + #print([c.kind for c in children]) + # print(" ".join([t.spelling for t in node_child.get_tokens()])) + + if len(children) == 1: + arg = children[0] + if arg.kind in (CursorKind.DECL_REF_EXPR, + CursorKind.UNEXPOSED_EXPR): + + if arg.type.kind == TypeKind.POINTER: + dec = arg.get_definition() + if dec: + size = parm_size(dec) + + # size == 0 is for 'float *a' + if size != -1 and size != 0: + + # nice print! + ''' + print("".join([t.spelling for t in func.get_tokens()]), + i, + " ".join([t.spelling for t in dec.get_tokens()])) + ''' + + # testing + # size_def = 100 + + if size < size_def: + location = node.location + print("%s:%d:%d: argument %d is size %d, should be %d" % + (location.file, + location.line, + location.column, + i + 1, size, size_def + )) + + + # we dont really care what we are looking at, just scan entire file for + # function calls. + + def recursive_func_call_check(node): + + if node.kind == CursorKind.CALL_EXPR: + validate_arg_size(node) + + for c in node.get_children(): + recursive_func_call_check(c) + + recursive_func_call_check(tu.cursor) + + +# -- first pass, cache function definitions sizes + +# PRINT FUNC DEFINES +def recursive_arg_sizes(node, ): + # print(node.kind, node.spelling) + if node.kind == CursorKind.FUNCTION_DECL: + args_sizes = function_get_arg_sizes(node) + #if args_sizes: + # print(node.spelling, args_sizes) + _defs[node.spelling] = args_sizes + # print("adding", node.spelling) + for c in node.get_children(): + recursive_arg_sizes(c) +# cache function sizes +recursive_arg_sizes(tu.cursor) +_defs.update(defs_precalc) + +# --- second pass, check against def's +file_check_arg_sizes(tu) diff --git a/build_files/cmake/cmake_static_check_clang_array.py b/build_files/cmake/cmake_static_check_clang_array.py new file mode 100644 index 00000000000..ff15a130ee0 --- /dev/null +++ b/build_files/cmake/cmake_static_check_clang_array.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3.2 + +# ***** 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. +# +# Contributor(s): Campbell Barton +# +# ***** END GPL LICENSE BLOCK ***** + +# + +import project_source_info +import subprocess +import sys +import os + +CHECKER_IGNORE_PREFIX = [ + "extern", + "intern/moto", + ] + +CHECKER_BIN = "python2" + +CHECKER_ARGS = [ + os.path.join(os.path.dirname(__file__), "clang_array_check.py"), + # not sure why this is needed, but it is. + "-I" + os.path.join(project_source_info.SOURCE_DIR, "extern", "glew", "include"), + ] + + +def main(): + source_info = project_source_info.build_info(ignore_prefix_list=CHECKER_IGNORE_PREFIX) + + check_commands = [] + for c, inc_dirs, defs in source_info: + cmd = ([CHECKER_BIN] + + CHECKER_ARGS + + [c] + + [("-I%s" % i) for i in inc_dirs] + + [("-D%s" % d) for d in defs] + ) + + check_commands.append((c, cmd)) + + process_functions = [] + + def my_process(i, c, cmd): + percent = 100.0 * (i / (len(check_commands) - 1)) + percent_str = "[" + ("%.2f]" % percent).rjust(7) + " %:" + + sys.stdout.flush() + sys.stdout.write("%s " % percent_str) + + return subprocess.Popen(cmd) + + for i, (c, cmd) in enumerate(check_commands): + process_functions.append((my_process, (i, c, cmd))) + + project_source_info.queue_processes(process_functions) + + +if __name__ == "__main__": + main() From 2ecb4781a7634b7e95c7426c0f15e98abafee4a5 Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Sat, 6 Oct 2012 14:35:48 +0000 Subject: [PATCH 134/143] Fix for incomplete loading of liboslexec static library. This is needed in order to provide the osl_allocate_closure_component function for LLVM. --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e031d0358e..dc90f962968 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -770,8 +770,9 @@ if(UNIX AND NOT APPLE) find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib) - # WARNING! depends on correct order of OSL libs linking - list(APPEND OSL_LIBRARIES ${OSL_LIB_COMP} ${OSL_LIB_EXEC} ${OSL_LIB_QUERY}) + # Note: --whole-archive is needed to force loading of all symbols in liboslexec, + # otherwise LLVM is missing the osl_allocate_closure_component function + list(APPEND OSL_LIBRARIES ${OSL_LIB_COMP} -Wl,--whole-archive ${OSL_LIB_EXEC} -Wl,--no-whole-archive ${OSL_LIB_QUERY}) find_path(OSL_INCLUDES OSL/oslclosure.h PATHS ${CYCLES_OSL}/include) find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin) From 78978dcd805af2db50478fcba7fdf56d3fbca2ec Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Sat, 6 Oct 2012 16:28:02 +0000 Subject: [PATCH 135/143] Fix for a case of 'static initialization fiasco' with OSL closure variables. The parameter lists are using OIIO::TypeDesc static standards, which are also static variables. With static OSL libraries these are not initialized when the closure parameter lists are initialized, so OSL rejects the closure types. Putting static initialization into functions works just as well, but ensures the OIIO::TypeDesc access is delayed until initialization is complete. --- intern/cycles/kernel/osl/background.cpp | 23 +++++-- .../kernel/osl/bsdf_ashikhmin_velvet.cpp | 16 +++-- intern/cycles/kernel/osl/bsdf_diffuse.cpp | 28 +++++--- intern/cycles/kernel/osl/bsdf_microfacet.cpp | 68 ++++++++++++------- intern/cycles/kernel/osl/bsdf_oren_nayar.cpp | 16 +++-- intern/cycles/kernel/osl/bsdf_phong.cpp | 32 ++++++--- intern/cycles/kernel/osl/bsdf_reflection.cpp | 14 ++-- intern/cycles/kernel/osl/bsdf_refraction.cpp | 16 +++-- intern/cycles/kernel/osl/bsdf_transparent.cpp | 12 ++-- intern/cycles/kernel/osl/bsdf_ward.cpp | 20 +++--- intern/cycles/kernel/osl/bsdf_westin.cpp | 32 +++++---- intern/cycles/kernel/osl/bssrdf.cpp | 14 ++-- intern/cycles/kernel/osl/debug.cpp | 14 ++-- intern/cycles/kernel/osl/emissive.cpp | 12 ++-- intern/cycles/kernel/osl/osl_closures.cpp | 44 ++++++------ intern/cycles/kernel/osl/osl_closures.h | 44 ++++++------ intern/cycles/kernel/osl/vol_subsurface.cpp | 20 +++--- 17 files changed, 258 insertions(+), 167 deletions(-) diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp index 81812a46b6c..6290eed0af8 100644 --- a/intern/cycles/kernel/osl/background.cpp +++ b/intern/cycles/kernel/osl/background.cpp @@ -85,16 +85,25 @@ public: } }; -ClosureParam closure_background_params[] = { - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(GenericBackgroundClosure) -}; + +ClosureParam *closure_background_params() +{ + static ClosureParam params[] = { + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(GenericBackgroundClosure) + }; + return params; +} CLOSURE_PREPARE(closure_background_prepare, GenericBackgroundClosure) -ClosureParam closure_holdout_params[] = { - CLOSURE_FINISH_PARAM(HoldoutClosure) -}; +ClosureParam *closure_holdout_params() +{ + static ClosureParam params[] = { + CLOSURE_FINISH_PARAM(HoldoutClosure) + }; + return params; +} CLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure) diff --git a/intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp b/intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp index 2c545ca55e7..a1904d7f5d7 100644 --- a/intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp +++ b/intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp @@ -173,12 +173,16 @@ public: -ClosureParam bsdf_ashikhmin_velvet_params[] = { - CLOSURE_VECTOR_PARAM(AshikhminVelvetClosure, m_N), - CLOSURE_FLOAT_PARAM(AshikhminVelvetClosure, m_sigma), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(AshikhminVelvetClosure) -}; +ClosureParam *bsdf_ashikhmin_velvet_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(AshikhminVelvetClosure, m_N), + CLOSURE_FLOAT_PARAM(AshikhminVelvetClosure, m_sigma), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(AshikhminVelvetClosure) + }; + return params; +} CLOSURE_PREPARE(bsdf_ashikhmin_velvet_prepare, AshikhminVelvetClosure) diff --git a/intern/cycles/kernel/osl/bsdf_diffuse.cpp b/intern/cycles/kernel/osl/bsdf_diffuse.cpp index 582ac01d959..1e06d3b583f 100644 --- a/intern/cycles/kernel/osl/bsdf_diffuse.cpp +++ b/intern/cycles/kernel/osl/bsdf_diffuse.cpp @@ -168,17 +168,25 @@ public: } }; -ClosureParam bsdf_diffuse_params[] = { - CLOSURE_VECTOR_PARAM(DiffuseClosure, m_N), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(DiffuseClosure) -}; +ClosureParam *bsdf_diffuse_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(DiffuseClosure, m_N), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(DiffuseClosure) + }; + return params; +} -ClosureParam bsdf_translucent_params[] = { - CLOSURE_VECTOR_PARAM(TranslucentClosure, m_N), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(TranslucentClosure) -}; +ClosureParam *bsdf_translucent_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(TranslucentClosure, m_N), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(TranslucentClosure) + }; + return params; +} CLOSURE_PREPARE(bsdf_diffuse_prepare, DiffuseClosure) CLOSURE_PREPARE(bsdf_translucent_prepare, TranslucentClosure) diff --git a/intern/cycles/kernel/osl/bsdf_microfacet.cpp b/intern/cycles/kernel/osl/bsdf_microfacet.cpp index 09730d8c3e1..8446dbbe982 100644 --- a/intern/cycles/kernel/osl/bsdf_microfacet.cpp +++ b/intern/cycles/kernel/osl/bsdf_microfacet.cpp @@ -503,35 +503,51 @@ public: -ClosureParam bsdf_microfacet_ggx_params[] = { - CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<0>, m_N), - CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure<0>, m_ag), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<0>) -}; +ClosureParam *bsdf_microfacet_ggx_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<0>, m_N), + CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure<0>, m_ag), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<0>) + }; + return params; +} -ClosureParam bsdf_microfacet_ggx_refraction_params[] = { - CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<1>, m_N), - CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure<1>, m_ag), - CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure<1>, m_eta), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<1>) -}; +ClosureParam *bsdf_microfacet_ggx_refraction_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<1>, m_N), + CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure<1>, m_ag), + CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure<1>, m_eta), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<1>) + }; + return params; +} -ClosureParam bsdf_microfacet_beckmann_params[] = { - CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<0>, m_N), - CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure<0>, m_ab), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<0>) -}; +ClosureParam *bsdf_microfacet_beckmann_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<0>, m_N), + CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure<0>, m_ab), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<0>) + }; + return params; +} -ClosureParam bsdf_microfacet_beckmann_refraction_params[] = { - CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<1>, m_N), - CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure<1>, m_ab), - CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure<1>, m_eta), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<1>) -}; +ClosureParam *bsdf_microfacet_beckmann_refraction_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<1>, m_N), + CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure<1>, m_ab), + CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure<1>, m_eta), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<1>) + }; + return params; +} CLOSURE_PREPARE(bsdf_microfacet_ggx_prepare, MicrofacetGGXClosure<0>) CLOSURE_PREPARE(bsdf_microfacet_ggx_refraction_prepare, MicrofacetGGXClosure<1>) diff --git a/intern/cycles/kernel/osl/bsdf_oren_nayar.cpp b/intern/cycles/kernel/osl/bsdf_oren_nayar.cpp index 83d0e583695..2a00100c256 100644 --- a/intern/cycles/kernel/osl/bsdf_oren_nayar.cpp +++ b/intern/cycles/kernel/osl/bsdf_oren_nayar.cpp @@ -125,12 +125,16 @@ private: } }; -ClosureParam bsdf_oren_nayar_params[] = { - CLOSURE_VECTOR_PARAM(OrenNayarClosure, m_N), - CLOSURE_FLOAT_PARAM(OrenNayarClosure, m_sigma), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(OrenNayarClosure) -}; +ClosureParam *bsdf_oren_nayar_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(OrenNayarClosure, m_N), + CLOSURE_FLOAT_PARAM(OrenNayarClosure, m_sigma), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(OrenNayarClosure) + }; + return params; +} CLOSURE_PREPARE(bsdf_oren_nayar_prepare, OrenNayarClosure) diff --git a/intern/cycles/kernel/osl/bsdf_phong.cpp b/intern/cycles/kernel/osl/bsdf_phong.cpp index 57745079d33..1f430cc6f5d 100644 --- a/intern/cycles/kernel/osl/bsdf_phong.cpp +++ b/intern/cycles/kernel/osl/bsdf_phong.cpp @@ -258,18 +258,28 @@ public: -ClosureParam bsdf_phong_params[] = { - CLOSURE_VECTOR_PARAM(PhongClosure, m_N), - CLOSURE_FLOAT_PARAM (PhongClosure, m_exponent), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(PhongClosure) }; +ClosureParam *bsdf_phong_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(PhongClosure, m_N), + CLOSURE_FLOAT_PARAM (PhongClosure, m_exponent), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(PhongClosure) + }; + return params; +} -ClosureParam bsdf_phong_ramp_params[] = { - CLOSURE_VECTOR_PARAM (PhongRampClosure, m_N), - CLOSURE_FLOAT_PARAM (PhongRampClosure, m_exponent), - CLOSURE_COLOR_ARRAY_PARAM(PhongRampClosure, m_colors, PhongRampClosure::MAXCOLORS), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM (PhongRampClosure) }; +ClosureParam *bsdf_phong_ramp_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM (PhongRampClosure, m_N), + CLOSURE_FLOAT_PARAM (PhongRampClosure, m_exponent), + CLOSURE_COLOR_ARRAY_PARAM(PhongRampClosure, m_colors, PhongRampClosure::MAXCOLORS), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM (PhongRampClosure) + }; + return params; +} CLOSURE_PREPARE(bsdf_phong_prepare, PhongClosure) CLOSURE_PREPARE(bsdf_phong_ramp_prepare, PhongRampClosure) diff --git a/intern/cycles/kernel/osl/bsdf_reflection.cpp b/intern/cycles/kernel/osl/bsdf_reflection.cpp index 7041b4ced6f..1b85ec146d3 100644 --- a/intern/cycles/kernel/osl/bsdf_reflection.cpp +++ b/intern/cycles/kernel/osl/bsdf_reflection.cpp @@ -97,11 +97,15 @@ public: } }; -ClosureParam bsdf_reflection_params[] = { - CLOSURE_VECTOR_PARAM(ReflectionClosure, m_N), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(ReflectionClosure) -}; +ClosureParam *bsdf_reflection_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(ReflectionClosure, m_N), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(ReflectionClosure) + }; + return params; +} CLOSURE_PREPARE(bsdf_reflection_prepare, ReflectionClosure) diff --git a/intern/cycles/kernel/osl/bsdf_refraction.cpp b/intern/cycles/kernel/osl/bsdf_refraction.cpp index f56ad7b127c..76ee53f7929 100644 --- a/intern/cycles/kernel/osl/bsdf_refraction.cpp +++ b/intern/cycles/kernel/osl/bsdf_refraction.cpp @@ -108,12 +108,16 @@ public: } }; -ClosureParam bsdf_refraction_params[] = { - CLOSURE_VECTOR_PARAM(RefractionClosure, m_N), - CLOSURE_FLOAT_PARAM(RefractionClosure, m_eta), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(RefractionClosure) -}; +ClosureParam *bsdf_refraction_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(RefractionClosure, m_N), + CLOSURE_FLOAT_PARAM(RefractionClosure, m_eta), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(RefractionClosure) + }; + return params; +} CLOSURE_PREPARE(bsdf_refraction_prepare, RefractionClosure) diff --git a/intern/cycles/kernel/osl/bsdf_transparent.cpp b/intern/cycles/kernel/osl/bsdf_transparent.cpp index acde92530a2..29cef8e192f 100644 --- a/intern/cycles/kernel/osl/bsdf_transparent.cpp +++ b/intern/cycles/kernel/osl/bsdf_transparent.cpp @@ -87,10 +87,14 @@ public: -ClosureParam bsdf_transparent_params[] = { - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(TransparentClosure) -}; +ClosureParam *bsdf_transparent_params() +{ + static ClosureParam params[] = { + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(TransparentClosure) + }; + return params; +} CLOSURE_PREPARE(bsdf_transparent_prepare, TransparentClosure) diff --git a/intern/cycles/kernel/osl/bsdf_ward.cpp b/intern/cycles/kernel/osl/bsdf_ward.cpp index 4aacbc4ffc3..9d8d2fc4b76 100644 --- a/intern/cycles/kernel/osl/bsdf_ward.cpp +++ b/intern/cycles/kernel/osl/bsdf_ward.cpp @@ -211,14 +211,18 @@ public: -ClosureParam bsdf_ward_params[] = { - CLOSURE_VECTOR_PARAM(WardClosure, m_N), - CLOSURE_VECTOR_PARAM(WardClosure, m_T), - CLOSURE_FLOAT_PARAM(WardClosure, m_ax), - CLOSURE_FLOAT_PARAM(WardClosure, m_ay), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(WardClosure) -}; +ClosureParam *bsdf_ward_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(WardClosure, m_N), + CLOSURE_VECTOR_PARAM(WardClosure, m_T), + CLOSURE_FLOAT_PARAM(WardClosure, m_ax), + CLOSURE_FLOAT_PARAM(WardClosure, m_ay), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(WardClosure) + }; + return params; +} CLOSURE_PREPARE(bsdf_ward_prepare, WardClosure) diff --git a/intern/cycles/kernel/osl/bsdf_westin.cpp b/intern/cycles/kernel/osl/bsdf_westin.cpp index a476e8045f7..6716376ad3e 100644 --- a/intern/cycles/kernel/osl/bsdf_westin.cpp +++ b/intern/cycles/kernel/osl/bsdf_westin.cpp @@ -222,19 +222,27 @@ public: -ClosureParam bsdf_westin_backscatter_params[] = { - CLOSURE_VECTOR_PARAM(WestinBackscatterClosure, m_N), - CLOSURE_FLOAT_PARAM(WestinBackscatterClosure, m_roughness), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(WestinBackscatterClosure) -}; +ClosureParam *bsdf_westin_backscatter_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(WestinBackscatterClosure, m_N), + CLOSURE_FLOAT_PARAM(WestinBackscatterClosure, m_roughness), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(WestinBackscatterClosure) + }; + return params; +} -ClosureParam bsdf_westin_sheen_params[] = { - CLOSURE_VECTOR_PARAM(WestinSheenClosure, m_N), - CLOSURE_FLOAT_PARAM(WestinSheenClosure, m_edginess), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(WestinSheenClosure) -}; +ClosureParam *bsdf_westin_sheen_params() +{ + static ClosureParam params[] = { + CLOSURE_VECTOR_PARAM(WestinSheenClosure, m_N), + CLOSURE_FLOAT_PARAM(WestinSheenClosure, m_edginess), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(WestinSheenClosure) + }; + return params; +} CLOSURE_PREPARE(bsdf_westin_backscatter_prepare, WestinBackscatterClosure) CLOSURE_PREPARE(bsdf_westin_sheen_prepare, WestinSheenClosure) diff --git a/intern/cycles/kernel/osl/bssrdf.cpp b/intern/cycles/kernel/osl/bssrdf.cpp index b195cf513cd..889e8a54796 100644 --- a/intern/cycles/kernel/osl/bssrdf.cpp +++ b/intern/cycles/kernel/osl/bssrdf.cpp @@ -94,11 +94,15 @@ public: -ClosureParam closure_bssrdf_cubic_params[] = { - CLOSURE_COLOR_PARAM(BSSRDFCubicClosure, m_radius), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(BSSRDFCubicClosure) -}; +ClosureParam *closure_bssrdf_cubic_params() +{ + static ClosureParam params[] = { + CLOSURE_COLOR_PARAM(BSSRDFCubicClosure, m_radius), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(BSSRDFCubicClosure) + }; + return params; +} CLOSURE_PREPARE(closure_bssrdf_cubic_prepare, BSSRDFCubicClosure) diff --git a/intern/cycles/kernel/osl/debug.cpp b/intern/cycles/kernel/osl/debug.cpp index 768a9100e8a..ee5fb30371a 100644 --- a/intern/cycles/kernel/osl/debug.cpp +++ b/intern/cycles/kernel/osl/debug.cpp @@ -69,11 +69,15 @@ public: }; -ClosureParam closure_debug_params[] = { - CLOSURE_STRING_PARAM(DebugClosure, m_tag), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(DebugClosure) -}; +ClosureParam *closure_debug_params() +{ + static ClosureParam params[] = { + CLOSURE_STRING_PARAM(DebugClosure, m_tag), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(DebugClosure) + }; + return params; +} CLOSURE_PREPARE(closure_debug_prepare, DebugClosure) diff --git a/intern/cycles/kernel/osl/emissive.cpp b/intern/cycles/kernel/osl/emissive.cpp index 0a582c3f558..3ee57cbe6b6 100644 --- a/intern/cycles/kernel/osl/emissive.cpp +++ b/intern/cycles/kernel/osl/emissive.cpp @@ -97,10 +97,14 @@ public: -ClosureParam closure_emission_params[] = { - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(GenericEmissiveClosure) -}; +ClosureParam *closure_emission_params() +{ + static ClosureParam params[] = { + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(GenericEmissiveClosure) + }; + return params; +} CLOSURE_PREPARE(closure_emission_prepare, GenericEmissiveClosure) diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index a1a108a1b1d..9e99d4d2480 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -64,28 +64,28 @@ static void register_closure(OSL::ShadingSystem *ss, const char *name, int id, O void OSLShader::register_closures(OSL::ShadingSystem *ss) { - register_closure(ss, "diffuse", OSL_CLOSURE_BSDF_DIFFUSE_ID, bsdf_diffuse_params, bsdf_diffuse_prepare); - register_closure(ss, "oren_nayar", OSL_CLOSURE_BSDF_OREN_NAYAR_ID, bsdf_oren_nayar_params, bsdf_oren_nayar_prepare); - register_closure(ss, "translucent", OSL_CLOSURE_BSDF_TRANSLUCENT_ID, bsdf_translucent_params, bsdf_translucent_prepare); - register_closure(ss, "reflection", OSL_CLOSURE_BSDF_REFLECTION_ID, bsdf_reflection_params, bsdf_reflection_prepare); - register_closure(ss, "refraction", OSL_CLOSURE_BSDF_REFRACTION_ID, bsdf_refraction_params, bsdf_refraction_prepare); - register_closure(ss, "transparent", OSL_CLOSURE_BSDF_TRANSPARENT_ID, bsdf_transparent_params, bsdf_transparent_prepare); - register_closure(ss, "microfacet_ggx", OSL_CLOSURE_BSDF_MICROFACET_GGX_ID, bsdf_microfacet_ggx_params, bsdf_microfacet_ggx_prepare); - register_closure(ss, "microfacet_ggx_refraction", OSL_CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, bsdf_microfacet_ggx_refraction_params, bsdf_microfacet_ggx_refraction_prepare); - register_closure(ss, "microfacet_beckmann", OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_ID, bsdf_microfacet_beckmann_params, bsdf_microfacet_beckmann_prepare); - register_closure(ss, "microfacet_beckmann_refraction", OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID, bsdf_microfacet_beckmann_refraction_params, bsdf_microfacet_beckmann_refraction_prepare); - register_closure(ss, "ward", OSL_CLOSURE_BSDF_WARD_ID, bsdf_ward_params, bsdf_ward_prepare); - register_closure(ss, "phong", OSL_CLOSURE_BSDF_PHONG_ID, bsdf_phong_params, bsdf_phong_prepare); - register_closure(ss, "phong_ramp", OSL_CLOSURE_BSDF_PHONG_RAMP_ID, bsdf_phong_ramp_params, bsdf_phong_ramp_prepare); - register_closure(ss, "ashikhmin_velvet", OSL_CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, bsdf_ashikhmin_velvet_params, bsdf_ashikhmin_velvet_prepare); - register_closure(ss, "westin_backscatter", OSL_CLOSURE_BSDF_WESTIN_BACKSCATTER_ID, bsdf_westin_backscatter_params, bsdf_westin_backscatter_prepare); - register_closure(ss, "westin_sheen", OSL_CLOSURE_BSDF_WESTIN_SHEEN_ID, bsdf_westin_sheen_params, bsdf_westin_sheen_prepare); - register_closure(ss, "bssrdf_cubic", OSL_CLOSURE_BSSRDF_CUBIC_ID, closure_bssrdf_cubic_params, closure_bssrdf_cubic_prepare); - register_closure(ss, "emission", OSL_CLOSURE_EMISSION_ID, closure_emission_params, closure_emission_prepare); - register_closure(ss, "debug", OSL_CLOSURE_DEBUG_ID, closure_debug_params, closure_debug_prepare); - register_closure(ss, "background", OSL_CLOSURE_BACKGROUND_ID, closure_background_params, closure_background_prepare); - register_closure(ss, "holdout", OSL_CLOSURE_HOLDOUT_ID, closure_holdout_params, closure_holdout_prepare); - register_closure(ss, "subsurface", OSL_CLOSURE_SUBSURFACE_ID, closure_subsurface_params, closure_subsurface_prepare); + register_closure(ss, "diffuse", OSL_CLOSURE_BSDF_DIFFUSE_ID, bsdf_diffuse_params(), bsdf_diffuse_prepare); + register_closure(ss, "oren_nayar", OSL_CLOSURE_BSDF_OREN_NAYAR_ID, bsdf_oren_nayar_params(), bsdf_oren_nayar_prepare); + register_closure(ss, "translucent", OSL_CLOSURE_BSDF_TRANSLUCENT_ID, bsdf_translucent_params(), bsdf_translucent_prepare); + register_closure(ss, "reflection", OSL_CLOSURE_BSDF_REFLECTION_ID, bsdf_reflection_params(), bsdf_reflection_prepare); + register_closure(ss, "refraction", OSL_CLOSURE_BSDF_REFRACTION_ID, bsdf_refraction_params(), bsdf_refraction_prepare); + register_closure(ss, "transparent", OSL_CLOSURE_BSDF_TRANSPARENT_ID, bsdf_transparent_params(), bsdf_transparent_prepare); + register_closure(ss, "microfacet_ggx", OSL_CLOSURE_BSDF_MICROFACET_GGX_ID, bsdf_microfacet_ggx_params(), bsdf_microfacet_ggx_prepare); + register_closure(ss, "microfacet_ggx_refraction", OSL_CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, bsdf_microfacet_ggx_refraction_params(), bsdf_microfacet_ggx_refraction_prepare); + register_closure(ss, "microfacet_beckmann", OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_ID, bsdf_microfacet_beckmann_params(), bsdf_microfacet_beckmann_prepare); + register_closure(ss, "microfacet_beckmann_refraction", OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID, bsdf_microfacet_beckmann_refraction_params(), bsdf_microfacet_beckmann_refraction_prepare); + register_closure(ss, "ward", OSL_CLOSURE_BSDF_WARD_ID, bsdf_ward_params(), bsdf_ward_prepare); + register_closure(ss, "phong", OSL_CLOSURE_BSDF_PHONG_ID, bsdf_phong_params(), bsdf_phong_prepare); + register_closure(ss, "phong_ramp", OSL_CLOSURE_BSDF_PHONG_RAMP_ID, bsdf_phong_ramp_params(), bsdf_phong_ramp_prepare); + register_closure(ss, "ashikhmin_velvet", OSL_CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, bsdf_ashikhmin_velvet_params(), bsdf_ashikhmin_velvet_prepare); + register_closure(ss, "westin_backscatter", OSL_CLOSURE_BSDF_WESTIN_BACKSCATTER_ID, bsdf_westin_backscatter_params(), bsdf_westin_backscatter_prepare); + register_closure(ss, "westin_sheen", OSL_CLOSURE_BSDF_WESTIN_SHEEN_ID, bsdf_westin_sheen_params(), bsdf_westin_sheen_prepare); + register_closure(ss, "bssrdf_cubic", OSL_CLOSURE_BSSRDF_CUBIC_ID, closure_bssrdf_cubic_params(), closure_bssrdf_cubic_prepare); + register_closure(ss, "emission", OSL_CLOSURE_EMISSION_ID, closure_emission_params(), closure_emission_prepare); + register_closure(ss, "debug", OSL_CLOSURE_DEBUG_ID, closure_debug_params(), closure_debug_prepare); + register_closure(ss, "background", OSL_CLOSURE_BACKGROUND_ID, closure_background_params(), closure_background_prepare); + register_closure(ss, "holdout", OSL_CLOSURE_HOLDOUT_ID, closure_holdout_params(), closure_holdout_prepare); + register_closure(ss, "subsurface", OSL_CLOSURE_SUBSURFACE_ID, closure_subsurface_params(), closure_subsurface_prepare); } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index 00794183ca5..a69af45672d 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -64,28 +64,28 @@ enum { OSL_CLOSURE_SUBSURFACE_ID }; -extern OSL::ClosureParam bsdf_diffuse_params[]; -extern OSL::ClosureParam bsdf_oren_nayar_params[]; -extern OSL::ClosureParam bsdf_translucent_params[]; -extern OSL::ClosureParam bsdf_reflection_params[]; -extern OSL::ClosureParam bsdf_refraction_params[]; -extern OSL::ClosureParam bsdf_transparent_params[]; -extern OSL::ClosureParam bsdf_microfacet_ggx_params[]; -extern OSL::ClosureParam bsdf_microfacet_ggx_refraction_params[]; -extern OSL::ClosureParam bsdf_microfacet_beckmann_params[]; -extern OSL::ClosureParam bsdf_microfacet_beckmann_refraction_params[]; -extern OSL::ClosureParam bsdf_ward_params[]; -extern OSL::ClosureParam bsdf_phong_params[]; -extern OSL::ClosureParam bsdf_phong_ramp_params[]; -extern OSL::ClosureParam bsdf_ashikhmin_velvet_params[]; -extern OSL::ClosureParam bsdf_westin_backscatter_params[]; -extern OSL::ClosureParam bsdf_westin_sheen_params[]; -extern OSL::ClosureParam closure_bssrdf_cubic_params[]; -extern OSL::ClosureParam closure_emission_params[]; -extern OSL::ClosureParam closure_debug_params[]; -extern OSL::ClosureParam closure_background_params[]; -extern OSL::ClosureParam closure_holdout_params[]; -extern OSL::ClosureParam closure_subsurface_params[]; +OSL::ClosureParam *bsdf_diffuse_params(); +OSL::ClosureParam *bsdf_oren_nayar_params(); +OSL::ClosureParam *bsdf_translucent_params(); +OSL::ClosureParam *bsdf_reflection_params(); +OSL::ClosureParam *bsdf_refraction_params(); +OSL::ClosureParam *bsdf_transparent_params(); +OSL::ClosureParam *bsdf_microfacet_ggx_params(); +OSL::ClosureParam *bsdf_microfacet_ggx_refraction_params(); +OSL::ClosureParam *bsdf_microfacet_beckmann_params(); +OSL::ClosureParam *bsdf_microfacet_beckmann_refraction_params(); +OSL::ClosureParam *bsdf_ward_params(); +OSL::ClosureParam *bsdf_phong_params(); +OSL::ClosureParam *bsdf_phong_ramp_params(); +OSL::ClosureParam *bsdf_ashikhmin_velvet_params(); +OSL::ClosureParam *bsdf_westin_backscatter_params(); +OSL::ClosureParam *bsdf_westin_sheen_params(); +OSL::ClosureParam *closure_bssrdf_cubic_params(); +OSL::ClosureParam *closure_emission_params(); +OSL::ClosureParam *closure_debug_params(); +OSL::ClosureParam *closure_background_params(); +OSL::ClosureParam *closure_holdout_params(); +OSL::ClosureParam *closure_subsurface_params(); void bsdf_diffuse_prepare(OSL::RendererServices *, int id, void *data); void bsdf_oren_nayar_prepare(OSL::RendererServices *, int id, void *data); diff --git a/intern/cycles/kernel/osl/vol_subsurface.cpp b/intern/cycles/kernel/osl/vol_subsurface.cpp index 818a057b6cc..5845428ed43 100644 --- a/intern/cycles/kernel/osl/vol_subsurface.cpp +++ b/intern/cycles/kernel/osl/vol_subsurface.cpp @@ -122,14 +122,18 @@ public: -ClosureParam closure_subsurface_params[] = { - CLOSURE_FLOAT_PARAM(SubsurfaceClosure, m_eta), - CLOSURE_FLOAT_PARAM(SubsurfaceClosure, m_g), - CLOSURE_COLOR_PARAM(SubsurfaceClosure, m_mfp), - CLOSURE_COLOR_PARAM(SubsurfaceClosure, m_albedo), - CLOSURE_STRING_KEYPARAM("label"), - CLOSURE_FINISH_PARAM(SubsurfaceClosure) -}; +ClosureParam *closure_subsurface_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT_PARAM(SubsurfaceClosure, m_eta), + CLOSURE_FLOAT_PARAM(SubsurfaceClosure, m_g), + CLOSURE_COLOR_PARAM(SubsurfaceClosure, m_mfp), + CLOSURE_COLOR_PARAM(SubsurfaceClosure, m_albedo), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(SubsurfaceClosure) + }; + return params; +} CLOSURE_PREPARE(closure_subsurface_prepare, SubsurfaceClosure) From 1df170bb96158abebc123256df04cebe6a5f8f08 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 6 Oct 2012 16:42:11 +0000 Subject: [PATCH 136/143] Code cleanups for PBVH GPU buffers * De-duplicate GPU code to check if VBO should be used. * Add a flag to indicate if the buffer should be drawn smooth or not, rather than checking each time the node is drawn. --- source/blender/gpu/intern/gpu_buffers.c | 41 ++++++++++++++++--------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 3e5a14774c2..a0a379c3cee 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -1269,6 +1269,14 @@ void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, /* XXX: the rest of the code in this file is used for optimized PBVH * drawing and doesn't interact at all with the buffer code above */ +/* Return false if VBO is either unavailable or disabled by the user, + true otherwise */ +static int gpu_vbo_enabled(void) +{ + return (GLEW_ARB_vertex_buffer_object && + !(U.gameflags & USER_DISABLE_VBO)); +} + /* Convenience struct for building the VBO. */ typedef struct { float co[3]; @@ -1304,6 +1312,10 @@ struct GPU_Buffers { int has_hidden; unsigned int tot_tri, tot_quad; + + /* The PBVH ensures that either all faces in the node are + smooth-shaded or all faces are flat-shaded */ + int smooth; }; typedef enum { VBO_ENABLED, @@ -1434,6 +1446,7 @@ GPU_Buffers *GPU_build_mesh_buffers(int (*face_vert_indices)[4], buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers"); buffers->index_type = GL_UNSIGNED_SHORT; + buffers->smooth = mface[face_indices[0]].flag & ME_SMOOTH; /* Count the number of visible triangles */ for (i = 0, tottri = 0; i < totface; ++i) { @@ -1442,7 +1455,7 @@ GPU_Buffers *GPU_build_mesh_buffers(int (*face_vert_indices)[4], tottri += f->v4 ? 2 : 1; } - if (GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO)) + if (gpu_vbo_enabled()) glGenBuffersARB(1, &buffers->index_buf); if (buffers->index_buf) { @@ -1591,6 +1604,8 @@ void GPU_update_grid_buffers(GPU_Buffers *buffers, CCGElem **grids, buffers->grid_flag_mats = grid_flag_mats; buffers->gridkey = *key; + buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; + //printf("node updated %p\n", buffers); } @@ -1685,7 +1700,7 @@ static GLuint gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *to /* VBO is disabled; delete the previous buffer (if it exists) and * return an invalid handle */ - if (!GLEW_ARB_vertex_buffer_object || (U.gameflags & USER_DISABLE_VBO)) { + if (gpu_vbo_enabled()) { if (buffer) glDeleteBuffersARB(1, &buffer); return 0; @@ -1773,7 +1788,7 @@ GPU_Buffers *GPU_build_grid_buffers(int *grid_indices, int totgrid, #undef FILL_QUAD_BUFFER -static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth) +static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers) { const MVert *mvert = buffers->mvert; int i, j; @@ -1793,7 +1808,7 @@ static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth) glBegin((f->v4) ? GL_QUADS : GL_TRIANGLES); - if (smooth) { + if (buffers->smooth) { for (j = 0; j < S; j++) { if (has_mask) { gpu_color_from_mask_set(buffers->vmask[fv[j]]); @@ -1840,7 +1855,7 @@ static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth) } } -static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) +static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers) { const CCGKey *key = &buffers->gridkey; int i, j, x, y, gridsize = buffers->gridkey.grid_size; @@ -1873,7 +1888,7 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) if (paint_is_grid_face_hidden(gh, gridsize, x, y)) continue; - if (smooth) { + if (buffers->smooth) { for (j = 0; j < 4; j++) { if (has_mask) { gpu_color_from_mask_set(*CCG_elem_mask(key, e[j])); @@ -1903,7 +1918,7 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth) glEnd(); } - else if (smooth) { + else if (buffers->smooth) { for (y = 0; y < gridsize - 1; y++) { glBegin(GL_QUAD_STRIP); for (x = 0; x < gridsize; x++) { @@ -1970,19 +1985,15 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) const MFace *f = &buffers->mface[buffers->face_indices[0]]; if (!setMaterial(f->mat_nr + 1, NULL)) return; - - smooth = f->flag & ME_SMOOTH; - glShadeModel(smooth ? GL_SMOOTH : GL_FLAT); } else if (buffers->totgrid) { const DMFlagMat *f = &buffers->grid_flag_mats[buffers->grid_indices[0]]; if (!setMaterial(f->mat_nr + 1, NULL)) return; - - smooth = f->flag & ME_SMOOTH; - glShadeModel(smooth ? GL_SMOOTH : GL_FLAT); } + glShadeModel(buffers->smooth ? GL_SMOOTH : GL_FLAT); + if (buffers->vert_buf && buffers->index_buf) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); @@ -2042,10 +2053,10 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) } /* fallbacks if we are out of memory or VBO is disabled */ else if (buffers->totface) { - gpu_draw_buffers_legacy_mesh(buffers, smooth); + gpu_draw_buffers_legacy_mesh(buffers); } else if (buffers->totgrid) { - gpu_draw_buffers_legacy_grids(buffers, smooth); + gpu_draw_buffers_legacy_grids(buffers); } } From 0c0fa7dde66269f451d5b6ebe95860dd9e913d5f Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 6 Oct 2012 16:52:52 +0000 Subject: [PATCH 137/143] Improve flat-shaded VBO drawing for sculpt meshes Separate vertex copies are now made for flat-shading, such that the normal is correctly flat-shaded. The element index buffer is not created in this case. --- source/blender/gpu/intern/gpu_buffers.c | 110 +++++++++++++++++++----- 1 file changed, 90 insertions(+), 20 deletions(-) diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index a0a379c3cee..201162262b2 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -1397,28 +1397,88 @@ void GPU_update_mesh_buffers(GPU_Buffers *buffers, MVert *mvert, int *vert_indices, int totvert, const float *vmask) { VertexBufferFormat *vert_data; - int i; + int i, j, k; buffers->vmask = vmask; if (buffers->vert_buf) { + int totelem = (buffers->smooth ? totvert : (buffers->tot_tri * 3)); + /* Build VBO */ glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); glBufferDataARB(GL_ARRAY_BUFFER_ARB, - sizeof(VertexBufferFormat) * totvert, - NULL, GL_STATIC_DRAW_ARB); + sizeof(VertexBufferFormat) * totelem, + NULL, GL_STATIC_DRAW_ARB); + vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); if (vert_data) { - for (i = 0; i < totvert; ++i) { - MVert *v = mvert + vert_indices[i]; - VertexBufferFormat *out = vert_data + i; + /* Vertex data is shared if smooth-shaded, but seperate + copies are made for flat shading because normals + shouldn't be shared. */ + if (buffers->smooth) { + for (i = 0; i < totvert; ++i) { + MVert *v = mvert + vert_indices[i]; + VertexBufferFormat *out = vert_data + i; - copy_v3_v3(out->co, v->co); - memcpy(out->no, v->no, sizeof(short) * 3); - if (vmask) { - gpu_color_from_mask_copy(vmask[vert_indices[i]], - out->color); + copy_v3_v3(out->co, v->co); + memcpy(out->no, v->no, sizeof(short) * 3); + if (vmask) { + gpu_color_from_mask_copy(vmask[vert_indices[i]], + out->color); + } + } + } + else { + for (i = 0; i < buffers->totface; ++i) { + const MFace *f = &buffers->mface[buffers->face_indices[i]]; + const unsigned int *fv = &f->v1; + const int vi[2][3] = {{0, 1, 2}, {3, 0, 2}}; + float fno[3]; + short no[3]; + + float fmask; + + /* Face normal and mask */ + if (f->v4) { + normal_quad_v3(fno, + mvert[fv[0]].co, + mvert[fv[1]].co, + mvert[fv[2]].co, + mvert[fv[3]].co); + if (vmask) { + fmask = (vmask[fv[0]] + + vmask[fv[1]] + + vmask[fv[2]] + + vmask[fv[3]]) * 0.25; + } + } + else { + normal_tri_v3(fno, + mvert[fv[0]].co, + mvert[fv[1]].co, + mvert[fv[2]].co); + if (vmask) { + fmask = (vmask[fv[0]] + + vmask[fv[1]] + + vmask[fv[2]]) / 3.0f; + } + } + normal_float_to_short_v3(no, fno); + + for (j = 0; j < (f->v4 ? 2 : 1); j++) { + for (k = 0; k < 3; k++) { + const MVert *v = &mvert[fv[vi[j][k]]]; + VertexBufferFormat *out = vert_data; + + copy_v3_v3(out->co, v->co); + memcpy(out->no, no, sizeof(short) * 3); + if (vmask) + gpu_color_from_mask_copy(fmask, out->color); + + vert_data++; + } + } } } @@ -1454,8 +1514,11 @@ GPU_Buffers *GPU_build_mesh_buffers(int (*face_vert_indices)[4], if (!paint_is_face_hidden(f, mvert)) tottri += f->v4 ? 2 : 1; } - - if (gpu_vbo_enabled()) + + /* An element index buffer is used for smooth shading, but flat + shading requires separate vertex normals so an index buffer is + can't be used there. */ + if (gpu_vbo_enabled() && buffers->smooth) glGenBuffersARB(1, &buffers->index_buf); if (buffers->index_buf) { @@ -1499,7 +1562,7 @@ GPU_Buffers *GPU_build_mesh_buffers(int (*face_vert_indices)[4], glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } - if (buffers->index_buf) + if (buffers->index_buf || !buffers->smooth) glGenBuffersARB(1, &buffers->vert_buf); buffers->tot_tri = tottri; @@ -1979,7 +2042,6 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers) void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) { const int has_mask = (buffers->vmask || buffers->gridkey.has_mask); - int smooth = 0; if (buffers->totface) { const MFace *f = &buffers->mface[buffers->face_indices[0]]; @@ -1992,9 +2054,9 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) return; } - glShadeModel(buffers->smooth ? GL_SMOOTH : GL_FLAT); + glShadeModel((buffers->smooth || buffers->totface) ? GL_SMOOTH : GL_FLAT); - if (buffers->vert_buf && buffers->index_buf) { + if (buffers->vert_buf) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); if (has_mask) { @@ -2006,7 +2068,9 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) } glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); + + if (buffers->index_buf) + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); if (buffers->tot_quad) { char *offset = 0; @@ -2027,6 +2091,8 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) } } else { + int totelem = buffers->tot_tri * 3; + glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), (void *)offsetof(VertexBufferFormat, co)); glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), @@ -2036,11 +2102,15 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) (void *)offsetof(VertexBufferFormat, color)); } - glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0); + if (buffers->index_buf) + glDrawElements(GL_TRIANGLES, totelem, buffers->index_type, 0); + else + glDrawArrays(GL_TRIANGLES, 0, totelem); } glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + if (buffers->index_buf) + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); From f7d61831e175ffc506dc0e0d3362b0f40cdce5ae Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sat, 6 Oct 2012 17:11:53 +0000 Subject: [PATCH 138/143] Cycles / OSL: * OSL UI message did not show up when device type was GPU, but User Preferences were None. Also remove experimental check, more convenient for testing. --- intern/cycles/blender/addon/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 8d39b09ab0e..4f4b0371839 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -955,7 +955,7 @@ def draw_device(self, context): elif device_type == 'OPENCL' and cscene.feature_set == 'EXPERIMENTAL': layout.prop(cscene, "device") - if cscene.feature_set == 'EXPERIMENTAL' and cscene.device == 'CPU' and engine.with_osl(): + if engine.with_osl() and (cscene.device == 'CPU' or device_type == 'None'): layout.prop(cscene, "shading_system") From 1e433e81ad032c522eddb50a7020c62d54c53f3f Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 6 Oct 2012 17:51:52 +0000 Subject: [PATCH 139/143] Increase maximum octree depth to 12 Note that this is just an RNA change, underlying dualcon octree already supports even higher values. --- source/blender/makesrna/intern/rna_modifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index eb4660c18e8..1b26c0447ff 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -3007,7 +3007,7 @@ static void rna_def_modifier_remesh(BlenderRNA *brna) prop = RNA_def_property(srna, "octree_depth", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "depth"); - RNA_def_property_range(prop, 1, 10); + RNA_def_property_range(prop, 1, 12); RNA_def_property_ui_text(prop, "Octree Depth", "Resolution of the octree; higher values give finer details"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); From 8b4baa347fbaf05c8ee84cd18d5f8f66e7d0e480 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 6 Oct 2012 18:28:34 +0000 Subject: [PATCH 140/143] Code cleanups for dualcon octree * Move InternalNode operators from Octree class into InternalNode struct * Constify various member functions --- intern/dualcon/intern/octree.cpp | 91 +++++----- intern/dualcon/intern/octree.h | 299 ++++++++++++++++++------------- 2 files changed, 217 insertions(+), 173 deletions(-) diff --git a/intern/dualcon/intern/octree.cpp b/intern/dualcon/intern/octree.cpp index c74f8bf2f46..f17148799a1 100644 --- a/intern/dualcon/intern/octree.cpp +++ b/intern/dualcon/intern/octree.cpp @@ -384,22 +384,22 @@ InternalNode *Octree::addTriangle(InternalNode *node, CubeTriangleIsect *p, int /* Pruning using intersection test */ if (subp->isIntersecting()) { - if (!hasChild(node, i)) { + if (!node->has_child(i)) { if (height == 1) node = addLeafChild(node, i, count, createLeaf(0)); else node = addInternalChild(node, i, count, createInternal(0)); } - Node *chd = getChild(node, count); + Node *chd = node->get_child(count); if (node->is_child_leaf(i)) - setChild(node, count, (Node *)updateCell(&chd->leaf, subp)); + node->set_child(count, (Node *)updateCell(&chd->leaf, subp)); else - setChild(node, count, (Node *)addTriangle(&chd->internal, subp, height - 1)); + node->set_child(count, (Node *)addTriangle(&chd->internal, subp, height - 1)); } } - if (hasChild(node, i)) + if (node->has_child(i)) count++; } @@ -450,11 +450,11 @@ void Octree::preparePrimalEdgesMask(InternalNode *node) { int count = 0; for (int i = 0; i < 8; i++) { - if (hasChild(node, i)) { + if (node->has_child(i)) { if (node->is_child_leaf(i)) - createPrimalEdgesMask(&getChild(node, count)->leaf); + createPrimalEdgesMask(&node->get_child(count)->leaf); else - preparePrimalEdgesMask(&getChild(node, count)->internal); + preparePrimalEdgesMask(&node->get_child(count)->internal); count++; } @@ -487,7 +487,7 @@ Node *Octree::trace(Node *newnode, int *st, int len, int depth, PathList *& path // Get children paths int chdleaf[8]; - fillChildren(&newnode->internal, chd, chdleaf); + newnode->internal.fill_children(chd, chdleaf); // int count = 0; for (i = 0; i < 8; i++) { @@ -510,7 +510,7 @@ Node *Octree::trace(Node *newnode, int *st, int len, int depth, PathList *& path int df[2] = {depth - 1, depth - 1}; int *nstf[2]; - fillChildren(&newnode->internal, chd, chdleaf); + newnode->internal.fill_children(chd, chdleaf); for (i = 0; i < 12; i++) { int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]}; @@ -590,7 +590,7 @@ void Octree::findPaths(Node *node[2], int leaf[2], int depth[2], int *st[2], int for (j = 0; j < 2; j++) { if (!leaf[j]) { - fillChildren(&node[j]->internal, chd[j], chdleaf[j]); + node[j]->internal.fill_children(chd[j], chdleaf[j]); int len = (dimen >> (maxDepth - depth[j] + 1)); for (i = 0; i < 8; i++) { @@ -966,10 +966,10 @@ Node *Octree::patch(Node *newnode, int st[3], int len, PathList *rings) st[1] + len * vertmap[i][1], st[2] + len * vertmap[i][2] }; - patch(getChild(&newnode->internal, count), nori, len, zlists[i]); + patch(newnode->internal.get_child(count), nori, len, zlists[i]); } - if (hasChild(&newnode->internal, i)) { + if (newnode->internal.has_child(i)) { count++; } } @@ -1408,16 +1408,16 @@ Node *Octree::locateCell(InternalNode *node, int st[3], int len, int ori[3], int rst[1] = st[1] + vertmap[ind][1] * len; rst[2] = st[2] + vertmap[ind][2] * len; - if (hasChild(node, ind)) { - int count = getChildCount(node, ind); - Node *chd = getChild(node, count); + if (node->has_child(ind)) { + int count = node->get_child_count(ind); + Node *chd = node->get_child(count); if (node->is_child_leaf(ind)) { rleaf = chd; rlen = len; } else { // Recur - setChild(node, count, locateCell(&chd->internal, rst, len, ori, dir, side, rleaf, rst, rlen)); + node->set_child(count, locateCell(&chd->internal, rst, len, ori, dir, side, rleaf, rst, rlen)); } } else { @@ -1724,7 +1724,7 @@ void Octree::buildSigns(unsigned char table[], Node *node, int isLeaf, int sg, i // Internal node Node *chd[8]; int leaf[8]; - fillChildren(&node->internal, chd, leaf); + node->internal.fill_children(chd, leaf); // Get the signs at the corners of the first cube rvalue[0] = sg; @@ -1784,8 +1784,8 @@ void Octree::clearProcessBits(Node *node, int height) // Internal cell, recur int count = 0; for (i = 0; i < 8; i++) { - if (hasChild(&node->internal, i)) { - clearProcessBits(getChild(&node->internal, count), height - 1); + if (node->internal.has_child(i)) { + clearProcessBits(node->internal.get_child(count), height - 1); count++; } } @@ -2016,13 +2016,13 @@ int Octree::floodFill(Node *node, int st[3], int len, int height, int threshold) int count = 0; len >>= 1; for (i = 0; i < 8; i++) { - if (hasChild((InternalNode *)node, i)) { + if (node->internal.has_child(i)) { int nst[3]; nst[0] = st[0] + vertmap[i][0] * len; nst[1] = st[1] + vertmap[i][1] * len; nst[2] = st[2] + vertmap[i][2] * len; - int d = floodFill(getChild((InternalNode *)node, count), nst, len, height - 1, threshold); + int d = floodFill(node->internal.get_child(count), nst, len, height - 1, threshold); if (d > maxtotal) { maxtotal = d; } @@ -2062,9 +2062,9 @@ void Octree::writeOut() void Octree::countIntersection(Node *node, int height, int& nedge, int& ncell, int& nface) { if (height > 0) { - int total = getNumChildren(&node->internal); + int total = node->internal.get_num_children(); for (int i = 0; i < total; i++) { - countIntersection(getChild(&node->internal, i), height - 1, nedge, ncell, nface); + countIntersection(node->internal.get_child(i), height - 1, nedge, ncell, nface); } } else { @@ -2175,7 +2175,8 @@ static void minimize(float rvalue[3], float mp[3], const float pts[12][3], solve_least_squares(ata, atb, mp, rvalue); } -void Octree::computeMinimizer(LeafNode *leaf, int st[3], int len, float rvalue[3]) +void Octree::computeMinimizer(const LeafNode *leaf, int st[3], int len, + float rvalue[3]) const { // First, gather all edge intersections float pts[12][3], norms[12][3]; @@ -2253,13 +2254,13 @@ void Octree::generateMinimizer(Node *node, int st[3], int len, int height, int& int count = 0; len >>= 1; for (i = 0; i < 8; i++) { - if (hasChild(&node->internal, i)) { + if (node->internal.has_child(i)) { int nst[3]; nst[0] = st[0] + vertmap[i][0] * len; nst[1] = st[1] + vertmap[i][1] * len; nst[2] = st[2] + vertmap[i][2] * len; - generateMinimizer(getChild(&node->internal, count), + generateMinimizer(node->internal.get_child(count), nst, len, height - 1, offset); count++; } @@ -2344,9 +2345,9 @@ void Octree::edgeProcContour(Node *node[4], int leaf[4], int depth[4], int maxde Node *chd[4][8]; for (j = 0; j < 4; j++) { for (i = 0; i < 8; i++) { - chd[j][i] = ((!leaf[j]) && hasChild(&node[j]->internal, i)) ? - getChild(&node[j]->internal, - getChildCount(&node[j]->internal, i)) : NULL; + chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ? + node[j]->internal.get_child( + node[j]->internal.get_child_count(i)) : NULL; } } @@ -2391,9 +2392,9 @@ void Octree::faceProcContour(Node *node[2], int leaf[2], int depth[2], int maxde Node *chd[2][8]; for (j = 0; j < 2; j++) { for (i = 0; i < 8; i++) { - chd[j][i] = ((!leaf[j]) && hasChild(&node[j]->internal, i)) ? - getChild(&node[j]->internal, - getChildCount(&node[j]->internal, i)) : NULL; + chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ? + node[j]->internal.get_child( + node[j]->internal.get_child_count(i)) : NULL; } } @@ -2460,9 +2461,8 @@ void Octree::cellProcContour(Node *node, int leaf, int depth) // Fill children nodes Node *chd[8]; for (i = 0; i < 8; i++) { - chd[i] = ((!leaf) && hasChild(&node->internal, i)) ? - getChild(&node->internal, - getChildCount(&node->internal, i)) : NULL; + chd[i] = ((!leaf) && node->internal.has_child(i)) ? + node->internal.get_child(node->internal.get_child_count(i)) : NULL; } // 8 Cell calls @@ -2539,8 +2539,8 @@ void Octree::edgeProcParity(Node *node[4], int leaf[4], int depth[4], int maxdep Node *chd[4][8]; for (j = 0; j < 4; j++) { for (i = 0; i < 8; i++) { - chd[j][i] = ((!leaf[j]) && hasChild(&node[j]->internal, i)) ? - getChild(&node[j]->internal, getChildCount(&node[j]->internal, i)) : NULL; + chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ? + node[j]->internal.get_child( node[j]->internal.get_child_count(i)) : NULL; } } @@ -2589,9 +2589,9 @@ void Octree::faceProcParity(Node *node[2], int leaf[2], int depth[2], int maxdep Node *chd[2][8]; for (j = 0; j < 2; j++) { for (i = 0; i < 8; i++) { - chd[j][i] = ((!leaf[j]) && hasChild(&node[j]->internal, i)) ? - getChild(&node[j]->internal, - getChildCount(&node[j]->internal, i)) : NULL; + chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ? + node[j]->internal.get_child( + node[j]->internal.get_child_count(i)) : NULL; } } @@ -2658,9 +2658,8 @@ void Octree::cellProcParity(Node *node, int leaf, int depth) // Fill children nodes Node *chd[8]; for (i = 0; i < 8; i++) { - chd[i] = ((!leaf) && hasChild((InternalNode *)node, i)) ? - getChild((InternalNode *)node, - getChildCount((InternalNode *)node, i)) : NULL; + chd[i] = ((!leaf) && node->internal.has_child(i)) ? + node->internal.get_child(node->internal.get_child_count(i)) : NULL; } // 8 Cell calls @@ -2803,3 +2802,7 @@ const int dirEdge[3][4] = { {7, 6, 5, 4}, {11, 10, 9, 8} }; + +int InternalNode::numChildrenTable[256]; +int InternalNode::childrenCountTable[256][8]; +int InternalNode::childrenIndexTable[256][8]; diff --git a/intern/dualcon/intern/octree.h b/intern/dualcon/intern/octree.h index 550d584baa7..6cbdc9fb3d8 100644 --- a/intern/dualcon/intern/octree.h +++ b/intern/dualcon/intern/octree.h @@ -56,12 +56,18 @@ #define EDGE_FLOATS 4 union Node; +struct LeafNode; struct InternalNode { - /* Treat as bitfield, bit N indicates whether child N exists or not */ - unsigned char has_child; - /* Treat as bitfield, bit N indicates whether child N is a leaf or not */ - unsigned char child_is_leaf; + /* Initialized in Octree::BuildTable */ + static int numChildrenTable[256]; + static int childrenCountTable[256][8]; + static int childrenIndexTable[256][8]; + + /* Bit N indicates whether child N exists or not */ + unsigned char has_child_bitfield; + /* Bit N indicates whether child N is a leaf or not */ + unsigned char child_is_leaf_bitfield; /* Can have up to eight children */ Node *children[0]; @@ -69,7 +75,78 @@ struct InternalNode { /// Test if child is leaf int is_child_leaf(int index) const { - return (child_is_leaf >> index) & 1; + return (child_is_leaf_bitfield >> index) & 1; + } + + /// If child index exists + int has_child(int index) const + { + return (has_child_bitfield >> index) & 1; + } + + /// Get the pointer to child index + Node *get_child(int count) + { + return children[count]; + } + + const Node *get_child(int count) const + { + return children[count]; + } + + /// Get total number of children + int get_num_children() const + { + return numChildrenTable[has_child_bitfield]; + } + + /// Get the count of children + int get_child_count(int index) const + { + return childrenCountTable[has_child_bitfield][index]; + } + int get_child_index(int count) + { + return childrenIndexTable[has_child_bitfield][count]; + } + const int *get_child_counts() const + { + return childrenCountTable[has_child_bitfield]; + } + + /// Get all children + void fill_children(Node *children[8], int leaf[8]) + { + int count = 0; + for (int i = 0; i < 8; i++) { + leaf[i] = is_child_leaf(i); + if (has_child(i)) { + children[i] = get_child(count); + count++; + } + else { + children[i] = NULL; + leaf[i] = 0; + } + } + } + + /// Sets the child pointer + void set_child(int count, Node *chd) + { + children[count] = chd; + } + void set_internal_child(int index, int count, InternalNode *chd) + { + set_child(count, (Node *)chd); + has_child_bitfield |= (1 << index); + } + void set_leaf_child(int index, int count, LeafNode *chd) + { + set_child(count, (Node *)chd); + has_child_bitfield |= (1 << index); + child_is_leaf_bitfield |= (1 << index); } }; @@ -345,7 +422,8 @@ class Octree void countIntersection(Node *node, int height, int& nedge, int& ncell, int& nface); void generateMinimizer(Node * node, int st[3], int len, int height, int& offset); - void computeMinimizer(LeafNode * leaf, int st[3], int len, float rvalue[3]); + void computeMinimizer(const LeafNode * leaf, int st[3], int len, + float rvalue[3]) const; /** * Traversal functions to generate polygon model * op: 0 for counting, 1 for writing OBJ, 2 for writing OFF, 3 for writing PLY @@ -365,9 +443,6 @@ class Octree /************ Operators for all nodes ************/ /// Lookup table - int numChildrenTable[256]; - int childrenCountTable[256][8]; - int childrenIndexTable[256][8]; int numEdgeTable[8]; int edgeCountTable[8][3]; @@ -375,12 +450,12 @@ class Octree void buildTable() { for (int i = 0; i < 256; i++) { - numChildrenTable[i] = 0; + InternalNode::numChildrenTable[i] = 0; int count = 0; for (int j = 0; j < 8; j++) { - numChildrenTable[i] += ((i >> j) & 1); - childrenCountTable[i][j] = count; - childrenIndexTable[i][count] = j; + InternalNode::numChildrenTable[i] += ((i >> j) & 1); + InternalNode::childrenCountTable[i][j] = count; + InternalNode::childrenIndexTable[i][count] = j; count += ((i >> j) & 1); } } @@ -402,15 +477,15 @@ class Octree return getSign(&node->leaf, index); } else { - if (hasChild(&node->internal, index)) { - return getSign(getChild(&node->internal, getChildCount(&node->internal, index)), + if (node->internal.has_child(index)) { + return getSign(node->internal.get_child(node->internal.get_child_count(index)), height - 1, index); } else { - return getSign(getChild(&node->internal, 0), + return getSign(node->internal.get_child(0), height - 1, - 7 - getChildIndex(&node->internal, 0)); + 7 - node->internal.get_child_index(0)); } } } @@ -469,7 +544,7 @@ class Octree leaf->signs |= ((sign & 1) << index); } - int getSignMask(const LeafNode *leaf) + int getSignMask(const LeafNode *leaf) const { return leaf->signs; } @@ -536,7 +611,7 @@ class Octree } /// Get edge parity - int getEdgeParity(LeafNode *leaf, int index) + int getEdgeParity(const LeafNode *leaf, int index) const { assert(index >= 0 && index <= 11); @@ -597,7 +672,8 @@ class Octree leaf->primary_edge_intersections |= (1 << pindex); } - int getStoredEdgesParity(LeafNode *leaf, int pindex) + + int getStoredEdgesParity(const LeafNode *leaf, int pindex) const { assert(pindex <= 2 && pindex >= 0); @@ -652,7 +728,7 @@ class Octree InternalNode *parent = locateParent(node, len, st, count); // Update - setChild(parent, count, (Node *)leaf); + parent->set_child(count, (Node *)leaf); } void updateParent(InternalNode *node, int len, int st[3]) @@ -667,14 +743,14 @@ class Octree InternalNode *parent = locateParent(len, st, count); // UPdate - setChild(parent, count, (Node *)node); + parent->set_child(count, (Node *)node); } /// Find edge intersection on a given edge - int getEdgeIntersectionByIndex(int st[3], int index, float pt[3], int check) + int getEdgeIntersectionByIndex(int st[3], int index, float pt[3], int check) const { // First, locat the leaf - LeafNode *leaf; + const LeafNode *leaf; if (check) { leaf = locateLeafCheck(st); } @@ -697,7 +773,7 @@ class Octree } /// Retrieve number of edges intersected - int getPrimalEdgesMask(LeafNode *leaf) + int getPrimalEdgesMask(const LeafNode *leaf) const { return leaf->primary_edge_intersections; } @@ -710,7 +786,7 @@ class Octree } /// Get the count for a primary edge - int getEdgeCount(LeafNode *leaf, int index) + int getEdgeCount(const LeafNode *leaf, int index) const { return edgeCountTable[getPrimalEdgesMask(leaf)][index]; } @@ -744,7 +820,7 @@ class Octree } /// Retrieve edge intersection - float getEdgeOffset(LeafNode *leaf, int count) + float getEdgeOffset(const LeafNode *leaf, int count) const { return leaf->edge_intersections[4 * count]; } @@ -834,10 +910,11 @@ class Octree } /// Retrieve complete edge intersection - void getEdgeIntersectionByIndex(LeafNode *leaf, int index, int st[3], int len, float pt[3], float nm[3]) + void getEdgeIntersectionByIndex(const LeafNode *leaf, int index, int st[3], + int len, float pt[3], float nm[3]) const { int count = getEdgeCount(leaf, index); - float *pts = leaf->edge_intersections; + const float *pts = leaf->edge_intersections; float off = pts[4 * count]; @@ -865,7 +942,8 @@ class Octree return off; } - void fillEdgeIntersections(LeafNode *leaf, int st[3], int len, float pts[12][3], float norms[12][3]) + void fillEdgeIntersections(const LeafNode *leaf, int st[3], int len, + float pts[12][3], float norms[12][3]) const { int i; // int stt[3] = {0, 0, 0}; @@ -890,7 +968,7 @@ class Octree nst[i] += len; // int nstt[3] = {0, 0, 0}; // nstt[i] += 1; - LeafNode *node = locateLeaf(nst); + const LeafNode *node = locateLeaf(nst); if (e1) { // getEdgeIntersectionByIndex(node, femask[i][0], nstt, 1, pts[fmask[i][0]], norms[fmask[i][0]]); @@ -912,7 +990,7 @@ class Octree nst[i] -= len; // int nstt[3] = {1, 1, 1}; // nstt[i] -= 1; - LeafNode *node = locateLeaf(nst); + const LeafNode *node = locateLeaf(nst); // getEdgeIntersectionByIndex(node, eemask[i], nstt, 1, pts[emask[i]], norms[emask[i]]); getEdgeIntersectionByIndex(node, eemask[i], nst, len, pts[emask[i]], norms[emask[i]]); @@ -921,7 +999,9 @@ class Octree } - void fillEdgeIntersections(LeafNode *leaf, int st[3], int len, float pts[12][3], float norms[12][3], int parity[12]) + void fillEdgeIntersections(const LeafNode *leaf, int st[3], int len, + float pts[12][3], float norms[12][3], + int parity[12]) const { int i; for (i = 0; i < 12; i++) { @@ -948,7 +1028,7 @@ class Octree nst[i] += len; // int nstt[3] = {0, 0, 0}; // nstt[i] += 1; - LeafNode *node = locateLeafCheck(nst); + const LeafNode *node = locateLeafCheck(nst); if (node == NULL) { continue; } @@ -979,7 +1059,7 @@ class Octree nst[i] -= len; // int nstt[3] = {1, 1, 1}; // nstt[i] -= 1; - LeafNode *node = locateLeafCheck(nst); + const LeafNode *node = locateLeafCheck(nst); if (node == NULL) { continue; } @@ -1088,7 +1168,20 @@ class Octree int index = (((st[0] >> i) & 1) << 2) | (((st[1] >> i) & 1) << 1) | (((st[2] >> i) & 1)); - node = getChild(&node->internal, getChildCount(&node->internal, index)); + node = node->internal.get_child(node->internal.get_child_count(index)); + } + + return &node->leaf; + } + + const LeafNode *locateLeaf(int st[3]) const + { + const Node *node = root; + for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) { + int index = (((st[0] >> i) & 1) << 2) | + (((st[1] >> i) & 1) << 1) | + (((st[2] >> i) & 1)); + node = node->internal.get_child(node->internal.get_child_count(index)); } return &node->leaf; @@ -1102,8 +1195,7 @@ class Octree index = (((st[0] & i) ? 4 : 0) | ((st[1] & i) ? 2 : 0) | ((st[2] & i) ? 1 : 0)); - node = getChild(&node->internal, - getChildCount(&node->internal, index)); + node = node->internal.get_child(node->internal.get_child_count(index)); } return &node->leaf; @@ -1116,10 +1208,26 @@ class Octree int index = (((st[0] >> i) & 1) << 2) | (((st[1] >> i) & 1) << 1) | (((st[2] >> i) & 1)); - if (!hasChild(&node->internal, index)) { + if (!node->internal.has_child(index)) { return NULL; } - node = getChild(&node->internal, getChildCount(&node->internal, index)); + node = node->internal.get_child(node->internal.get_child_count(index)); + } + + return &node->leaf; + } + + const LeafNode *locateLeafCheck(int st[3]) const + { + const Node *node = root; + for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) { + int index = (((st[0] >> i) & 1) << 2) | + (((st[1] >> i) & 1) << 1) | + (((st[2] >> i) & 1)); + if (!node->internal.has_child(index)) { + return NULL; + } + node = node->internal.get_child(node->internal.get_child_count(index)); } return &node->leaf; @@ -1135,10 +1243,10 @@ class Octree ((st[1] & i) ? 2 : 0) | ((st[2] & i) ? 1 : 0)); pre = node; - node = &getChild(node, getChildCount(node, index))->internal; + node = &node->get_child(node->get_child_count(index))->internal; } - count = getChildCount(pre, index); + count = pre->get_child_count(index); return pre; } @@ -1152,88 +1260,21 @@ class Octree ((st[1] & i) ? 2 : 0) | ((st[2] & i) ? 1 : 0)); pre = node; - node = (InternalNode *)getChild(node, getChildCount(node, index)); + node = &node->get_child(node->get_child_count(index))->internal; } - count = getChildCount(pre, index); + count = pre->get_child_count(index); return pre; } /************ Operators for internal nodes ************/ - /// If child index exists - int hasChild(InternalNode *node, int index) - { - return (node->has_child >> index) & 1; - } - - /// Get the pointer to child index - Node *getChild(InternalNode *node, int count) - { - return node->children[count]; - }; - - /// Get total number of children - int getNumChildren(InternalNode *node) - { - return numChildrenTable[node->has_child]; - } - - /// Get the count of children - int getChildCount(InternalNode *node, int index) - { - return childrenCountTable[node->has_child][index]; - } - int getChildIndex(InternalNode *node, int count) - { - return childrenIndexTable[node->has_child][count]; - } - int *getChildCounts(InternalNode *node) - { - return childrenCountTable[node->has_child]; - } - - /// Get all children - void fillChildren(InternalNode *node, Node *children[8], int leaf[8]) - { - int count = 0; - for (int i = 0; i < 8; i++) { - leaf[i] = node->is_child_leaf(i); - if (hasChild(node, i)) { - children[i] = getChild(node, count); - count++; - } - else { - children[i] = NULL; - leaf[i] = 0; - } - } - } - - /// Sets the child pointer - void setChild(InternalNode *node, int count, Node *chd) - { - node->children[count] = chd; - } - void setInternalChild(InternalNode *node, int index, int count, InternalNode *chd) - { - setChild(node, count, (Node *)chd); - node->has_child |= (1 << index); - } - void setLeafChild(InternalNode *node, int index, int count, LeafNode *chd) - { - setChild(node, count, (Node *)chd); - node->has_child |= (1 << index); - node->child_is_leaf |= (1 << index); - } /// Add a kid to an existing internal node - /// Fix me: can we do this without wasting memory ? - /// Fixed: using variable memory InternalNode *addChild(InternalNode *node, int index, Node *child, int aLeaf) { // Create new internal node - int num = getNumChildren(node); + int num = node->get_num_children(); InternalNode *rnode = createInternal(num + 1); // Establish children @@ -1242,19 +1283,19 @@ class Octree for (i = 0; i < 8; i++) { if (i == index) { if (aLeaf) { - setLeafChild(rnode, i, count2, &child->leaf); + rnode->set_leaf_child(i, count2, &child->leaf); } else { - setInternalChild(rnode, i, count2, &child->internal); + rnode->set_internal_child(i, count2, &child->internal); } count2++; } - else if (hasChild(node, i)) { + else if (node->has_child(i)) { if (node->is_child_leaf(i)) { - setLeafChild(rnode, i, count2, &getChild(node, count1)->leaf); + rnode->set_leaf_child(i, count2, &node->get_child(count1)->leaf); } else { - setInternalChild(rnode, i, count2, &getChild(node, count1)->internal); + rnode->set_internal_child(i, count2, &node->get_child(count1)->internal); } count1++; count2++; @@ -1269,8 +1310,8 @@ class Octree InternalNode *createInternal(int length) { InternalNode *inode = (InternalNode *)alloc[length]->allocate(); - inode->has_child = 0; - inode->child_is_leaf = 0; + inode->has_child_bitfield = 0; + inode->child_is_leaf_bitfield = 0; return inode; } @@ -1301,21 +1342,21 @@ class Octree InternalNode *addLeafChild(InternalNode *par, int index, int count, LeafNode *leaf) { - int num = getNumChildren(par) + 1; + int num = par->get_num_children() + 1; InternalNode *npar = createInternal(num); *npar = *par; if (num == 1) { - setLeafChild(npar, index, 0, leaf); + npar->set_leaf_child(index, 0, leaf); } else { int i; for (i = 0; i < count; i++) { - setChild(npar, i, getChild(par, i)); + npar->set_child(i, par->get_child(i)); } - setLeafChild(npar, index, count, leaf); + npar->set_leaf_child(index, count, leaf); for (i = count + 1; i < num; i++) { - setChild(npar, i, getChild(par, i - 1)); + npar->set_child(i, par->get_child(i - 1)); } } @@ -1326,21 +1367,21 @@ class Octree InternalNode *addInternalChild(InternalNode *par, int index, int count, InternalNode *node) { - int num = getNumChildren(par) + 1; + int num = par->get_num_children() + 1; InternalNode *npar = createInternal(num); *npar = *par; if (num == 1) { - setInternalChild(npar, index, 0, node); + npar->set_internal_child(index, 0, node); } else { int i; for (i = 0; i < count; i++) { - setChild(npar, i, getChild(par, i)); + npar->set_child(i, par->get_child(i)); } - setInternalChild(npar, index, count, node); + npar->set_internal_child(index, count, node); for (i = count + 1; i < num; i++) { - setChild(npar, i, getChild(par, i - 1)); + npar->set_child(i, par->get_child(i - 1)); } } From e8bc62e16232aff442d2f0f6d52ff37e0c79be92 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 6 Oct 2012 18:28:38 +0000 Subject: [PATCH 141/143] Avoid unecessary minimizer calculations in dualcon * The minimize() function, which solves a least-squares problem, is only needed for sharp remesh mode, but was being calculated for smooth and blocks modes as well. Disabling this calculation when it's not needed gives a big performance boost. --- intern/dualcon/intern/octree.cpp | 78 ++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/intern/dualcon/intern/octree.cpp b/intern/dualcon/intern/octree.cpp index f17148799a1..49c50c8240d 100644 --- a/intern/dualcon/intern/octree.cpp +++ b/intern/dualcon/intern/octree.cpp @@ -2128,8 +2128,32 @@ static void solve_least_squares(const float halfA[], const float b[], rvalue[i] = result(i); } +static void mass_point(float mp[3], const float pts[12][3], const int parity[12]) +{ + int ec = 0; + + for (int i = 0; i < 12; i++) { + if (parity[i]) { + const float *p = pts[i]; + + mp[0] += p[0]; + mp[1] += p[1]; + mp[2] += p[2]; + + ec++; + } + } + + if (ec == 0) { + return; + } + mp[0] /= ec; + mp[1] /= ec; + mp[2] /= ec; +} + static void minimize(float rvalue[3], float mp[3], const float pts[12][3], - const float norms[12][3], const int parity[12]) + const float norms[12][3], const int parity[12]) { float ata[6] = {0, 0, 0, 0, 0, 0}; float atb[3] = {0, 0, 0}; @@ -2183,27 +2207,43 @@ void Octree::computeMinimizer(const LeafNode *leaf, int st[3], int len, int parity[12]; fillEdgeIntersections(leaf, st, len, pts, norms, parity); - // Next, construct QEF and minimizer - float mp[3] = {0, 0, 0}; - minimize(rvalue, mp, pts, norms, parity); - - /* Restraining the location of the minimizer */ - float nh1 = hermite_num * len; - float nh2 = (1 + hermite_num) * len; - if ((mode == DUALCON_MASS_POINT || mode == DUALCON_CENTROID) || - (rvalue[0] < st[0] - nh1 || rvalue[1] < st[1] - nh1 || rvalue[2] < st[2] - nh1 || - rvalue[0] > st[0] + nh2 || rvalue[1] > st[1] + nh2 || rvalue[2] > st[2] + nh2)) { - if (mode == DUALCON_CENTROID) { - // Use centroids + switch (mode) { + case DUALCON_CENTROID: rvalue[0] = (float) st[0] + len / 2; rvalue[1] = (float) st[1] + len / 2; rvalue[2] = (float) st[2] + len / 2; - } - else { - // Use mass point instead - rvalue[0] = mp[0]; - rvalue[1] = mp[1]; - rvalue[2] = mp[2]; + break; + + case DUALCON_MASS_POINT: + rvalue[0] = rvalue[1] = rvalue[2] = 0; + mass_point(rvalue, pts, parity); + break; + + default: { + // Sharp features */ + + // construct QEF and minimizer + float mp[3] = {0, 0, 0}; + minimize(rvalue, mp, pts, norms, parity); + + /* Restraining the location of the minimizer */ + float nh1 = hermite_num * len; + float nh2 = (1 + hermite_num) * len; + + if (rvalue[0] < st[0] - nh1 || + rvalue[1] < st[1] - nh1 || + rvalue[2] < st[2] - nh1 || + + rvalue[0] > st[0] + nh2 || + rvalue[1] > st[1] + nh2 || + rvalue[2] > st[2] + nh2) + { + // Use mass point instead + rvalue[0] = mp[0]; + rvalue[1] = mp[1]; + rvalue[2] = mp[2]; + } + break; } } } From 868df3525e79ff6c4f5eb6a2801bb70553877fcb Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Sat, 6 Oct 2012 18:40:05 +0000 Subject: [PATCH 142/143] Fix for WITH_LLVM cmake option: When using WITH_CYCLES_OSL this option is forced ON, but this change was not cached yet. Thanks to Jens Verwiebe for providing this fix. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc90f962968..47a53d0edb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -376,7 +376,7 @@ endif() # auto enable llvm for cycles_osl if(WITH_CYCLES_OSL) - set(WITH_LLVM ON) + set(WITH_LLVM ON CACHE BOOL "ON" FORCE) endif() # don't store paths to libs for portable distribution From e7db06ad9db5a1a05b00fc835038d4366d637851 Mon Sep 17 00:00:00 2001 From: Jens Verwiebe Date: Sat, 6 Oct 2012 18:53:57 +0000 Subject: [PATCH 143/143] Force USE_QTKIT for osx 64bit --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47a53d0edb1..1f0ef41fe59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -319,6 +319,9 @@ if(APPLE) option(WITH_COCOA "Use Cocoa framework instead of deprecated Carbon" ON) option(USE_QTKIT "Use QtKit instead of Carbon quicktime (needed for having partial quicktime for 64bit)" OFF) option(WITH_LIBS10.5 "Use 10.5 libs (needed for 64bit builds)" OFF) + if(CMAKE_OSX_ARCHITECTURES MATCHES x86_64) + set(USE_QTKIT ON CACHE BOOL "ON" FORCE) # no Quicktime in 64bit + endif() endif()