diff options
32 files changed, 3150 insertions, 127 deletions
diff --git a/release/scripts/op/console_python.py b/release/scripts/op/console_python.py new file mode 100755 index 00000000000..81046322967 --- /dev/null +++ b/release/scripts/op/console_python.py @@ -0,0 +1,284 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> +import sys +import bpy + +language_id = 'python' + +# store our own __main__ module, not 100% needed +# but python expects this in some places +_BPY_MAIN_OWN = True + +def add_scrollback(text, text_type): + for l in text.split('\n'): + bpy.ops.console.scrollback_append(text=l.replace('\t', ' '), + type=text_type) + + +def get_console(console_id): + ''' + helper function for console operators + currently each text datablock gets its own + console - code.InteractiveConsole() + ...which is stored in this function. + + console_id can be any hashable type + ''' + from code import InteractiveConsole + + consoles = getattr(get_console, "consoles", None) + hash_next = hash(bpy.context.window_manager) + + if consoles is None: + consoles = get_console.consoles = {} + get_console.consoles_namespace_hash = hash_next + else: + # check if clearning the namespace is needed to avoid a memory leak. + # the window manager is normally loaded with new blend files + # so this is a reasonable way to deal with namespace clearing. + # bpy.data hashing is reset by undo so cant be used. + hash_prev = getattr(get_console, "consoles_namespace_hash", 0) + + if hash_prev != hash_next: + get_console.consoles_namespace_hash = hash_next + consoles.clear() + + console_data = consoles.get(console_id) + + if console_data: + console, stdout, stderr = console_data + + # XXX, bug in python 3.1.2 ? (worked in 3.1.1) + # seems there is no way to clear StringIO objects for writing, have to make new ones each time. + import io + stdout = io.StringIO() + stderr = io.StringIO() + else: + if _BPY_MAIN_OWN: + import types + bpy_main_mod = types.ModuleType("__main__") + namespace = bpy_main_mod.__dict__ + else: + namespace = {} + + namespace["__builtins__"] = sys.modules["builtins"] + namespace["bpy"] = bpy + namespace["C"] = bpy.context + + console = InteractiveConsole(locals=namespace, filename="<blender_console>") + + if _BPY_MAIN_OWN: + console._bpy_main_mod = bpy_main_mod + + import io + stdout = io.StringIO() + stderr = io.StringIO() + + consoles[console_id] = console, stdout, stderr + + return console, stdout, stderr + + +# Both prompts must be the same length +PROMPT = '>>> ' +PROMPT_MULTI = '... ' + + +def execute(context): + sc = context.space_data + + try: + line_object = sc.history[-1] + except: + return {'CANCELLED'} + + if sc.console_type != 'PYTHON': + return {'CANCELLED'} + + console, stdout, stderr = get_console(hash(context.region)) + + # redirect output + sys.stdout = stdout + sys.stderr = stderr + + # dont allow the stdin to be used, can lock blender. + stdin_backup = sys.stdin + sys.stdin = None + + if _BPY_MAIN_OWN: + main_mod_back = sys.modules["__main__"] + sys.modules["__main__"] = console._bpy_main_mod + + # incase exception happens + line = "" # incase of encodingf error + is_multiline = False + + try: + line = line_object.body + + # run the console, "\n" executes a multiline statement + line_exec = line if line.strip() else "\n" + + is_multiline = console.push(line_exec) + except: + # unlikely, but this can happen with unicode errors for example. + import traceback + stderr.write(traceback.format_exc()) + + if _BPY_MAIN_OWN: + sys.modules["__main__"] = main_mod_back + + stdout.seek(0) + stderr.seek(0) + + output = stdout.read() + output_err = stderr.read() + + # cleanup + sys.stdout = sys.__stdout__ + sys.stderr = sys.__stderr__ + sys.last_traceback = None + + # So we can reuse, clear all data + stdout.truncate(0) + stderr.truncate(0) + + bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT') + + if is_multiline: + sc.prompt = PROMPT_MULTI + else: + sc.prompt = PROMPT + + # insert a new blank line + bpy.ops.console.history_append(text="", current_character=0, + remove_duplicates=True) + + # Insert the output into the editor + # not quite correct because the order might have changed, + # but ok 99% of the time. + if output: + add_scrollback(output, 'OUTPUT') + if output_err: + add_scrollback(output_err, 'ERROR') + + # restore the stdin + sys.stdin = stdin_backup + + return {'FINISHED'} + + +def autocomplete(context): + from console import intellisense + + sc = context.space_data + + console = get_console(hash(context.region))[0] + + if not console: + return {'CANCELLED'} + + if sc.console_type != 'PYTHON': + return {'CANCELLED'} + + # dont allow the stdin to be used, can lock blender. + # note: unlikely stdin would be used for autocomp. but its possible. + stdin_backup = sys.stdin + sys.stdin = None + + scrollback = "" + scrollback_error = "" + + if _BPY_MAIN_OWN: + main_mod_back = sys.modules["__main__"] + sys.modules["__main__"] = console._bpy_main_mod + + try: + current_line = sc.history[-1] + line = current_line.body + + # This function isnt aware of the text editor or being an operator + # just does the autocomp then copy its results back + current_line.body, current_line.current_character, scrollback = \ + intellisense.expand( + line=current_line.body, + cursor=current_line.current_character, + namespace=console.locals, + private=bpy.app.debug) + except: + # unlikely, but this can happen with unicode errors for example. + # or if the api attribute access its self causes an error. + import traceback + scrollback_error = traceback.format_exc() + + if _BPY_MAIN_OWN: + sys.modules["__main__"] = main_mod_back + + # Separate automplete output by command prompts + if scrollback != '': + bpy.ops.console.scrollback_append(text=sc.prompt + current_line.body, type='INPUT') + + # Now we need to copy back the line from blender back into the + # text editor. This will change when we dont use the text editor + # anymore + if scrollback: + add_scrollback(scrollback, 'INFO') + + if scrollback_error: + add_scrollback(scrollback_error, 'ERROR') + + # restore the stdin + sys.stdin = stdin_backup + + context.area.tag_redraw() + + return {'FINISHED'} + + +def banner(context): + sc = context.space_data + version_string = sys.version.strip().replace('\n', ' ') + + add_scrollback(" * Python Interactive Console %s *" % version_string, 'OUTPUT') + add_scrollback("Command History: Up/Down Arrow", 'OUTPUT') + add_scrollback("Cursor: Left/Right Home/End", 'OUTPUT') + add_scrollback("Remove: Backspace/Delete", 'OUTPUT') + add_scrollback("Execute: Enter", 'OUTPUT') + add_scrollback("Autocomplete: Ctrl+Space", 'OUTPUT') + add_scrollback("Ctrl +/- Wheel: Zoom", 'OUTPUT') + add_scrollback("Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bgl, blf, mathutils, geometry", 'OUTPUT') + add_scrollback("", 'OUTPUT') + add_scrollback(" WARNING!!! Blender 2.5 API is subject to change, see API reference for more info.", 'ERROR') + add_scrollback("", 'OUTPUT') + sc.prompt = PROMPT + + return {'FINISHED'} + + +def register(): + pass + + +def unregister(): + pass + + +if __name__ == "__main__": + register() diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 950ac6f3f4f..c9a1cfc4618 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1075,7 +1075,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos index = DM_get_edge_data_layer(dm, CD_ORIGINDEX); for(i=0; i<dm->numEdgeData; i++) *index++= i; index = DM_get_face_data_layer(dm, CD_ORIGINDEX); - for(i=0; i<dm->numFaceData; i++) *index++= i; + for(i=0; i<dm->numPolyData; i++) *index++= i; } } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 71abab93989..f43927e7df6 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -1725,6 +1725,8 @@ int mesh_recalcTesselation(CustomData *fdata, mf[k].v1 = f->v1->keyindex; mf[k].v2 = f->v2->keyindex; mf[k].v3 = f->v3->keyindex; + mf[k].v4 = f->v1->tmp.l; + mf[k].mat_nr = mp->mat_nr; mf[k].flag = mp->flag; origIndex[k] = use_face_origindex ? k : f->v1->tmp.l; @@ -1766,7 +1768,9 @@ int mesh_recalcTesselation(CustomData *fdata, mf->v3 = mloop[mf->v3].v; mesh_loops_to_corners(fdata, ldata, pdata, - lindex, i, origIndex[i], numTex, numCol); + lindex, i, mf->v4, numTex, numCol); + + mf->v4 = 0; } return totface; diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h index 7c1dfb1d3a4..b1db2538e6f 100644 --- a/source/blender/blenlib/BLI_array.h +++ b/source/blender/blenlib/BLI_array.h @@ -1,6 +1,5 @@ /** - * Array library - * + * Array Library * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -23,7 +22,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): Geoffrey Bantle. + * Contributor(s): Joseph Eagar. * * ***** END GPL LICENSE BLOCK ***** */ @@ -90,6 +89,7 @@ behaviour, though it may not be the best in practice. #define BLI_array_growitems(arr, num) {int _i; for (_i=0; _i<(num); _i++) {BLI_array_growone(arr);}} #define BLI_array_free(arr) if (arr && arr != _##arr##_static) MEM_freeN(arr) +#define BLI_array_pop(arr) ((arr&&_##arr##_count) ? arr[--_##arr##_count] : NULL) /*resets the logical size of an array to zero, but doesn't free the memory.*/ #define BLI_array_empty(arr) _##arr##_count=0 diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h index c7be8f50cf3..62714defd21 100644 --- a/source/blender/blenlib/BLI_mempool.h +++ b/source/blender/blenlib/BLI_mempool.h @@ -36,19 +36,42 @@ extern "C" { #endif +#include "BKE_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_blenlib.h" +#include <string.h> + #ifndef BLI_MEMPOOL_INTERN -struct BLI_mempool; -struct BLI_mempool_chunk; -typedef struct BLI_mempool BLI_mempool; +//struct BLI_mempool; +//struct BLI_mempool_chunk; +//typedef struct BLI_mempool BLI_mempool; #endif +typedef struct BLI_freenode{ + struct BLI_freenode *next; + int freeword; /*used to identify this as a freed node*/ +}BLI_freenode; + +typedef struct BLI_mempool_chunk{ + struct BLI_mempool_chunk *next, *prev; + void *data; +}BLI_mempool_chunk; + +typedef struct BLI_mempool{ + struct ListBase chunks; + int esize, csize, pchunk; /*size of elements and chunks in bytes and number of elements per chunk*/ + BLI_freenode *free; /*free element list. Interleaved into chunk datas.*/ + int totalloc, totused; /*total number of elements allocated in total, and currently in use*/ + int use_sysmalloc, allow_iter; +}BLI_mempool; + /*allow_iter allows iteration on this mempool. note: this requires that the first four bytes of the elements never contain the character string 'free'. use with care.*/ BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk, int use_sysmalloc, int allow_iter); -void *BLI_mempool_alloc(BLI_mempool *pool); +//void *BLI_mempool_alloc(BLI_mempool *pool); void *BLI_mempool_calloc(BLI_mempool *pool); void BLI_mempool_free(BLI_mempool *pool, void *addr); void BLI_mempool_destroy(BLI_mempool *pool); @@ -69,6 +92,55 @@ void BLI_mempool_allow_iter(BLI_mempool *pool); void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter); void *BLI_mempool_iterstep(BLI_mempool_iter *iter); +/************ inlined stuff ***********/ +#define FREEWORD MAKE_ID('f', 'r', 'e', 'e') +#include "MEM_guardedalloc.h" + +BM_INLINE void *BLI_mempool_alloc(BLI_mempool *pool) { + void *retval=NULL; + BLI_freenode *curnode=NULL; + char *addr=NULL; + int j; + + if (!pool) return NULL; + + pool->totused++; + + if(!(pool->free)){ + /*need to allocate a new chunk*/ + BLI_mempool_chunk *mpchunk = pool->use_sysmalloc ? (BLI_mempool_chunk*)malloc(sizeof(BLI_mempool_chunk)) : (BLI_mempool_chunk*)MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk"); + mpchunk->next = mpchunk->prev = NULL; + mpchunk->data = pool->use_sysmalloc ? malloc(pool->csize) : MEM_mallocN(pool->csize, "BLI_Mempool Chunk Data"); + BLI_addtail(&(pool->chunks), mpchunk); + + pool->free = (BLI_freenode*)mpchunk->data; /*start of the list*/ + if (pool->allow_iter) + pool->free->freeword = FREEWORD; + for(addr = (char*)mpchunk->data, j=0; j < pool->pchunk; j++){ + curnode = ((BLI_freenode*)addr); + addr += pool->esize; + curnode->next = (BLI_freenode*)addr; + + if (pool->allow_iter) { + curnode->freeword = FREEWORD; + if (j != pool->pchunk-1) + curnode->next->freeword = FREEWORD; + } + } + curnode->next = NULL; /*terminate the list*/ + + pool->totalloc += pool->pchunk; + } + + retval = pool->free; + if (pool->allow_iter) + pool->free->freeword = 0x7FFFFFFF; + + pool->free = pool->free->next; + //memset(retval, 0, pool->esize); + return retval; +} + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h new file mode 100755 index 00000000000..5badff062b7 --- /dev/null +++ b/source/blender/blenlib/BLI_smallhash.h @@ -0,0 +1,204 @@ +/** + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Eagar. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BLI_SMALLHASH_H +#define BLI_SMALLHASH_H + +/*******a light stack-friendly hash library****** + * (it uses stack space for smallish hash tables) */ + +/*based on a doubling non-chaining approach */ + +#include "MEM_guardedalloc.h" +#include "BLO_sys_types.h" +#include "BKE_utildefines.h" + +extern unsigned int hashsizes[]; +#define NONHASH -25436536 +typedef struct entry {intptr_t key; void *val;} entry; + +#define SMSTACKSIZE 521 +typedef struct SmallHash { + entry *table, _stacktable[SMSTACKSIZE], _copytable[SMSTACKSIZE]; + entry *stacktable, *copytable; + int used; + int curhash; + int size; +} SmallHash; + +/*CELL_UNUSED means this cell is inside a key series, while CELL_FREE + means this cell terminates a key series. + + no chance of anyone shoving INT32_MAX-2 into a *val pointer, I + imagine. hopefully. */ +#define CELL_UNUSED ((void*)0x7FFFFFFD) +#define CELL_FREE ((void*)0x7FFFFFFD) + +#define HASHNEXT(h) (((h) + ((h)==0))*2) + +BM_INLINE void BLI_smallhash_init(SmallHash *hash) +{ + int i; + + memset(hash, 0, sizeof(*hash)); + + hash->table = hash->_stacktable; + hash->curhash = 2; + hash->size = hashsizes[hash->curhash]; + + hash->copytable = hash->_copytable; + hash->stacktable = hash->_stacktable; + + for (i=0; i<hash->size; i++) { + hash->table[i].val = CELL_FREE; + } +} + +/*NOTE: does *not* free *hash itself! only the direct data!*/ +BM_INLINE void BLI_smallhash_release(SmallHash *hash) +{ + if (!hash) + return; + + if (hash->table != hash->stacktable) + MEM_freeN(hash->table); +} + +BM_INLINE void BLI_smallhash_insert(SmallHash *hash, intptr_t key, void *item) +{ + int h; + + if (hash->size < hash->used*3) { + int newsize = hashsizes[++hash->curhash]; + entry *tmp; + int i = 0; + + if (hash->table != hash->stacktable || newsize > SMSTACKSIZE) { + tmp = MEM_callocN(sizeof(*hash->table)*newsize, "new hashkeys"); + } else { + SWAP(entry*, hash->stacktable, hash->copytable); + tmp = hash->stacktable; + } + + SWAP(entry*, tmp, hash->table); + + hash->size = newsize; + + for (i=0; i<hash->size; i++) { + hash->table[i].val = CELL_FREE; + } + + for (i=0; i<hashsizes[hash->curhash-1]; i++) { + if (ELEM(tmp[i].val, CELL_UNUSED, CELL_FREE)) + continue; + + h = tmp[i].key; + while (!ELEM(hash->table[h % newsize].val, CELL_UNUSED, CELL_FREE)) + h = HASHNEXT(h); + + h %= newsize; + + hash->table[h].key = tmp[i].key; + hash->table[h].val = tmp[i].val; + } + + if (tmp != hash->stacktable && tmp != hash->copytable) { + MEM_freeN(tmp); + } + } + + h = key; + while (!ELEM(hash->table[h % hash->size].val, CELL_UNUSED, CELL_FREE)) + h = HASHNEXT(h); + + h %= hash->size; + hash->table[h].key = key; + hash->table[h].val = item; + + hash->used++; +} + +BM_INLINE void BLI_smallhash_remove(SmallHash *hash, intptr_t key) +{ + int h = key; + + while (hash->table[h % hash->size].key != key + || hash->table[h % hash->size].val == CELL_UNUSED) + { + if (hash->table[h % hash->size].val == CELL_FREE) + return; + h = HASHNEXT(h); + } + + h %= hash->size; + hash->table[h].key = 0; + hash->table[h].val = CELL_UNUSED; +} + +BM_INLINE void *BLI_smallhash_lookup(SmallHash *hash, intptr_t key) +{ + int h = key; + + if (!hash->table) + return NULL; + + while (hash->table[h % hash->size].key != key + || hash->table[h % hash->size].val == CELL_UNUSED) + { + if (hash->table[h % hash->size].val == CELL_FREE) + return NULL; + h = HASHNEXT(h); + } + + return hash->table[h % hash->size].val; +} + + +BM_INLINE int BLI_smallhash_haskey(SmallHash *hash, intptr_t key) +{ + int h = key; + + if (!hash->table) + return 0; + + while (hash->table[h % hash->size].key != key + || hash->table[h % hash->size].val == CELL_UNUSED) + { + if (hash->table[h % hash->size].val == CELL_FREE) + return 0; + h = HASHNEXT(h); + } + + return 1; +} + +BM_INLINE int BLI_smallhash_count(SmallHash *hash) +{ + return hash->used; +} + +#endif // BLI_SMALLHASH_H diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c index ed56a390719..686709d8879 100644 --- a/source/blender/blenlib/intern/BLI_mempool.c +++ b/source/blender/blenlib/intern/BLI_mempool.c @@ -42,26 +42,6 @@ #include <string.h> -#define FREEWORD MAKE_ID('f', 'r', 'e', 'e') - -typedef struct BLI_freenode{ - struct BLI_freenode *next; - intptr_t freeword; /*used to identify this as a freed node*/ -}BLI_freenode; - -typedef struct BLI_mempool_chunk{ - struct BLI_mempool_chunk *next, *prev; - void *data; -}BLI_mempool_chunk; - -typedef struct BLI_mempool{ - struct ListBase chunks; - int esize, csize, pchunk; /*size of elements and chunks in bytes and number of elements per chunk*/ - struct BLI_freenode *free; /*free element list. Interleaved into chunk datas.*/ - int totalloc, totused; /*total number of elements allocated in total, and currently in use*/ - int use_sysmalloc, allow_iter; -}BLI_mempool; - #define BLI_MEMPOOL_INTERN #include "BLI_mempool.h" @@ -132,7 +112,7 @@ BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk, curnode->next = NULL; return pool; } - +#if 0 void *BLI_mempool_alloc(BLI_mempool *pool){ void *retval=NULL; BLI_freenode *curnode=NULL; @@ -177,6 +157,7 @@ void *BLI_mempool_alloc(BLI_mempool *pool){ //memset(retval, 0, pool->esize); return retval; } +#endif void *BLI_mempool_calloc(BLI_mempool *pool){ void *retval=NULL; diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 68b1feea632..6756f42bf35 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -1568,7 +1568,7 @@ void interp_weights_poly_v3(float *w,float v[][3], int n, float *co) t2= mean_value_half_tan(co, vmid, vnext); len= len_v3v3(co, vmid); - w[i]= (t1+t2)/len; + w[i]= (t1+t2)/(len+FLT_EPSILON*2); totweight += w[i]; } diff --git a/source/blender/bmesh/bmesh_iterators.h b/source/blender/bmesh/bmesh_iterators.h index 16127f54e9d..c741ec5d967 100644 --- a/source/blender/bmesh/bmesh_iterators.h +++ b/source/blender/bmesh/bmesh_iterators.h @@ -45,6 +45,7 @@ a different face hole boundary*/ from the other faces in the radial cycle surrounding the input loop's edge.*/ #define BM_LOOPS_OF_LOOP 12 +#define BM_LOOPS_OF_EDGE 13 #define BM_ITER(ele, iter, bm, type, data) \ ele = BMIter_New(iter, bm, type, data); \ diff --git a/source/blender/bmesh/bmesh_operator_api.h b/source/blender/bmesh/bmesh_operator_api.h index 0b5075d4e66..0b1e356d01d 100644 --- a/source/blender/bmesh/bmesh_operator_api.h +++ b/source/blender/bmesh/bmesh_operator_api.h @@ -141,9 +141,9 @@ void BMO_Finish_Op(struct BMesh *bm, struct BMOperator *op); if you need to store a value per element, use a ghash or a mapping slot to do it.*/ /*flags 15 and 16 (1<<14 and 1<<15) are reserved for bmesh api use*/ -#define BMO_TestFlag(bm, element, flag) (((BMHeader*)element)->flags[bm->stackdepth-1].f & (flag)) -#define BMO_SetFlag(bm, element, flag) (((BMHeader*)element)->flags[bm->stackdepth-1].f |= (flag)) -#define BMO_ClearFlag(bm, element, flag) (((BMHeader*)element)->flags[bm->stackdepth-1].f &= ~(flag)) +#define BMO_TestFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f & (flag)) +#define BMO_SetFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f |= (flag)) +#define BMO_ClearFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f &= ~(flag)) /*profiling showed a significant amount of time spent in BMO_TestFlag void BMO_SetFlag(struct BMesh *bm, void *element, int flag); @@ -398,6 +398,11 @@ BM_INLINE void BMO_Insert_Mapping(BMesh *bm, BMOperator *op, char *slotname, BLI_ghash_insert(slot->data.ghash, element, mapping); } +BM_INLINE void BMO_Insert_MapInt(BMesh *bm, BMOperator *op, char *slotname, + void *element, int val) +{ + BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(int)); +} BM_INLINE void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, char *slotname, void *element, float val) @@ -448,6 +453,15 @@ BM_INLINE float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, char *slotname, return 0.0f; } +BM_INLINE int BMO_Get_MapInt(BMesh *bm, BMOperator *op, char *slotname, + void *element) +{ + int *val = (int*) BMO_Get_MapData(bm, op, slotname, element); + if (val) return *val; + + return 0; +} + BM_INLINE void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, char *slotname, void *element) { diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index cdf05e1f780..7df30f61136 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -331,6 +331,8 @@ BMFace *BM_Make_Ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, for (i=0; i<len; i++) { edges2[i] = BM_Edge_Exist(verts[i], verts[(i+1)%len]); + if (!edges2[i]) + return NULL; } /*check if face already exists*/ @@ -534,11 +536,13 @@ BMesh *BM_Copy_Mesh(BMesh *bmold) } f2 = BM_Make_Ngon(bm, v, v2, edges, f->len, 0); + if (!f2) + continue; BMINDEX_SET(f, i); BLI_array_growone(ftable); ftable[i] = f2; - + BM_Copy_Attributes(bmold, bm, f, f2); VECCOPY(f2->no, f->no); diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c index f53a9e4f47b..1f737ac9fe9 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.c +++ b/source/blender/bmesh/intern/bmesh_iterators.c @@ -210,6 +210,35 @@ static void *loop_of_vert_step(BMIter *iter) return NULL; } + +static void loops_of_edge_begin(BMIter *iter) +{ + BMLoop *l; + + l = iter->edata->l; + if (!l) + return; + + /*note sure why this sets ldata. . .*/ + init_iterator(iter); + + iter->firstloop = iter->nextloop = l; +} + +static void *loops_of_edge_step(BMIter *iter) +{ + BMLoop *current = iter->nextloop; + + if(iter->nextloop) + iter->nextloop = bmesh_radial_nextloop(iter->nextloop); + + if(iter->nextloop == iter->firstloop) + iter->nextloop = NULL; + + if(current) return current; + return NULL; +} + static void loops_of_loop_begin(BMIter *iter) { BMLoop *l; @@ -420,6 +449,14 @@ void *BMIter_New(BMIter *iter, BMesh *bm, int type, void *data) iter->step = loops_of_loop_step; iter->ldata = data; break; + case BM_LOOPS_OF_EDGE: + if (!data) + return NULL; + + iter->begin = loops_of_edge_begin; + iter->step = loops_of_edge_step; + iter->edata = data; + break; default: break; } diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index 48cfdd1cdf6..d804e0f9193 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -129,7 +129,7 @@ BMesh *BM_Make_Mesh(int allocsize[4]) /*allocate one flag pool that we dont get rid of.*/ bm->toolflagpool = BLI_mempool_create(sizeof(BMFlagLayer), 512, 512, 0, 0); - bm->stackdepth = 0; + bm->stackdepth = 1; bm->totflags = 1; return bm; diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 718326b803d..fe5c49a921b 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -221,6 +221,12 @@ BMFace *BM_Join_TwoFaces(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) { } l1 = jed->l; + + if (!l1) { + bmesh_error(); + return NULL; + } + l2 = l1->radial_next; if (l1->v == l2->v) { bmesh_loop_reverse(bm, f2); diff --git a/source/blender/bmesh/intern/bmesh_newcore.c b/source/blender/bmesh/intern/bmesh_newcore.c index c22946ed95f..64fcb310c93 100644 --- a/source/blender/bmesh/intern/bmesh_newcore.c +++ b/source/blender/bmesh/intern/bmesh_newcore.c @@ -1,3 +1,5 @@ +#include <limits.h> + #include "BLI_math_vector.h" #include "BKE_utildefines.h" @@ -658,8 +660,17 @@ static int count_flagged_radial(BMLoop *l, int flag) int i = 0; do { + if (!l2) { + bmesh_error(); + return 0; + } + i += bmesh_api_getflag(l2->f, flag) ? 1 : 0; l2 = bmesh_radial_nextloop(l2); + if (i >= 800000) { + bmesh_error(); + return 0; + } } while (l2 != l); return i; diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 11403db2cc3..560c5b4aef0 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -383,8 +383,12 @@ BMOpDefine def_contextual_create= { BMOpDefine def_edgenet_fill= { "edgenet_fill", - {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, - {BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, + {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, /*input edges*/ + {BMOP_OPSLOT_MAPPING, "restrict"}, /*restricts edges to groups. maps edges to integers*/ + {BMOP_OPSLOT_INT, "use_restrict"}, + {BMOP_OPSLOT_ELEMENT_BUF, "excludefaces"}, /*list of faces to ignore for manifold checks*/ + {BMOP_OPSLOT_MAPPING, "faceout_groupmap"}, /*maps new faces to the group numbers they came from*/ + {BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, /*new faces*/ {0, /*null-terminating sentinel*/}}, bmesh_edgenet_fill_exec, 0, diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index 9204052b81d..2f298902c3c 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -130,11 +130,11 @@ void BMO_Exec_Op(BMesh *bm, BMOperator *op) BMO_push(bm, op); - if(bm->stackdepth == 1) + if(bm->stackdepth == 2) bmesh_begin_edit(bm); op->exec(bm, op); - if(bm->stackdepth == 1) + if(bm->stackdepth == 2) bmesh_end_edit(bm,0); BMO_pop(bm); @@ -792,13 +792,13 @@ static void alloc_flag_layer(BMesh *bm) bm->totflags++; /*allocate new flag pool*/ - bm->toolflagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, 1, 0); + bm->toolflagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, 0, 0); /*now go through and memcpy all the flags. Loops don't get a flag layer at this time...*/ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){ oldflags = v->head.flags; v->head.flags = BLI_mempool_calloc(bm->toolflagpool); - memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*(bm->totflags-1)); /*dont know if this memcpy usage is correct*/ + memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*(bm->totflags-1)); } for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){ oldflags = e->head.flags; diff --git a/source/blender/bmesh/operators/createops.c b/source/blender/bmesh/operators/createops.c index 8b983f00087..57c5e13ba57 100644 --- a/source/blender/bmesh/operators/createops.c +++ b/source/blender/bmesh/operators/createops.c @@ -9,23 +9,34 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_array.h" +#include "BLI_smallhash.h" +#include "BLI_rand.h" #include "bmesh.h" #include "bmesh_operators_private.h" +#define EDGE_MARK 1 +#define EDGE_VIS 2 + +#define FACE_NEW 1 + #define ELE_NEW 1 #define ELE_OUT 2 #define ELE_ORIG 4 +#define FACE_IGNORE 16 + typedef struct EPathNode { struct EPathNode *next, *prev; BMVert *v; BMEdge *e; + BMEdge *cure; } EPathNode; typedef struct EPath { ListBase nodes; float weight; + int group; } EPath; typedef struct PathBase { @@ -35,12 +46,534 @@ typedef struct PathBase { typedef struct EdgeData { int tag; int ftag; + + struct { + struct BMEdge *next, *prev; + } dlink1; + struct { + struct BMEdge *next, *prev; + } dlink2; } EdgeData; -#define EDGE_MARK 1 -#define EDGE_VIS 2 +typedef struct VertData { + BMEdge *e; + float no[3], offco[3], sco[3]; /*offco is vertex coordinate slightly offset randomly*/ + int tag; +} VertData; -#define FACE_NEW 1 +static int count_edge_faces(BMesh *bm, BMEdge *e); + +/**** rotation system code ***/ + +#define rs_get_edge_link(e, v, ed) (Link*)((v) == ((BMEdge*)(e))->v1 ? &(((EdgeData*)(ed))->dlink1) : &(((EdgeData*)(ed))->dlink2)) + +int rotsys_append_edge(struct BMEdge *e, struct BMVert *v, + EdgeData *edata, VertData *vdata) +{ + EdgeData *ed = &edata[BMINDEX_GET(e)]; + VertData *vd = &vdata[BMINDEX_GET(v)]; + + if (!vd->e) { + Link *e1 = (Link*)rs_get_edge_link(e, v, ed); + + vd->e = e; + e1->next = e1->prev = (Link*)e; + } else { + Link *e1, *e2, *e3; + EdgeData *ved = &edata[BMINDEX_GET(vd->e)]; + + e1 = rs_get_edge_link(e, v, ed); + e2 = rs_get_edge_link(vd->e, v, ved); + e3 = e2->prev ? rs_get_edge_link(e2->prev, v, &edata[BMINDEX_GET(e2->prev)]) : NULL; + + e1->next = (Link*)vd->e; + e1->prev = e2->prev; + + e2->prev = (Link*)e; + if (e3) + e3->next = (Link*)e; + } + + return 1; +} + +void rotsys_remove_edge(struct BMEdge *e, struct BMVert *v, + EdgeData *edata, VertData *vdata) +{ + EdgeData *ed = edata + BMINDEX_GET(e); + VertData *vd = vdata + BMINDEX_GET(v); + Link *e1, *e2; + + e1 = rs_get_edge_link(e, v, ed); + if (e1->prev) { + e2 = rs_get_edge_link(e1->prev, v, ed); + e2->next = e1->next; + } + + if (e1->next) { + e2 = rs_get_edge_link(e1->next, v, ed); + e2->prev = e1->prev; + } + + if (vd->e == e) + vd->e = e!=e1->next ? (BMEdge*)e1->next : NULL; + + e1->next = e1->prev = NULL; +} + +struct BMEdge *rotsys_nextedge(struct BMEdge *e, struct BMVert *v, + EdgeData *edata, VertData *vdata) +{ + if (v == e->v1) + return edata[BMINDEX_GET(e)].dlink1.next; + if (v == e->v2) + return edata[BMINDEX_GET(e)].dlink2.next; + return NULL; +} + +BMEdge *rotsys_prevedge(BMEdge *e, BMVert *v, + EdgeData *edata, VertData *vdata) +{ + if (v == e->v1) + return edata[BMINDEX_GET(e)].dlink1.prev; + if (v == e->v2) + return edata[BMINDEX_GET(e)].dlink2.prev; + return NULL; +} + +struct BMEdge *rotsys_reverse(struct BMEdge *e, struct BMVert *v, EdgeData *edata, VertData *vdata) +{ + BMEdge **edges = NULL; + BMEdge *e2; + BLI_array_staticdeclare(edges, 256); + int i, totedge; + + e2 = vdata[BMINDEX_GET(v)].e; + do { + BLI_array_append(edges, e2); + e2 = rotsys_nextedge(e2, v, edata, vdata); + } while (e2 != vdata[BMINDEX_GET(v)].e); + + totedge = BLI_array_count(edges); + for (i=0; i<totedge/2; i++) { + SWAP(BMEdge*, edges[i], edges[totedge-1-i]); + } + + vdata[BMINDEX_GET(v)].e = NULL; + for (i=0; i<totedge; i++) { + rotsys_append_edge(edges[i], v, edata, vdata); + } + + BLI_array_free(edges); +} + +int rotsys_count(struct BMVert *v, EdgeData *edata, VertData *vdata) +{ + BMEdge *e = vdata[BMINDEX_GET(v)].e; + int i=0; + + if (!e) + return 0; + + do { + if (!e) + return 0; + e = rotsys_nextedge(e, v, edata, vdata); + + if (i >= (1<<20)) { + printf("bmesh error: infinite loop in disk cycle!\n"); + return 0; + } + + i += 1; + } while (e != vdata[BMINDEX_GET(v)].e); + + return i; +} + +int rotsys_fill_faces(BMesh *bm, EdgeData *edata, VertData *vdata) +{ + BMIter iter; + BMEdge *e, **edges = NULL; + BLI_array_declare(edges); + BMVert *v, **verts = NULL; + BMFace *f; + BLI_array_declare(verts); + SmallHash visithash, *hash=&visithash; + int i; + + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + BMEdge *e2, *starte; + BMVert *startv; + int rad, ok; + + rad = count_edge_faces(bm, e); + + if (rad < 2) + starte = e; + else + continue; + + /*do two passes, going forward then backward*/ + for (i=0; i<2; i++) { + BLI_smallhash_init(hash); + + BLI_array_empty(verts); + BLI_array_empty(edges); + + startv = v = starte->v1; + e2 = starte; + ok = 1; + if (!v || !e2) + continue; + + do { + if (BLI_smallhash_haskey(hash, (intptr_t)e2) + || BLI_smallhash_haskey(hash, (intptr_t)v)) { + ok = 0; + break; + } + + BLI_array_append(verts, v); + BLI_array_append(edges, e2); + + BLI_smallhash_insert(hash, (intptr_t)e2, NULL); + + v = BM_OtherEdgeVert(e2, v); + e2 = i ? rotsys_prevedge(e2, v, edata, vdata) : rotsys_nextedge(e2, v, edata, vdata); + } while (e2 != starte && v != startv); + + BLI_smallhash_release(hash); + + if (!ok || BLI_array_count(edges) < 3) + continue; + + f = BM_Make_Ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), 1); + if (!f) + continue; + } + } +} + +void rotsys_make_consistent(BMesh *bm, EdgeData *edata, VertData *vdata) +{ + BMIter iter; + BMEdge *e; + BMVert *v, **stack=NULL; + BLI_array_declare(stack); + int i; + + for (i=0; i<bm->totvert; i++) { + vdata[i].tag = 0; + } + + while (1) { + VertData *vd; + BMVert *startv = NULL; + float dis; + + v = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (i=0; i<bm->totvert; i++, BMIter_Step(&iter)) { + vd = vdata + BMINDEX_GET(v); + + if (vd->tag) + continue; + + if (!startv || dot_v3v3(vd->offco, vd->offco) > dis) { + dis = dot_v3v3(vd->offco, vd->offco); + startv = v; + } + } + + if (!startv) + break; + + vd = vdata + BMINDEX_GET(startv); + + BLI_array_empty(stack); + BLI_array_append(stack, startv); + + vd->tag = 1; + + while (BLI_array_count(stack)) { + v = BLI_array_pop(stack); + vd = vdata + BMINDEX_GET(v); + + if (!vd->e) + continue; + + e = vd->e; + do { + BMVert *v2 = BM_OtherEdgeVert(e, v); + VertData *vd2 = vdata + BMINDEX_GET(v2); + + if (dot_v3v3(vd->no, vd2->no) < 0.0f+FLT_EPSILON*2) { + rotsys_reverse(e, v2, edata, vdata); + mul_v3_fl(vd2->no, -1.0f); + } + + if (!vd2->tag) { + BLI_array_append(stack, v2); + vd2->tag = 1; + } + + e = rotsys_nextedge(e, v, edata, vdata); + } while (e != vd->e); + } + } + +} + +void init_rotsys(BMesh *bm, EdgeData *edata, VertData *vdata) +{ + BMIter iter; + BMEdge *e; + BMEdge **edges = NULL; + BLI_array_staticdeclare(edges, 256); + BMVert *v, *lastv, **verts = NULL; + BLI_array_staticdeclare(verts, 256); + int i; + + #define SIGN(n) ((n)<0.0f) + + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + BMIter eiter; + float no[3], cent[3]; + int j, k=0, totedge=0; + + if (BMINDEX_GET(v) == -1) + continue; + + BLI_array_empty(edges); + + BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) { + if (BMO_TestFlag(bm, e, EDGE_MARK)) { + BLI_array_append(edges, e); + totedge++; + } + } + + copy_v3_v3(cent, v->co); + + zero_v3(no); + for (i=0; i<totedge; i++) { + BMEdge *e1, *e2; + float cno[3], vec1[3], vec2[3]; + + e1 = edges[i]; + e2 = edges[(i+1)%totedge]; + + sub_v3_v3v3(vec1, (BM_OtherEdgeVert(e1, v))->co, v->co); + sub_v3_v3v3(vec2, (BM_OtherEdgeVert(e2, v))->co, v->co); + + cross_v3_v3v3(cno, vec1, vec2); + normalize_v3(cno); + + if (i && dot_v3v3(cno, no) < 0.0f+FLT_EPSILON*10) + mul_v3_fl(cno, -1.0f); + + add_v3_v3(no, cno); + normalize_v3(no); + } + + /*generate plane-flattened coordinates*/ + for (i=0; i<totedge; i++) { + BMEdge *e1; + BMVert *v2; + float cvec[3], vec1[3]; + + e1 = edges[i]; + v2 = BM_OtherEdgeVert(e1, v); + + sub_v3_v3v3(vec1, v2->co, v->co); + + cross_v3_v3v3(cvec, vec1, no); + cross_v3_v3v3(vec1, cvec, no); + normalize_v3(vec1); + + mul_v3_fl(vec1, len_v3v3(v2->co, v->co)); + add_v3_v3(vec1, v->co); + + copy_v3_v3(vdata[BMINDEX_GET(v2)].sco, vec1); + } + + /*first, ensure no 0 or 180 angles between adjacent + (and that adjacent's adjacent) edges*/ + for (i=0, k=0; i<totedge; i++) { + BMEdge *e1, *e2, *e3=NULL; + BMVert *v1, *v2, *v3; + VertData *vd1, *vd2, *vd3; + float vec1[3], vec2[3], vec3[3], size; + int s1, s2, s3; + + if (totedge < 3) + continue; + + e1 = edges[(i+totedge-1) % totedge]; + e2 = edges[i]; + e3 = edges[(i+1) % totedge]; + + v1 = BM_OtherEdgeVert(e1, v); v2 = BM_OtherEdgeVert(e2, v); v3 = BM_OtherEdgeVert(e3, v); + vd1 = vdata+BMINDEX_GET(v1); vd2 = vdata+BMINDEX_GET(v2); vd3 = vdata+BMINDEX_GET(v3); + + sub_v3_v3v3(vec1, vd1->sco, cent); + sub_v3_v3v3(vec2, vd2->sco, cent); + sub_v3_v3v3(vec3, vd3->sco, cent); + + size = (len_v3(vec1) + len_v3(vec3))*0.01; + normalize_v3(vec1); normalize_v3(vec2); normalize_v3(vec3); + + #ifdef STRAIGHT + #undef STRAIGHT + #endif + #define STRAIGHT(vec11, vec22) (fabs(dot_v3v3((vec11), (vec22))) > 1.0-FLT_EPSILON*1000) + + s1 = STRAIGHT(vec1, vec2); s2 = STRAIGHT(vec2, vec3); s3 = STRAIGHT(vec1, vec3); + + if (s1 || s2 || s3) { + copy_v3_v3(cent, v->co); + + for (j=0; j<3; j++) { + float fac = (BLI_frand()-0.5f)*size; + cent[j] += fac; + } + + if (k < 2000) { + i = 0; + k++; + continue; + } else { + k++; + continue; + } + + } + } + + copy_v3_v3(vdata[BMINDEX_GET(v)].offco, cent); + copy_v3_v3(v->co, cent); + + /*now, sort edges so the triangle fan of all edges + has a consistent normal. this is the same as + sorting by polar coordinates along a group normal*/ + for (j=0; j<totedge; j++) { + for (i=0; i<totedge; i++) { + BMEdge *e1, *e2, *e3=NULL; + BMVert *v1, *v2, *v3; + VertData *vd1, *vd2, *vd3; + float vec1[3], vec2[3], vec3[3], n1[3], n2[3], n3[3]; + int s1, s2, s3; + + e1 = edges[(i+totedge-1) % totedge]; + e2 = edges[i]; + e3 = edges[(i+1) % totedge]; + + v1 = BM_OtherEdgeVert(e1, v); v2 = BM_OtherEdgeVert(e2, v); v3 = BM_OtherEdgeVert(e3, v); + vd1 = vdata+BMINDEX_GET(v1); vd2 = vdata+BMINDEX_GET(v2); vd3 = vdata+BMINDEX_GET(v3); + + sub_v3_v3v3(vec1, vd1->sco, cent); + sub_v3_v3v3(vec2, vd2->sco, cent); + sub_v3_v3v3(vec3, vd3->sco, cent); + + cross_v3_v3v3(n1, vec1, vec2); + cross_v3_v3v3(n2, vec2, vec3); + cross_v3_v3v3(n3, vec1, vec3); + + normalize_v3(n1); normalize_v3(n2); normalize_v3(n3); + + s1 = STRAIGHT(vec1, vec2); s2 = STRAIGHT(vec2, vec3); s3 = STRAIGHT(vec1, vec3); + + if (s1 || s2 || s3) { + printf("yeek! s1: %d, s2: %d, s3: %dx\n", s1, s2, s3); + } + if (dot_v3v3(n1, n2) < 0.0f) { + if (dot_v3v3(n1, n3) >= 0.0f + FLT_EPSILON*10) { + SWAP(BMEdge*, edges[i], edges[(i+1)%totedge]); + } else { + SWAP(BMEdge*, edges[(i+totedge-1)%totedge], edges[(i+1)%totedge]) + SWAP(BMEdge*, edges[i], edges[(i+1)%totedge]) + } + } + } + } + + #undef STRAIGHT + + zero_v3(no); + + /*yay, edges is sorted*/ + for (i=0; i<totedge; i++) { + BMEdge *e1 = edges[i], *e2 = edges[(i+1)%totedge]; + float eno[3]; + + normal_tri_v3(eno, BM_OtherEdgeVert(e1, v)->co, v->co, BM_OtherEdgeVert(e2, v)->co); + add_v3_v3(no, eno); + + rotsys_append_edge(edges[i], v, edata, vdata); + } + + normalize_v3(no); + copy_v3_v3(vdata[BMINDEX_GET(v)].no, no); + } + + /*now, make sure rotation system is topologically consistent + (e.g. vert normals consistently point either inside or outside)*/ + rotsys_make_consistent(bm, edata, vdata); + + //rotsys_fill_faces(bm, edata, vdata); + +#if 0 + /*create visualizing geometry*/ + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + BMVert *v2; + BMFace *f; + int totedge = BM_Vert_EdgeCount(v); + + if (BMINDEX_GET(v) == -1) + continue; + + //cv = BM_Make_Vert(bm, cent, v); + //BMINDEX_SET(cv, -1); + i = 0; + e = vdata[BMINDEX_GET(v)].e; + lastv = NULL; + do { + BMEdge *e2; + BMVert *v2; + float f = ((float)i / (float)totedge)*0.35 + 0.05; + float co[3]; + + if (!e) + break; + + if (!BM_OtherEdgeVert(e, v)) + continue; + + sub_v3_v3v3(co, (BM_OtherEdgeVert(e, v))->co, vdata[BMINDEX_GET(v)].offco); + mul_v3_fl(co, f); + add_v3_v3(co, vdata[BMINDEX_GET(v)].offco); + + v2 = BM_Make_Vert(bm, co, NULL); + BMINDEX_SET(v2, -1); + //BM_Make_Edge(bm, cv, v2, NULL, 0); + + BM_Select(bm, v2, 1); + if (lastv) { + e2 = + BM_Make_Edge(bm, lastv, v2, NULL, 0); + BM_Select(bm, e2, 1); + } + + lastv = v2; + + e = rotsys_nextedge(e, v, edata, vdata); + i++; + } while (e != vdata[BMINDEX_GET(v)].e); + } +#endif + + BLI_array_free(edges); +} PathBase *edge_pathbase_new(void) { @@ -64,33 +597,40 @@ EPath *edge_copy_add_path(PathBase *pb, EPath *path, BMVert *appendv, BMEdge *e) EPath *path2; EPathNode *node, *node2; - path2 = BLI_mempool_calloc(pb->pathpool); + path2 = BLI_mempool_alloc(pb->pathpool); + path2->nodes.first = path2->nodes.last = NULL; + path2->weight = 0.0f; + path2->group = path->group; for (node=path->nodes.first; node; node=node->next) { - node2 = BLI_mempool_calloc(pb->nodepool); + node2 = BLI_mempool_alloc(pb->nodepool); *node2 = *node; BLI_addtail(&path2->nodes, node2); } - node2 = BLI_mempool_calloc(pb->nodepool); + node2 = BLI_mempool_alloc(pb->nodepool); node2->v = appendv; node2->e = e; + node2->cure = NULL; BLI_addtail(&path2->nodes, node2); return path2; } -EPath *edge_path_new(PathBase *pb, BMVert *start) +EPath *edge_path_new(PathBase *pb, BMVert *start, BMEdge *starte) { EPath *path; EPathNode *node; - path = BLI_mempool_calloc(pb->pathpool); - node = BLI_mempool_calloc(pb->nodepool); - + path = BLI_mempool_alloc(pb->pathpool); + node = BLI_mempool_alloc(pb->nodepool); + + path->nodes.first = path->nodes.last = NULL; + node->v = start; - node->e = NULL; + node->e = starte; + node->cure = NULL; BLI_addtail(&path->nodes, node); path->weight = 0.0f; @@ -98,14 +638,18 @@ EPath *edge_path_new(PathBase *pb, BMVert *start) return path; } -float edge_weight_path(EPath *path, EdgeData *edata) +float edge_weight_path(EPath *path, EdgeData *edata, VertData *vdata) { - EPathNode *node; + EPathNode *node, *first=path->nodes.first; float w = 0.0; for (node=path->nodes.first; node; node=node->next) { - if (node->e) { + if (node->e && node != path->nodes.first) { w += edata[BMINDEX_GET(node->e)].ftag; + if (node->prev) { + //w += len_v3v3(node->v->co, first->e->v1->co)*0.0001f; + //w += len_v3v3(node->v->co, first->e->v2->co)*0.0001f; + } } w += 1.0f; @@ -127,30 +671,39 @@ void edge_free_path(PathBase *pathbase, EPath *path) BLI_mempool_free(pathbase->pathpool, path); } -EPath *edge_find_shortest_path(BMesh *bm, BMEdge *edge, EdgeData *edata, PathBase *pathbase) +EPath *edge_find_shortest_path(BMesh *bm, BMOperator *op, BMEdge *edge, EdgeData *edata, + VertData *vdata, PathBase *pathbase, int group) { - BMIter iter; - BMEdge *e; + BMEdge *e, *starte; GHash *gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createops find shortest path"); BMVert *v1, *v2; BMVert **verts = NULL; - BLI_array_declare(verts); + BLI_array_staticdeclare(verts, 1024); Heap *heap = BLI_heap_new(); EPath *path = NULL, *path2; + BMVert *startv; + BMVert *endv; EPathNode *node; - int i; + int i, use_restrict = BMO_Get_Int(op, "use_restrict"); - path = edge_path_new(pathbase, edge->v1); + startv = edata[BMINDEX_GET(edge)].ftag ? edge->v2 : edge->v1; + endv = edata[BMINDEX_GET(edge)].ftag ? edge->v1 : edge->v2; + + path = edge_path_new(pathbase, startv, edge); + BLI_ghash_insert(gh, startv, NULL); BLI_heap_insert(heap, path->weight, path); - path = NULL; + path->group = group; while (BLI_heap_size(heap)) { - if (path) - edge_free_path(pathbase, path); + VertData *vd; + EPathNode *last; + BMFace *f = NULL; + path = BLI_heap_popmin(heap); - v1 = ((EPathNode*)path->nodes.last)->v; + last = path->nodes.last; + v1 = last->v; - if (v1 == edge->v2) { + if (v1 == endv) { /*make sure this path loop doesn't already exist*/ i = 0; BLI_array_empty(verts); @@ -159,33 +712,79 @@ EPath *edge_find_shortest_path(BMesh *bm, BMEdge *edge, EdgeData *edata, PathBas verts[i] = node->v; } - if (!BM_Face_Exists(bm, verts, i, NULL)) - break; - else - continue; + if (BM_Face_Exists(bm, verts, i, &f)) { + if (!BMO_TestFlag(bm, f, FACE_IGNORE)) { + BLI_ghash_remove(gh, endv, NULL, NULL); + continue; + } + } + break; } - - BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v1) { - if (e == edge || !BMO_TestFlag(bm, e, EDGE_MARK)) - continue; + + vd = vdata + BMINDEX_GET(v1); + if (!vd->e) + continue; + + v2 = NULL; + while (1) { + if (!last->cure) { + last->cure = e = vdata[BMINDEX_GET(last->v)].e; + } else { + last->cure = e = rotsys_nextedge(last->cure, last->v, edata, vdata); + if (last->cure == vdata[BMINDEX_GET(last->v)].e) { + v2 = NULL; + break; + } + } - v2 = BM_OtherEdgeVert(e, v1); + if (e == edge || !BMO_TestFlag(bm, e, EDGE_MARK)) { + continue; + } + + v2 = BM_OtherEdgeVert(e, last->v); - if (BLI_ghash_haskey(gh, v2)) + if (BLI_ghash_haskey(gh, v2)) { + v2 = NULL; continue; + } + + if (use_restrict && BMO_InMap(bm, op, "restrict", e)) { + int group = BMO_Get_MapInt(bm, op, "restrict", e); + + if (!(group & path->group)) { + v2 = NULL; + continue; + } + } - BLI_ghash_insert(gh, v2, NULL); - - path2 = edge_copy_add_path(pathbase, path, v2, e); - path2->weight = edge_weight_path(path2, edata); - - BLI_heap_insert(heap, path2->weight, path2); + break; + } + + if (!v2) { + if (path) { + edge_free_path(pathbase, path); + path = NULL; + } + continue; } + + /*add path back into heap*/ + BLI_heap_insert(heap, path->weight, path); + + /*put v2 in gh map*/ + BLI_ghash_insert(gh, v2, NULL); - if (BLI_heap_size(heap) == 0) - path = NULL; - } + path2 = edge_copy_add_path(pathbase, path, v2, e); + path2->weight = edge_weight_path(path2, edata, vdata); + BLI_heap_insert(heap, path2->weight, path2); + } + + if (path && ((EPathNode*)path->nodes.last)->v != endv) { + edge_free_path(pathbase, path); + path = NULL; + } + BLI_array_free(verts); BLI_heap_free(heap, NULL); BLI_ghash_free(gh, NULL, NULL); @@ -193,26 +792,56 @@ EPath *edge_find_shortest_path(BMesh *bm, BMEdge *edge, EdgeData *edata, PathBas return path; } +static int count_edge_faces(BMesh *bm, BMEdge *e) { + int i=0; + BMLoop *l = e->l; + + if (!l) + return 0; + + do { + if (!BMO_TestFlag(bm, l->f, FACE_IGNORE)) + i++; + + l = l->radial_next; + } while (l != e->l); + + return i; +} + void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op) { BMIter iter; BMOIter siter; - BMEdge *e, *edge; BMFace *f; + BMEdge *e, *edge; + BMVert *v, **verts = NULL; + BLI_array_declare(verts); EPath *path; EPathNode *node; EdgeData *edata; + VertData *vdata; BMEdge **edges = NULL; PathBase *pathbase = edge_pathbase_new(); BLI_array_declare(edges); - int i; + int use_restrict = BMO_Get_Int(op, "use_restrict"); + int i, j, group = 0; if (!bm->totvert || !bm->totedge) return; edata = MEM_callocN(sizeof(EdgeData)*bm->totedge, "EdgeData"); + vdata = MEM_callocN(sizeof(VertData)*bm->totvert, "VertData"); + BMO_Flag_Buffer(bm, op, "edges", EDGE_MARK, BM_EDGE); + BMO_Flag_Buffer(bm, op, "excludefaces", FACE_IGNORE, BM_FACE); + i = 0; + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + BMINDEX_SET(v, i); + i++; + } + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { BMO_SetFlag(bm, f, ELE_ORIG); } @@ -228,12 +857,38 @@ void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op) i += 1; } + init_rotsys(bm, edata, vdata); + while (1) { edge = NULL; - + group = 0; + BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) { + /*if restrict is on, only start on faces in the restrict map*/ + if (use_restrict && !BMO_InMap(bm, op, "restrict", e)) + continue; + if (edata[BMINDEX_GET(e)].tag < 2) { edge = e; + + if (use_restrict) { + int i=0, j=0, gi=0; + + group = BMO_Get_MapInt(bm, op, "restrict", e); + + for (i=0; i<30; i++) { + if (group & (1<<i)) { + j++; + gi = i; + + if (j-1 == edata[BMINDEX_GET(e)].tag) + break; + } + } + + group = 1<<gi; + } + break; } } @@ -243,11 +898,12 @@ void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op) edata[BMINDEX_GET(edge)].tag += 1; - path = edge_find_shortest_path(bm, edge, edata, pathbase); + path = edge_find_shortest_path(bm, op, edge, edata, vdata, pathbase, group); if (!path) continue; BLI_array_empty(edges); + BLI_array_empty(verts); i = 0; for (node=path->nodes.first; node; node=node->next) { if (!node->next) @@ -262,23 +918,44 @@ void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op) edata[BMINDEX_GET(e)].ftag++; BLI_array_growone(edges); edges[i++] = e; + + BLI_array_append(verts, node->v); } BLI_array_growone(edges); edges[i++] = edge; + edata[BMINDEX_GET(edge)].ftag++; + + for (j=0; j<i; j++) { + if (count_edge_faces(bm, edges[j]) >= 2) { + edge_free_path(pathbase, path); + break; + } + } + + if (j != i) + continue; + + if (i) { + f = BM_Make_Ngon(bm, edge->v1, edge->v2, edges, i, 1); + if (f && !BMO_TestFlag(bm, f, ELE_ORIG)) { + BMO_SetFlag(bm, f, FACE_NEW); + } - f = BM_Make_Ngon(bm, edge->v1, edge->v2, edges, i, 1); - if (f && !BMO_TestFlag(bm, f, ELE_ORIG)) - BMO_SetFlag(bm, f, FACE_NEW); - + if (use_restrict) + BMO_Insert_MapInt(bm, op, "faceout_groupmap", f, path->group); + } + edge_free_path(pathbase, path); } BMO_Flag_To_Slot(bm, op, "faceout", FACE_NEW, BM_FACE); BLI_array_free(edges); + BLI_array_free(verts); edge_pathbase_free(pathbase); MEM_freeN(edata); + MEM_freeN(vdata); } /* evaluate if entire quad is a proper convex quad */ diff --git a/source/blender/bmesh/operators/mesh_conv.c b/source/blender/bmesh/operators/mesh_conv.c index a45142a3c0b..942951c11c1 100644 --- a/source/blender/bmesh/operators/mesh_conv.c +++ b/source/blender/bmesh/operators/mesh_conv.c @@ -45,7 +45,8 @@ void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op) { Object *ob = BMO_Get_Pnt(op, "object"); Mesh *me = BMO_Get_Pnt(op, "mesh"); - MVert *mvert; + MVert *mvert, **verts = NULL; + BLI_array_declare(verts); MEdge *medge; MLoop *ml; MPoly *mpoly; @@ -185,14 +186,17 @@ void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op) { BMLoop *l; BLI_array_empty(fedges); + BLI_array_empty(verts); for (j=0; j<mpoly->totloop; j++) { ml = &me->mloop[mpoly->loopstart+j]; v = vt[ml->v]; e = et[ml->e]; BLI_array_growone(fedges); + BLI_array_growone(verts); fedges[j] = e; + verts[j] = v; } v1 = vt[me->mloop[mpoly->loopstart].v]; @@ -203,8 +207,8 @@ void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op) { v1 = fedges[0]->v2; v2 = fedges[0]->v1; } - - f = BM_Make_Ngon(bm, v1, v2, fedges, mpoly->totloop, 0); + + f = BM_Make_Face(bm, verts, fedges, mpoly->totloop); if (!f) { printf("Warning! Bad face in mesh" @@ -222,9 +226,11 @@ void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op) { if (i == me->act_face) bm->act_face = f; /*Copy over loop customdata*/ + j = 0; BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) { - CustomData_to_bmesh_block(&me->ldata, &bm->ldata, li, &l->head.data); + CustomData_to_bmesh_block(&me->ldata, &bm->ldata, mpoly->loopstart+j, &l->head.data); li++; + j++; } /*Copy Custom Data*/ diff --git a/source/blender/editors/include/ED_toolmode.h b/source/blender/editors/include/ED_toolmode.h new file mode 100755 index 00000000000..733ca6c74fc --- /dev/null +++ b/source/blender/editors/include/ED_toolmode.h @@ -0,0 +1,80 @@ +#if 0 +/** + * $Id: + * + * ***** 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) 2008 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef ED_TOOLMODE_H +#define ED_TOOLMODE_H + +struct ID; +struct View3D; +struct ARegion; +struct bContext; +struct wmWindowManager; +struct wmKeyConfig; +struct ReportList; +struct ViewContext; +struct bDeformGroup; +struct MDeformWeight; +struct MDeformVert; +struct Scene; +struct Mesh; +struct MCol; +struct UvVertMap; +struct UvMapVert; +struct CustomData; +struct BMEditMesh; +struct BMEditSelection; +struct BMesh; +struct BMVert; +struct BMEdge; +struct BMFace; +struct UvVertMap; +struct UvMapVert; +struct Material; +struct Object; +struct rcti; +struct wmOperator; + +typedef struct ToolModeDefine { + short idtype, icon; + char *name; + void (*create)(void *args); + void (*free)(void *self); + + /*called when mode is set active*/ + void (*enter)(void *self, struct bContext *C); + void (*exit)(void *self, struct bContext *C); + + /*called on draw*/ + void (*draw)(void *self, struct bContext *C); + /*modal is option, and should be used carefully*/ + void (*modal)(struct bContext *C, struct wmOperator *op, struct wmEvent *event); + + /*keymap stuff*/ + void (*create_keymap)(struct wmKeyConfig *km); + void (*keymap_poll)(struct bContext *C); +}; +#endif diff --git a/source/blender/editors/mesh/bmesh_select.c b/source/blender/editors/mesh/bmesh_select.c index dd86b2da9ee..0f24764f51f 100644 --- a/source/blender/editors/mesh/bmesh_select.c +++ b/source/blender/editors/mesh/bmesh_select.c @@ -440,7 +440,7 @@ BMVert *EDBM_findnearestvert(ViewContext *vc, int *dist, short sel, short strict } /* returns labda for closest distance v1 to line-piece v2-v3 */ -static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3) +float labda_PdistVL2Dfl( float *v1, float *v2, float *v3) { float rc[2], len; @@ -564,9 +564,14 @@ BMFace *EDBM_findnearestface(ViewContext *vc, int *dist) { if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) { - unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]); - BMFace *efa = BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, index-1); + unsigned int index; + BMFace *efa; + + view3d_validate_backbuf(vc); + index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]); + efa = BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, index-1); + if (efa) { struct { short mval[2]; int dist; BMFace *toFace; } data; diff --git a/source/blender/editors/mesh/bmesh_tools.c b/source/blender/editors/mesh/bmesh_tools.c index a614521cdba..ae37c6f9337 100644 --- a/source/blender/editors/mesh/bmesh_tools.c +++ b/source/blender/editors/mesh/bmesh_tools.c @@ -1357,7 +1357,7 @@ static int flip_normals(bContext *C, wmOperator *op) Object *obedit= CTX_data_edit_object(C); BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; - if (!EDBM_CallOpf(em, op, "reversefaces facaes=%hf", BM_SELECT)) + if (!EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT)) return OPERATOR_CANCELLED; DAG_id_flush_update(obedit->data, OB_RECALC_DATA); diff --git a/source/blender/editors/mesh/editbmesh_bvh.c b/source/blender/editors/mesh/editbmesh_bvh.c index c0f82a0fe23..daa80dfe6e3 100644 --- a/source/blender/editors/mesh/editbmesh_bvh.c +++ b/source/blender/editors/mesh/editbmesh_bvh.c @@ -185,7 +185,7 @@ static void raycallback(void *userdata, int index, const BVHTreeRay *ray, BVHTre { BMBVHTree *tree = userdata; BMLoop **ls = tree->em->looptris[index]; - float dist, uv[2], co1[3], co2[3], co3[3]; + float dist, uv[2]; dist = ray_tri_intersection(ray, hit->dist, ls[0]->v->co, ls[1]->v->co, ls[2]->v->co, uv, tree->epsilon); @@ -195,16 +195,10 @@ static void raycallback(void *userdata, int index, const BVHTreeRay *ray, BVHTre VECCOPY(hit->no, ls[0]->v->no); - VECCOPY(co1, ls[0]->v->co); - VECCOPY(co2, ls[1]->v->co); - VECCOPY(co3, ls[2]->v->co); - - mul_v3_fl(co1, uv[0]); - mul_v3_fl(co2, uv[1]); - mul_v3_fl(co3, 1.0f-uv[0]-uv[1]); - - add_v3_v3v3(hit->co, co1, co2); - add_v3_v3v3(hit->co, hit->co, co3); + copy_v3_v3(hit->co, ray->direction); + normalize_v3(hit->co); + mul_v3_fl(hit->co, dist); + add_v3_v3(hit->co, ray->origin); } } @@ -227,6 +221,10 @@ BMFace *BMBVH_RayCast(BMBVHTree *tree, float *co, float *dir, float *hitout) return NULL; } +BVHTree *BMBVH_BVHTree(BMBVHTree *tree) +{ + return tree->tree; +} static void vertsearchcallback(void *userdata, int index, const float *co, BVHTreeNearest *hit) { diff --git a/source/blender/editors/mesh/editbmesh_bvh.h b/source/blender/editors/mesh/editbmesh_bvh.h index c64700b729f..328bd6507c7 100644 --- a/source/blender/editors/mesh/editbmesh_bvh.h +++ b/source/blender/editors/mesh/editbmesh_bvh.h @@ -4,6 +4,7 @@ struct BMEdge; struct BMVert; struct RegionView3D; struct BMBVHTree; +struct BVHTree; #ifndef IN_EDITMESHBVH typedef struct BMBVHTree BMBVHTree; @@ -11,6 +12,7 @@ typedef struct BMBVHTree BMBVHTree; struct BMBVHTree *BMBVH_NewBVH(struct BMEditMesh *em); void BMBVH_FreeBVH(struct BMBVHTree *tree); +struct BVHTree *BMBVH_BVHTree(struct BMBVHTree *tree); struct BMFace *BMBVH_RayCast(struct BMBVHTree *tree, float *co, float *dir, float *hitout); diff --git a/source/blender/editors/mesh/knifetool.c b/source/blender/editors/mesh/knifetool.c new file mode 100755 index 00000000000..bbe0adc9d27 --- /dev/null +++ b/source/blender/editors/mesh/knifetool.c @@ -0,0 +1,1623 @@ +#if 1 +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Joseph Eagar, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <float.h> +#define _USE_MATH_DEFINES +#include <math.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> + +#include "DNA_ID.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_userdef_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_object_types.h" + +#include "MEM_guardedalloc.h" + +#include "PIL_time.h" + +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" /*for WM_operator_pystring */ +#include "BLI_editVert.h" +#include "BLI_array.h" +#include "BLI_ghash.h" +#include "BLI_memarena.h" +#include "BLI_mempool.h" +#include "BLI_math.h" +#include "BLI_kdopbvh.h" +#include "BLI_smallhash.h" + +#include "BKE_blender.h" +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_scene.h" +#include "BKE_mesh.h" +#include "BKE_tessmesh.h" +#include "BKE_depsgraph.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" /* for paint cursor */ + +#include "IMB_imbuf_types.h" + +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_view3d.h" +#include "ED_mesh.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "mesh_intern.h" +#include "editbmesh_bvh.h" + +#define MAXGROUP 30 + +/* knifetool operator */ +typedef struct KnifeVert { + BMVert *v; /*non-NULL if this is an original vert*/ + ListBase edges; + + float co[3], sco[3]; /*sco is screen coordinates*/ + short flag, draw, isface; +} KnifeVert; + +typedef struct Ref { + struct Ref *next, *prev; + void *ref; +} Ref; + +typedef struct KnifeEdge { + KnifeVert *v1, *v2; + BMFace *basef; /*face to restrict face fill to*/ + ListBase faces; + int draw; + + BMEdge *e, *oe; /*non-NULL if this is an original edge*/ +} KnifeEdge; + +#define KMAXDIST 12 /*max mouse distance from edge before not detecting it*/ +#define MARK 4 +#define DEL 8 + +typedef struct BMEdgeHit { + BMEdge *e; + float hit[3]; + float shit[3]; + float l; /*lambda along line*/ + BMVert *v; //set if snapped to a vert +} BMEdgeHit; + +/* struct for properties used while drawing */ +typedef struct knifetool_opdata { + ARegion *ar; /* region that knifetool was activated in */ + void *draw_handle; /* for drawing preview loop */ + ViewContext vc; + + Object *ob; + BMEditMesh *em; + + MemArena *arena; + + GHash *origvertmap; + GHash *origedgemap; + + GHash *kedgefacemap; + + BMBVHTree *bmbvh; + + BLI_mempool *kverts; + BLI_mempool *kedges; + + float vthresh; + float ethresh; + + float vertco[3]; + float prevco[3]; + + /*used for drag-cutting*/ + BMEdgeHit *linehits; + int totlinehit; + + /*if curedge is NULL, attach to curvert; + if curvert is NULL, attach to curbmface, + otherwise create null vert*/ + KnifeEdge *curedge, *prevedge; + KnifeVert *curvert, *prevvert; + BMFace *curbmface, *prevbmface; + + int totkedge, totkvert, cutnr; + + BLI_mempool *refs; + + float projmat[4][4]; + + enum { + MODE_IDLE, + MODE_DRAGGING, + MODE_CONNECT, + } mode; +} knifetool_opdata; + +static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f); + +static KnifeEdge *new_knife_edge(knifetool_opdata *kcd) +{ + kcd->totkedge++; + return BLI_mempool_calloc(kcd->kedges); +} + +static KnifeVert *new_knife_vert(knifetool_opdata *kcd, float *co) +{ + KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts); + + kcd->totkvert++; + + copy_v3_v3(kfv->co, co); + copy_v3_v3(kfv->sco, co); + + view3d_project_float(kcd->ar, kfv->co, kfv->sco, kcd->projmat); + + return kfv; +} + +/*get a KnifeVert wrapper for an existing BMVert*/ +static KnifeVert *get_bm_knife_vert(knifetool_opdata *kcd, BMVert *v) +{ + KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v); + + if (!kfv) { + kfv = new_knife_vert(kcd, v->co); + kfv->v = v; + BLI_ghash_insert(kcd->origvertmap, v, kfv); + } + + return kfv; +} + +/*get a KnifeEdge wrapper for an existing BMEdge*/ +static KnifeEdge *get_bm_knife_edge(knifetool_opdata *kcd, BMEdge *e) +{ + KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e); + if (!kfe) { + Ref *ref; + BMIter iter; + BMFace *f; + + kfe = new_knife_edge(kcd); + kfe->e = e; + kfe->v1 = get_bm_knife_vert(kcd, e->v1); + kfe->v2 = get_bm_knife_vert(kcd, e->v2); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = kfe; + BLI_addtail(&kfe->v1->edges, ref); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = kfe; + BLI_addtail(&kfe->v2->edges, ref); + + BLI_ghash_insert(kcd->origedgemap, e, kfe); + + BM_ITER(f, &iter, kcd->em->bm, BM_FACES_OF_EDGE, e) { + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = f; + BLI_addtail(&kfe->faces, ref); + + /*ensures the kedges lst for this f is initialized, + it automatically adds kfe by itself*/ + knife_get_face_kedges(kcd, f); + } + } + + return kfe; +} + +static void knife_start_cut(knifetool_opdata *kcd) +{ + kcd->prevedge = kcd->curedge; + kcd->prevvert = kcd->curvert; + kcd->prevbmface = kcd->curbmface; + kcd->cutnr++; + + copy_v3_v3(kcd->prevco, kcd->vertco); +} + +static Ref *find_ref(ListBase *lb, void *ref) +{ + Ref *ref1; + + for (ref1=lb->first; ref1; ref1=ref1->next) { + if (ref1->ref == ref) + return ref1; + } + + return NULL; +} + +static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f) +{ + ListBase *lst = BLI_ghash_lookup(kcd->kedgefacemap, f); + + if (!lst) { + BMIter iter; + BMEdge *e; + + lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase)); + lst->first = lst->last = NULL; + + BM_ITER(e, &iter, kcd->em->bm, BM_EDGES_OF_FACE, f) { + Ref *ref = BLI_mempool_calloc(kcd->refs); + ref->ref = get_bm_knife_edge(kcd, e); + BLI_addtail(lst, ref); + } + + BLI_ghash_insert(kcd->kedgefacemap, f, lst); + } + + return lst; +} + +/*finds the proper face to restrict face fill to*/ +void knife_find_basef(knifetool_opdata *kcd, KnifeEdge *kfe) +{ + if (!kfe->basef) { + Ref *r1, *r2, *r3, *r4; + + if (kfe->v1->isface || kfe->v2->isface) { + if (kfe->v2->isface) + kfe->basef = kcd->curbmface; + else + kfe->basef = kcd->prevbmface; + } else { + for (r1=kfe->v1->edges.first; r1 && !kfe->basef; r1=r1->next) { + KnifeEdge *ke1 = r1->ref; + for (r2=ke1->faces.first; r2 && !kfe->basef; r2=r2->next) { + for (r3=kfe->v2->edges.first; r3 && !kfe->basef; r3=r3->next) { + KnifeEdge *ke2 = r3->ref; + + for (r4=ke2->faces.first; r4 && !kfe->basef; r4=r4->next) { + if (r2->ref == r4->ref) { + kfe->basef = r2->ref; + } + } + } + } + } + } + /*ok, at this point kfe->basef should be set if any valid possibility + exists*/ + } +} + +static KnifeVert *knife_split_edge(knifetool_opdata *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out) +{ + KnifeEdge *newkfe = new_knife_edge(kcd); + ListBase *lst; + Ref *ref; + + newkfe->v1 = kfe->v1; + newkfe->v2 = new_knife_vert(kcd, co); + newkfe->v2->draw = 1; + newkfe->basef = kfe->basef; + + ref = find_ref(&kfe->v1->edges, kfe); + BLI_remlink(&kfe->v1->edges, ref); + + kfe->v1 = newkfe->v2; + BLI_addtail(&kfe->v1->edges, ref); + + for (ref=kfe->faces.first; ref; ref=ref->next) { + Ref *ref2 = BLI_mempool_calloc(kcd->refs); + + /*add kedge ref to bm faces*/ + lst = knife_get_face_kedges(kcd, ref->ref); + ref2->ref = newkfe; + BLI_addtail(lst, ref2); + + ref2 = BLI_mempool_calloc(kcd->refs); + ref2->ref = ref->ref; + BLI_addtail(&newkfe->faces, ref2); + } + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = newkfe; + BLI_addtail(&newkfe->v1->edges, ref); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = newkfe; + BLI_addtail(&newkfe->v2->edges, ref); + + newkfe->draw = kfe->draw; + newkfe->e = kfe->e; + + *newkfe_out = newkfe; + + return newkfe->v2; +} + +static void knife_edge_append_face(knifetool_opdata *kcd, KnifeEdge *kfe, BMFace *f) +{ + ListBase *lst = knife_get_face_kedges(kcd, f); + Ref *ref = BLI_mempool_calloc(kcd->refs); + + ref->ref = kfe; + BLI_addtail(lst, ref); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = f; + BLI_addtail(&kfe->faces, ref); +} + +static void knife_copy_edge_facelist(knifetool_opdata *kcd, KnifeEdge *dest, KnifeEdge *source) +{ + Ref *ref, *ref2; + + for (ref2 = source->faces.first; ref2; ref2=ref2->next) { + ListBase *lst = knife_get_face_kedges(kcd, ref2->ref); + + /*add new edge to face knife edge list*/ + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = dest; + BLI_addtail(lst, ref); + + /*add face to new edge's face list*/ + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = ref2->ref; + BLI_addtail(&dest->faces, ref); + } +} + +static void knife_add_single_cut(knifetool_opdata *kcd) +{ + KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL; + Ref *ref; + + if (kcd->prevvert && kcd->prevvert == kcd->curvert) + return; + if (kcd->prevedge && kcd->prevedge == kcd->curedge) + return; + + if (kcd->prevvert) { + kfe->v1 = kcd->prevvert; + } else if (kcd->prevedge) { + kfe->v1 = knife_split_edge(kcd, kcd->prevedge, kcd->prevco, &kfe2); + } else { + kfe->v1 = new_knife_vert(kcd, kcd->prevco); + kfe->v1->draw = 1; + kfe->v1->isface = 1; + } + + if (kcd->curvert) { + kfe->v2 = kcd->curvert; + } else if (kcd->curedge) { + kfe->v2 = knife_split_edge(kcd, kcd->curedge, kcd->vertco, &kfe3); + + kcd->curvert = kfe->v2; + } else { + kfe->v2 = new_knife_vert(kcd, kcd->vertco); + kfe->v2->draw = 1; + kfe->v2->isface = 1; + + kcd->curvert = kfe->v2; + } + + knife_find_basef(kcd, kfe); + + kfe->draw = 1; + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = kfe; + BLI_addtail(&kfe->v1->edges, ref); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = kfe; + BLI_addtail(&kfe->v2->edges, ref); + + if (kfe->basef && !find_ref(&kfe->faces, kfe->basef)) + knife_edge_append_face(kcd, kfe, kfe->basef); + + /*sanity check to make sure we're in the right edge/face lists*/ + if (kcd->curbmface) { + if (!find_ref(&kfe->faces, kcd->curbmface)) { + knife_edge_append_face(kcd, kfe, kcd->curbmface); + } + + if (kcd->prevbmface && kcd->prevbmface != kcd->curbmface) { + if (!find_ref(&kfe->faces, kcd->prevbmface)) { + knife_edge_append_face(kcd, kfe, kcd->prevbmface); + } + } + } + + /*set up for next cut*/ + kcd->prevbmface = kcd->curbmface; + kcd->prevvert = kcd->curvert; + kcd->prevedge = kcd->curedge; + copy_v3_v3(kcd->prevco, kcd->vertco); +} + +static int verge_linehit(const void *vlh1, const void *vlh2) +{ + const BMEdgeHit *lh1=vlh1, *lh2=vlh2; + + if (lh1->l < lh2->l) return -1; + else if (lh1->l > lh2->l) return 1; + else return 0; +} + +static void knife_add_cut(knifetool_opdata *kcd) +{ + BMEditMesh *em = kcd->em; + BMesh *bm = em->bm; + knifetool_opdata oldkcd = *kcd; + + if (kcd->linehits) { + BMEdgeHit *lh, *lastlh, *firstlh; + int i; + + qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit); + + lh = kcd->linehits; + lastlh = firstlh = NULL; + for (i=0; i<kcd->totlinehit; i++, (lastlh=lh), lh++) { + if (lastlh && len_v3v3(lastlh->hit, lh->hit) == 0.0f) { + if (!firstlh) + firstlh = lastlh; + continue; + } else if (lastlh && firstlh) { + if (firstlh->v || lastlh->v) { + BMVert *bmv = firstlh->v ? firstlh->v : lastlh->v; + + kcd->prevvert = get_bm_knife_vert(kcd, bmv); + copy_v3_v3(kcd->prevco, firstlh->hit); + kcd->prevedge = NULL; + kcd->prevbmface = firstlh->e->l ? firstlh->e->l->f : NULL; + } + lastlh = firstlh = NULL; + } + + if (!lastlh && len_v3v3(kcd->prevco, lh->hit) < FLT_EPSILON*10) + continue; + + kcd->curedge = get_bm_knife_edge(kcd, lh->e); + kcd->curbmface = kcd->curedge->e->l ? kcd->curedge->e->l->f : NULL; + kcd->curvert = lh->v ? get_bm_knife_vert(kcd, lh->v) : NULL; + copy_v3_v3(kcd->vertco, lh->hit); + + knife_add_single_cut(kcd); + } + + kcd->curbmface = oldkcd.curbmface; + kcd->curvert = oldkcd.curvert; + kcd->curedge = oldkcd.curedge; + copy_v3_v3(kcd->vertco, oldkcd.vertco); + + knife_add_single_cut(kcd); + + MEM_freeN(kcd->linehits); + kcd->linehits = NULL; + kcd->totlinehit = 0; + } else { + knife_add_single_cut(kcd); + } +} + +static void knife_finish_cut(knifetool_opdata *kcd) +{ + +} + +/* modal loop selection drawing callback */ +static void knifetool_draw(const bContext *C, ARegion *ar, void *arg) +{ + knifetool_opdata *kcd = arg; + + glDisable(GL_DEPTH_TEST); + + glPushMatrix(); + glMultMatrixf(kcd->ob->obmat); + + if (kcd->mode == MODE_DRAGGING) { + glColor3f(0.1, 0.1, 0.1); + glLineWidth(2.0); + + glBegin(GL_LINES); + glVertex3fv(kcd->prevco); + glVertex3fv(kcd->vertco); + glEnd(); + + glLineWidth(1.0); + } + + if (kcd->curedge) { + glColor3f(0.5, 0.3, 0.15); + glLineWidth(2.0); + + glBegin(GL_LINES); + glVertex3fv(kcd->curedge->v1->co); + glVertex3fv(kcd->curedge->v2->co); + glEnd(); + + glLineWidth(1.0); + } else if (kcd->curvert) { + glColor3f(0.8, 0.2, 0.1); + glPointSize(9); + + glBegin(GL_POINTS); + glVertex3fv(kcd->vertco); + glEnd(); + } + + if (kcd->curbmface) { + glColor3f(0.1, 0.8, 0.05); + glPointSize(7); + + glBegin(GL_POINTS); + glVertex3fv(kcd->vertco); + glEnd(); + } + + if (kcd->totlinehit > 0) { + BMEdgeHit *lh; + int i; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /*draw any snapped verts first*/ + glColor4f(0.8, 0.2, 0.1, 0.4); + glPointSize(9); + glBegin(GL_POINTS); + lh = kcd->linehits; + for (i=0; i<kcd->totlinehit; i++, lh++) { + float sv1[3], sv2[3]; + + view3d_project_float_v3(kcd->ar, lh->e->v1->co, sv1, kcd->projmat); + view3d_project_float_v3(kcd->ar, lh->e->v2->co, sv2, kcd->projmat); + + if (len_v2v2(lh->shit, sv1) < kcd->vthresh/4) { + copy_v3_v3(lh->hit, lh->e->v1->co); + glVertex3fv(lh->hit); + lh->v = lh->e->v1; + } else if (len_v2v2(lh->shit, sv2) < kcd->vthresh/4) { + copy_v3_v3(lh->hit, lh->e->v2->co); + glVertex3fv(lh->hit); + lh->v = lh->e->v2; + } + } + glEnd(); + + /*now draw the rest*/ + glColor4f(0.1, 0.8, 0.05, 0.4); + glPointSize(5); + glBegin(GL_POINTS); + lh = kcd->linehits; + for (i=0; i<kcd->totlinehit; i++, lh++) { + glVertex3fv(lh->hit); + } + glEnd(); + glDisable(GL_BLEND); + } + + if (kcd->totkedge > 0) { + BLI_mempool_iter iter; + KnifeEdge *kfe; + + glLineWidth(1.0); + glBegin(GL_LINES); + + BLI_mempool_iternew(kcd->kedges, &iter); + for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) { + if (!kfe->draw) + continue; + + glColor3f(0.2, 0.2, 0.2); + + glVertex3fv(kfe->v1->co); + glVertex3fv(kfe->v2->co); + } + + glEnd(); + glLineWidth(1.0); + } + + if (kcd->totkvert > 0) { + BLI_mempool_iter iter; + KnifeVert *kfv; + + glPointSize(4.0); + + glBegin(GL_POINTS); + BLI_mempool_iternew(kcd->kverts, &iter); + for (kfv=BLI_mempool_iterstep(&iter); kfv; kfv=BLI_mempool_iterstep(&iter)) { + if (!kfv->draw) + continue; + + glColor3f(0.6, 0.1, 0.2); + + glVertex3fv(kfv->co); + } + + glEnd(); + } + + glPopMatrix(); + glEnable(GL_DEPTH_TEST); +} + +BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float v1[3], + float v2[3], float v3[3], bglMats *mats, int *count) +{ + BVHTree *tree2 = BLI_bvhtree_new(3, FLT_EPSILON*4, 8, 8), *tree = BMBVH_BVHTree(bmtree); + BMEdgeHit *edges = NULL; + BLI_array_declare(edges); + SmallHash hash, *ehash = &hash; + BVHTreeOverlap *results, *result; + BMLoop *l, **ls; + float cos[9], uv[3], lambda; + int tot=0, i, j; + + BLI_smallhash_init(ehash); + + copy_v3_v3(cos, v1); + copy_v3_v3(cos+3, v2); + copy_v3_v3(cos+6, v3); + + BLI_bvhtree_insert(tree2, 0, cos, 3); + BLI_bvhtree_balance(tree2); + + result = results = BLI_bvhtree_overlap(tree, tree2, &tot); + + for (i=0; i<tot; i++, result++) { + float p[3]; + + ls = (BMLoop**)kcd->em->looptris[result->indexA]; + + for (j=0; j<3; j++) { + if (isect_line_tri_v3(ls[j]->e->v1->co, ls[j]->e->v2->co, v1, v2, v3, &lambda, uv)) { + float no[3], view[3], sp[3]; + + sub_v3_v3v3(p, ls[j]->e->v2->co, ls[j]->e->v1->co); + mul_v3_fl(p, lambda); + add_v3_v3(p, ls[j]->e->v1->co); + + view3d_project_float_v3(kcd->ar, p, sp, kcd->projmat); + view3d_unproject(mats, view, sp[0], sp[1], 0.0f); + sub_v3_v3v3(view, p, view); + normalize_v3(view); + + copy_v3_v3(no, view); + mul_v3_fl(no, -0.00001); + + /*go backwards toward view a bit*/ + add_v3_v3(p, no); + + if (!BMBVH_RayCast(bmtree, p, no, NULL) && !BLI_smallhash_haskey(ehash, (intptr_t)ls[j]->e)) { + BMEdgeHit hit; + + hit.e = ls[j]->e; + hit.v = NULL; + copy_v3_v3(hit.hit, p); + view3d_project_float_v3(kcd->ar, hit.hit, hit.shit, kcd->projmat); + + BLI_array_append(edges, hit); + BLI_smallhash_insert(ehash, (intptr_t)ls[j]->e, NULL); + } + } + } + } + + BLI_smallhash_release(ehash); + + if (results) + MEM_freeN(results); + + *count = BLI_array_count(edges); + return edges; +} + +/*finds (visible) edges that intersects the current screen drag line*/ +static void knife_find_line_hits(knifetool_opdata *kcd) +{ + bglMats mats; + BMEdgeHit *e1, *e2; + float v1[3], v2[3], v3[3], v4[4], s1[3], s2[3], view[3]; + int i, c1, c2; + + bgl_get_mats(&mats); + + if (kcd->linehits) { + MEM_freeN(kcd->linehits); + kcd->linehits = NULL; + kcd->totlinehit = 0; + } + + /*project screen line's 3d coordinates back into 2d*/ + view3d_project_float_v3(kcd->ar, kcd->prevco, s1, kcd->projmat); + view3d_project_float_v3(kcd->ar, kcd->vertco, s2, kcd->projmat); + + if (len_v2v2(s1, s2) < 1) + return; + + /*unproject screen line*/ + view3d_unproject(&mats, v1, s1[0], s1[1], 0.0f); + view3d_unproject(&mats, v2, s2[0], s2[1], 0.0f); + view3d_unproject(&mats, v3, s1[0], s1[1], 1.0f-FLT_EPSILON); + view3d_unproject(&mats, v4, s2[0], s2[1], 1.0f-FLT_EPSILON); + + mul_m4_v3(kcd->ob->imat, v1); + mul_m4_v3(kcd->ob->imat, v2); + mul_m4_v3(kcd->ob->imat, v3); + mul_m4_v3(kcd->ob->imat, v4); + + sub_v3_v3v3(view, v4, v1); + normalize_v3(view); + + /*test two triangles of sceen line's plane*/ + e1 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v2, v3, &mats, &c1); + e2 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v3, v4, &mats, &c2); + if (c1 && c2) { + e1 = MEM_reallocN(e1, sizeof(BMEdgeHit)*(c1+c2)); + memcpy(e1+c1, e2, sizeof(BMEdgeHit)*c2); + MEM_freeN(e2); + } else if (c2) { + e1 = e2; + } + + kcd->linehits = e1; + kcd->totlinehit = c1+c2; + + /*find position along screen line, used for sorting*/ + for (i=0; i<kcd->totlinehit; i++) { + BMEdgeHit *lh = e1+i; + + lh->l = len_v2v2(lh->shit, s1) / len_v2v2(s2, s1); + } +} + +static BMFace *knife_find_closest_face(knifetool_opdata *kcd, float co[3]) +{ + BMFace *f; + bglMats mats; + float origin[3], ray[3]; + float mval[2]; + int dist = KMAXDIST; + + bgl_get_mats(&mats); + + mval[0] = kcd->vc.mval[0]; mval[1] = kcd->vc.mval[1]; + + /*unproject to find view ray*/ + view3d_unproject(&mats, origin, mval[0], mval[1], 0.0f); + + sub_v3_v3v3(ray, origin, kcd->vc.rv3d->viewinv[3]); + normalize_v3(ray); + + /*transform into object space*/ + mul_m4_v3(kcd->ob->imat, origin); + mul_m4_v3(kcd->ob->imat, ray); + + f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co); + if (!f) { + /*try to use backbuffer selection method if ray casting failed*/ + f = EDBM_findnearestface(&kcd->vc, &dist); + + /*cheat for now; just put in the origin instead + of a true coordinate on the face*/ + copy_v3_v3(co, origin); + } + + //copy_v3_v3(co, origin); + + return f; +} + +/*find the 2d screen space density of vertices within a radius. used to scale snapping + distance for picking edges/verts.*/ +static int knife_sample_screen_density(knifetool_opdata *kcd, float radius) +{ + BMFace *f; + float co[3], sco[3]; + + f = knife_find_closest_face(kcd, co); + + if (f) { + ListBase *lst; + Ref *ref; + KnifeVert *curv = NULL; + float dis; + int c = 0; + + view3d_project_float_v3(kcd->ar, co, sco, kcd->projmat); + + lst = knife_get_face_kedges(kcd, f); + for (ref=lst->first; ref; ref=ref->next) { + KnifeEdge *kfe = ref->ref; + int i; + + for (i=0; i<2; i++) { + KnifeVert *kfv = i ? kfe->v2 : kfe->v1; + + view3d_project_float_v3(kcd->ar, kfv->co, kfv->sco, kcd->projmat); + + dis = len_v2v2(kfv->sco, sco); + if (dis < radius) { + if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + float vec[3]; + + copy_v3_v3(vec, kfv->co); + mul_m4_v3(kcd->vc.obedit->obmat, vec); + + if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) { + c++; + } + } else { + c++; + } + } + } + } + + return c; + } + + return 0; +} + +/*returns snapping distance for edges/verts, scaled by the density of the + surrounding mesh (in screen space)*/ +static float knife_snap_size(knifetool_opdata *kcd, float maxsize) +{ + float density = (float)knife_sample_screen_density(kcd, maxsize*2.0f); + + density = MAX2(density, 1); + + return MIN2(maxsize / (density*0.5f), maxsize); +} + +/*p is closest point on edge to the mouse cursor*/ +static KnifeEdge *knife_find_closest_edge(knifetool_opdata *kcd, float p[3], BMFace **fptr) +{ + BMFace *f; + float co[3], sco[3], maxdist = knife_snap_size(kcd, kcd->ethresh); + + f = knife_find_closest_face(kcd, co); + /*set p to co, in case we don't find anything, means a face cut*/ + copy_v3_v3(p, co); + + if (f) { + KnifeEdge *cure = NULL; + ListBase *lst; + Ref *ref; + float dis, curdis=FLT_MAX; + + view3d_project_float_v3(kcd->ar, co, sco, kcd->projmat); + + /*look through all edges associated with this face*/ + lst = knife_get_face_kedges(kcd, f); + for (ref=lst->first; ref; ref=ref->next) { + KnifeEdge *kfe = ref->ref; + + /*project edge vertices into screen space*/ + view3d_project_float_v3(kcd->ar, kfe->v1->co, kfe->v1->sco, kcd->projmat); + view3d_project_float_v3(kcd->ar, kfe->v2->co, kfe->v2->sco, kcd->projmat); + + dis = dist_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco); + if (dis < curdis && dis < maxdist) { + if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + float labda_PdistVL2Dfl(float *v1, float *v2, float *v3); + float labda= labda_PdistVL2Dfl(sco, kfe->v1->sco, kfe->v2->sco); + float vec[3]; + + vec[0]= kfe->v1->co[0] + labda*(kfe->v2->co[0] - kfe->v1->co[0]); + vec[1]= kfe->v1->co[1] + labda*(kfe->v2->co[1] - kfe->v1->co[1]); + vec[2]= kfe->v1->co[2] + labda*(kfe->v2->co[2] - kfe->v1->co[2]); + mul_m4_v3(kcd->vc.obedit->obmat, vec); + + if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) { + cure = kfe; + curdis = dis; + } + } else { + cure = kfe; + curdis = dis; + } + } + } + + if (fptr) + *fptr = f; + + if (cure && p) { + closest_to_line_segment_v3(p, co, cure->v1->co, cure->v2->co); + } + + return cure; + } + + if (fptr) + *fptr = NULL; + + return NULL; +} + +/*find a vertex near the mouse cursor, if it exists*/ +static KnifeVert *knife_find_closest_vert(knifetool_opdata *kcd, float p[3], BMFace **fptr) +{ + BMFace *f; + float co[3], sco[3], maxdist = knife_snap_size(kcd, kcd->vthresh); + + f = knife_find_closest_face(kcd, co); + /*set p to co, in case we don't find anything, means a face cut*/ + copy_v3_v3(p, co); + + if (f) { + ListBase *lst; + Ref *ref; + KnifeVert *curv = NULL; + float dis, curdis=FLT_MAX; + + view3d_project_float_v3(kcd->ar, co, sco, kcd->projmat); + + lst = knife_get_face_kedges(kcd, f); + for (ref=lst->first; ref; ref=ref->next) { + KnifeEdge *kfe = ref->ref; + int i; + + for (i=0; i<2; i++) { + KnifeVert *kfv = i ? kfe->v2 : kfe->v1; + + view3d_project_float_v3(kcd->ar, kfv->co, kfv->sco, kcd->projmat); + + dis = len_v2v2(kfv->sco, sco); + if (dis < curdis && dis < maxdist) { + if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + float vec[3]; + + copy_v3_v3(vec, kfv->co); + mul_m4_v3(kcd->vc.obedit->obmat, vec); + + if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) { + curv = kfv; + curdis = dis; + } + } else { + curv = kfv; + curdis = dis; + } + } + } + } + + if (fptr) + *fptr = f; + + if (curv && p) { + copy_v3_v3(p, curv->co); + } + + return curv; + } + + if (fptr) + *fptr = NULL; + + return NULL; +} + +/*update active knife edge/vert pointers*/ +static int knife_update_active(knifetool_opdata *kcd) +{ + kcd->curvert = NULL; kcd->curedge = NULL; kcd->curbmface = NULL; + + kcd->curvert = knife_find_closest_vert(kcd, kcd->vertco, &kcd->curbmface); + if (!kcd->curvert) + kcd->curedge = knife_find_closest_edge(kcd, kcd->vertco, &kcd->curbmface); + + if (kcd->mode == MODE_DRAGGING) { + knife_find_line_hits(kcd); + } + return 1; +} + +#define VERT_ON_EDGE 8 +#define VERT_ORIG 16 +#define FACE_FLIP 32 + +/*use edgenet to fill faces. this is a bit annoying and convoluted.*/ +void knifenet_fill_faces(knifetool_opdata *kcd) +{ + BLI_mempool_iter iter; + BMOperator bmop; + BMesh *bm = kcd->em->bm; + BMOIter siter; + BMIter bmiter; + BMFace *f; + BMEdge *e; + KnifeVert *kfv; + KnifeEdge *kfe; + float (*vertcos)[3] = NULL; + void **blocks = NULL; + BLI_array_declare(blocks); + BLI_array_declare(vertcos); + float *w = NULL; + BLI_array_declare(w); + + BMO_push(bm, NULL); + + BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) { + BMINDEX_SET(f, 0); + } + + /*assign a bit flag to each face. adjacent + faces cannot share the same bit flag, nor can + diagonally adjacent faces*/ + BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) { + BMIter bmiter2; + BMLoop *l; + int group = 0, ok=0; + + while (!ok) { + ok = 1; + BM_ITER(l, &bmiter2, bm, BM_LOOPS_OF_FACE, f) { + BMLoop *l2 = l->radial_next; + while (l2 != l) { + BMLoop *l3; + BMIter bmiter3; + + if (l2->f == l->f) { + l2 = l2->radial_next; + continue; + } + + if (BMINDEX_GET(l2->f) == (1<<group) && group <= MAXGROUP) { + group++; + ok = 0; + } else if (BMINDEX_GET(l2->f) == (1<<group)) { + printf("yeek! ran out of groups! 1\n"); + } + + BM_ITER(l3, &bmiter3, bm, BM_LOOPS_OF_FACE, l2->f) { + BMLoop *l4 = l3->radial_next; + + do { + if (l4->f == l->f) { + l4 = l4->radial_next; + continue; + } + + if (BMINDEX_GET(l4->f) == (1<<group) && group <= MAXGROUP) { + group++; + ok = 0; + } else if (BMINDEX_GET(l4->f) == (1<<group)) { + printf("yeek! ran out of groups! 2`\n"); + } + + l4 = l4->radial_next; + } while (l4 != l3); + } + + l2 = l2->radial_next; + } + } + } + + BMINDEX_SET(f, (1<<group)); + } + + /*turn knife verts into real verts, as necassary*/ + BLI_mempool_iternew(kcd->kverts, &iter); + for (kfv=BLI_mempool_iterstep(&iter); kfv; kfv=BLI_mempool_iterstep(&iter)) { + if (!kfv->v) { + kfv->v = BM_Make_Vert(bm, kfv->co, NULL); + kfv->flag = 1; + } else { + kfv->flag = 0; + BMO_SetFlag(bm, kfv->v, VERT_ORIG); + } + + BMO_SetFlag(bm, kfv->v, MARK); + } + + BMO_InitOpf(bm, &bmop, "edgenet_fill use_restrict=%i", 1); + + /*turn knife edges into real edges, and assigns bit masks representing + the faces they are adjacent too*/ + BLI_mempool_iternew(kcd->kedges, &iter); + for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) { + int group = 0; + + if (!kfe->v1 || !kfe->v2) + continue; + + if (kfe->e) { + BM_ITER(f, &bmiter, bm, BM_FACES_OF_EDGE, kfe->e) { + group |= BMINDEX_GET(f); + + if (kfe->v1->v != kfe->e->v1 || kfe->v2->v != kfe->e->v2) { + BMO_SetFlag(bm, f, DEL); + } + } + + kfe->oe = kfe->e; + + if (kfe->v1->v != kfe->e->v1 || kfe->v2->v != kfe->e->v2) { + BMO_SetFlag(bm, kfe->e, DEL); + BMO_ClearFlag(bm, kfe->e, MARK); + + if (kfe->v1->v != kfe->e->v1) + BMO_SetFlag(bm, kfe->v1->v, VERT_ON_EDGE); + if (kfe->v2->v != kfe->e->v2) + BMO_SetFlag(bm, kfe->v2->v, VERT_ON_EDGE); + + kfe->e = NULL; + } + } + + if (!kfe->e) { + kfe->e = BM_Make_Edge(bm, kfe->v1->v, kfe->v2->v, NULL, 0); + } + + BMO_SetFlag(bm, kfe->e, MARK); + + if (kfe->basef) { + BMEdge *e; + BM_ITER(e, &bmiter, bm, BM_EDGES_OF_FACE, kfe->basef) { + BMO_SetFlag(bm, e, MARK); + } + + BMO_SetFlag(bm, kfe->basef, DEL); + group |= BMINDEX_GET(kfe->basef); + } + + if (!group) { + Ref *ref; + + for (ref=kfe->faces.first; ref; ref=ref->next) { + kfe->basef = ref->ref; + group |= BMINDEX_GET(ref->ref); + } + } + + if (group) + BMO_Insert_MapInt(bm, &bmop, "restrict", kfe->e, group); + else + printf("yeek!\n"); + } + + /*not sure why this is needed, sanity check to make sure del'd edges are not + marked as well*/ + BM_ITER(e, &bmiter, bm, BM_EDGES_OF_MESH, NULL) { + if (BMO_TestFlag(bm, e, DEL)) + BMO_ClearFlag(bm, e, MARK); + } + + BMO_Flag_To_Slot(bm, &bmop, "edges", MARK, BM_EDGE); + BMO_Flag_To_Slot(bm, &bmop, "excludefaces", DEL, BM_FACE); + + /*execute the edgenet fill operator. it will restrict filled faces to edges + belonging to the same group (note edges can belong to multiple groups, using + bitmasks)*/ + BMO_Exec_Op(bm, &bmop); + BMO_Flag_Buffer(bm, &bmop, "faceout", MARK, BM_FACE); + + BM_Compute_Normals(bm); + + //void interp_weights_poly_v3(float *w,float v[][3], int n, float *co) + + /* interpolate customdata */ + + /*first deal with interpolating vertices that lie on original edges*/ + BLI_mempool_iternew(kcd->kedges, &iter); + for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) { + BMLoop *l1, *l2; + float fac, w[2]; + void *blocks[2]; + + if (!kfe->oe) + continue; + + BM_ITER(l1, &bmiter, bm, BM_LOOPS_OF_EDGE, kfe->oe) { + BMLoop *l2 = NULL; + BMIter liter; + int i, j; + + BM_ITER(l2, &liter, bm, BM_LOOPS_OF_EDGE, kfe->e) { + if (!BM_Vert_In_Edge(kfe->e, l2->next->v)) { + l2 = l2->prev; + } + + if (!BMO_InMap(bm, &bmop, "faceout_groupmap", l2->f)) + continue; + + if (BMINDEX_GET(l1->f) == BMO_Get_MapInt(bm, &bmop, "faceout_groupmap", l2->f)) + break; + } + + if (!l2) + continue; + + if (dot_v3v3(l1->f->no, l2->f->no) < 0.0f) { + BMO_SetFlag(bm, l2->f, FACE_FLIP); + } + + for (i=0; i<2; i++) { + if (i) + l2 = l2->next; + + fac = len_v3v3(kfe->oe->v1->co, l2->v->co) / (len_v3v3(kfe->oe->v1->co, kfe->oe->v2->co)+FLT_EPSILON); + + if (kfe->oe->v1 == l1->v) { + w[0] = 1.0-fac; + w[1] = fac; + } else { + w[0] = fac; + w[1] = 1.0-fac; + } + + if (l1->e == kfe->oe) { + blocks[0] = l1->head.data; + blocks[1] = l1->next->head.data; + } else { + blocks[0] = l1->prev->head.data; + blocks[1] = l1->head.data; + } + + BM_Copy_Attributes(bm, bm, l1->f, l2->f); + CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, 2, l2->head.data); + } + } + } + + /*ensure normals are correct*/ + BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) { + if (BMO_TestFlag(bm, f, FACE_FLIP)) { + BM_flip_normal(bm, f); + } + } + + /*now deal with interior vertex interpolation + still kindof buggy*/ + BMO_ITER(f, &siter, bm, &bmop, "faceout_groupmap", BM_FACE) { + BMLoop *l1, *l2; + BMFace *f2; + BMIter liter1, liter2; + int group = *(int*)BMO_IterMapVal(&siter); + + BM_ITER(l1, &liter1, bm, BM_LOOPS_OF_FACE, f) { + float co[3], hit[3]; + float dir[3]; + int i; + + if (BMO_TestFlag(bm, l1->v, VERT_ORIG) || BMO_TestFlag(bm, l1->v, VERT_ON_EDGE)) + continue; + + copy_v3_v3(co, l1->v->co); + copy_v3_v3(dir, l1->v->no); + mul_v3_fl(dir, 0.001f); + + add_v3_v3(co, dir); + copy_v3_v3(dir, l1->v->no); + mul_v3_fl(dir, -1.0); + + f2 = BMBVH_RayCast(kcd->bmbvh, co, dir, hit); + if (!f2) { + printf("eek!!\n"); + continue; + } + + BLI_array_empty(vertcos); + BLI_array_empty(blocks); + BLI_array_empty(w); + BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_FACE, f2) { + BLI_array_growone(vertcos); + BLI_array_append(blocks, l2->head.data); + + copy_v3_v3(vertcos[BLI_array_count(vertcos)-1], l2->v->co); + BLI_array_append(w, 0.0f); + } + + BM_Copy_Attributes(bm, bm, f2, f); + + interp_weights_poly_v3(w, vertcos, f2->len, l1->v->co); + CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, BLI_array_count(blocks), l1->head.data); + } + } + + BMO_Finish_Op(bm, &bmop); + + /*delete left over faces*/ + BMO_CallOpf(bm, "del geom=%ff context=%i", DEL, DEL_ONLYFACES); + BMO_CallOpf(bm, "del geom=%fe context=%i", DEL, DEL_EDGES); + + BMO_pop(bm); +} + +/*called on tool confirmation*/ +static void knifetool_finish(bContext *C, wmOperator *op) +{ + knifetool_opdata *kcd= op->customdata; + + knifenet_fill_faces(kcd); +} + +void knife_recalc_projmat(knifetool_opdata *kcd) +{ + invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); + view3d_get_object_project_mat(kcd->ar->regiondata, kcd->ob, kcd->projmat); +} + +/* called when modal loop selection is done... */ +static void knifetool_exit (bContext *C, wmOperator *op) +{ + knifetool_opdata *kcd= op->customdata; + + if (!kcd) + return; + + /* deactivate the extra drawing stuff in 3D-View */ + ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle); + + /* free the custom data */ + BLI_mempool_destroy(kcd->refs); + BLI_mempool_destroy(kcd->kverts); + BLI_mempool_destroy(kcd->kedges); + + BLI_ghash_free(kcd->origedgemap, NULL, NULL); + BLI_ghash_free(kcd->origvertmap, NULL, NULL); + BLI_ghash_free(kcd->kedgefacemap, NULL, NULL); + + BMBVH_FreeBVH(kcd->bmbvh); + BLI_memarena_free(kcd->arena); + + /* tag for redraw */ + ED_region_tag_redraw(kcd->ar); + + /* destroy kcd itself */ + MEM_freeN(kcd); + op->customdata= NULL; +} + +/* called when modal loop selection gets set up... */ +static int knifetool_init (bContext *C, wmOperator *op, int do_cut) +{ + knifetool_opdata *kcd; + + /* alloc new customdata */ + kcd= op->customdata= MEM_callocN(sizeof(knifetool_opdata), "knifetool Modal Op Data"); + + /* assign the drawing handle for drawing preview line... */ + kcd->ar= CTX_wm_region(C); + kcd->draw_handle= ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW); + em_setup_viewcontext(C, &kcd->vc); + + kcd->ob = CTX_data_edit_object(C); + kcd->em= ((Mesh *)kcd->ob->data)->edit_btmesh; + kcd->bmbvh = BMBVH_NewBVH(kcd->em); + kcd->arena = BLI_memarena_new(1<<15, "knife"); + kcd->vthresh = KMAXDIST-1; + kcd->ethresh = KMAXDIST; + + knife_recalc_projmat(kcd); + + ED_region_tag_redraw(kcd->ar); + + kcd->refs = BLI_mempool_create(sizeof(Ref), 1, 2048, 0, 0); + kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 1, 512, 0, 1); + kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 1, 512, 0, 1); + + kcd->origedgemap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origedgemap"); + kcd->origvertmap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origvertmap"); + kcd->kedgefacemap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origvertmap"); + + return 1; +} + +static int knifetool_cancel (bContext *C, wmOperator *op) +{ + /* this is just a wrapper around exit() */ + knifetool_exit(C, op); + return OPERATOR_CANCELLED; +} + +static int knifetool_invoke (bContext *C, wmOperator *op, wmEvent *evt) +{ + knifetool_opdata *kcd; + + view3d_operator_needs_opengl(C); + + if (!knifetool_init(C, op, 0)) + return OPERATOR_CANCELLED; + + /* add a modal handler for this operator - handles loop selection */ + WM_event_add_modal_handler(C, op); + + kcd = op->customdata; + kcd->vc.mval[0] = evt->mval[0]; + kcd->vc.mval[1] = evt->mval[1]; + + return OPERATOR_RUNNING_MODAL; +} + +static int knifetool_modal (bContext *C, wmOperator *op, wmEvent *event) +{ + knifetool_opdata *kcd= op->customdata; + + view3d_operator_needs_opengl(C); + + switch (event->type) { + case ESCKEY: + case RETKEY: /* confirm */ // XXX hardcoded + if (event->val == KM_RELEASE) { + /* finish */ + ED_region_tag_redraw(kcd->ar); + + knifetool_finish(C, op); + knifetool_exit(C, op); + + return OPERATOR_FINISHED; + } + + ED_region_tag_redraw(kcd->ar); + return OPERATOR_RUNNING_MODAL; + case LEFTMOUSE: + knife_recalc_projmat(kcd); + if (event->val != KM_RELEASE) + break; + + if (kcd->mode == MODE_DRAGGING) { + knife_add_cut(kcd); + if (!event->ctrl) { + knife_finish_cut(kcd); + kcd->mode = MODE_IDLE; + } + } else { + knife_start_cut(kcd); + kcd->mode = MODE_DRAGGING; + } + + ED_region_tag_redraw(kcd->ar); + return OPERATOR_RUNNING_MODAL; + case LEFTCTRLKEY: + case RIGHTCTRLKEY: + knife_recalc_projmat(kcd); + + if (event->val == KM_RELEASE) { + knife_finish_cut(kcd); + kcd->mode = MODE_IDLE; + } + + ED_region_tag_redraw(kcd->ar); + return OPERATOR_RUNNING_MODAL; + case MOUSEMOVE: { /* mouse moved somewhere to select another loop */ + knife_recalc_projmat(kcd); + kcd->vc.mval[0] = event->mval[0]; + kcd->vc.mval[1] = event->mval[1]; + + if (knife_update_active(kcd)) + ED_region_tag_redraw(kcd->ar); + + break; + /*block undo*/ + case ZKEY: + if (event->ctrl) + return OPERATOR_RUNNING_MODAL; + } + } + + /* keep going until the user confirms */ + return OPERATOR_PASS_THROUGH; +} + +void MESH_OT_knifetool (wmOperatorType *ot) +{ + /* description */ + ot->name= "Knife Topology Tool"; + ot->idname= "MESH_OT_knifetool"; + ot->description= "Cut new topology"; + + /* callbacks */ + ot->invoke= knifetool_invoke; + ot->modal= knifetool_modal; + ot->cancel= knifetool_cancel; + ot->poll= ED_operator_editmesh_view3d; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; +} +#endif + +/* + if (0) { + ListBase fgroups[30]; + BMEdge *e; + + memset(fgroups, 0, sizeof(fgroups)); + BM_ITER(f, &bmiter, kcd->em->bm, BM_FACES_OF_MESH, NULL) { + Ref *ref = BLI_mempool_alloc(kcd->refs); + int i; + + ref->ref = f; + for (i=0; i<30; i++) { + if ((1<<i) == BMINDEX_GET(f)) + break; + } + + BLI_addtail(&fgroups[i], ref); + } + + BM_ITER(e, &bmiter, kcd->em->bm, BM_EDGES_OF_MESH, NULL) { + Ref *ref; + int group = 0; + + if (!BMO_InMap(kcd->em->bm, &bmop, "restrict", e)) + continue; + + group = BMO_Get_MapInt(kcd->em->bm, &bmop, "restrict", e); + + for (i=0; i<30; i++) { + if ((1<<i) & group) { + float co[3]; + BMVert *v1, *v2; + + add_v3_v3v3(co, e->v1->co, e->v2->co); + mul_v3_fl(co, 0.5f); + + v1 = BM_Make_Vert(kcd->em->bm, co, NULL); + + for (ref=fgroups[i].first; ref; ref=ref->next) { + BMFace *f = ref->ref; + BMLoop *l; + BMIter liter; + BMEdge *e2; + + zero_v3(co); + BM_ITER(l, &liter, kcd->em->bm, BM_LOOPS_OF_FACE, f) { + add_v3_v3(co, l->v->co); + } + mul_v3_fl(co, 1.0f/(float)f->len); + + v2 = BM_Make_Vert(kcd->em->bm, co, NULL); + e2 = BM_Make_Edge(kcd->em->bm, v1, v2, NULL, 0); + } + } + } + } + } + + */ diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index 282ed48a476..a699561e4bb 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -265,7 +265,8 @@ static void ringsel_find_edge(tringselOpData *lcd, const bContext *C, ARegion *a if (lcd->eed) { edgering_sel(lcd, cuts, 0); } else { - MEM_freeN(lcd->edges); + if (lcd->edges) + MEM_freeN(lcd->edges); lcd->edges = NULL; lcd->totedge = 0; } diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 28c72121d2f..327d0e95487 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -305,5 +305,7 @@ void MESH_OT_bm_test(struct wmOperatorType *ot); void MESH_OT_edgering_select(struct wmOperatorType *ot); void MESH_OT_loopcut(struct wmOperatorType *ot); +void MESH_OT_knifetool(struct wmOperatorType *ot); + #endif // MESH_INTERN_H diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 621f20144b5..f966852672f 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -143,6 +143,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_solidify); WM_operatortype_append(MESH_OT_select_nth); WM_operatortype_append(MESH_OT_vert_connect); + WM_operatortype_append(MESH_OT_knifetool); } int ED_operator_editmesh_face_select(bContext *C) @@ -294,8 +295,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MESH_OT_delete", XKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MESH_OT_delete", DELKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, 0, KKEY); - RNA_enum_set(WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, KM_SHIFT, KKEY)->ptr, "type", 2/*KNIFE_MIDPOINT*/); + WM_keymap_add_item(keymap, "MESH_OT_knifetool", KKEY, KM_PRESS, 0, 0); + //RNA_enum_set(WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, KM_SHIFT, KKEY)->ptr, "type", 2/*KNIFE_MIDPOINT*/); WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index dd5a7d60fbd..35924ad9afb 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -2883,11 +2883,13 @@ static void project_paint_begin(ProjPaintState *ps) ps->dm_mvert= MEM_dupallocN(ps->dm_mvert); ps->dm_mface= MEM_dupallocN(ps->dm_mface); /* looks like these are ok for now.*/ - /* + ps->dm_mtface= MEM_dupallocN(ps->dm_mtface); - ps->dm_mtface_clone= MEM_dupallocN(ps->dm_mtface_clone); - ps->dm_mtface_stencil= MEM_dupallocN(ps->dm_mtface_stencil); - */ + if (ps->dm_mtface_clone) + ps->dm_mtface_clone= MEM_dupallocN(ps->dm_mtface_clone); + if (ps->dm_mtface_stencil) + ps->dm_mtface_stencil= MEM_dupallocN(ps->dm_mtface_stencil); + } ps->viewDir[0] = 0.0f; @@ -4660,6 +4662,9 @@ static int texture_paint_init(bContext *C, wmOperator *op) Mesh *me; pop->s.ob = OBACT; + if (!pop->ps.ob) + pop->ps.ob = pop->s.ob; + pop->s.me = get_mesh(pop->s.ob); if (!pop->s.me) return 0; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 4361f4f2fb4..12b9e982d02 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1609,7 +1609,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P for (i=0; i<mpoly->totloop; i++, ml++) { if ((me->dvert+ml->v)->flag) { alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*ml->v, mval, pressure); - if(alpha) { + if(alpha != 0.0f) { do_weight_paint_vertex(wp, ob, ml->v, alpha, paintweight, flip, wpd->vgroup_mirror, wpd->vgroup_validmap); @@ -1882,7 +1882,7 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent make_vertexcol(ob); if(me->mloopcol==NULL) return OPERATOR_CANCELLED; - + /* make mode data storage */ vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData"); paint_stroke_set_mode_data(stroke, vpd); @@ -2019,7 +2019,8 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P MLoopCol *mlc; unsigned int *lcol = ((unsigned int*)me->mloopcol) + mpoly->loopstart; unsigned int *lcolorig = ((unsigned int*)vp->vpaint_prev) + mpoly->loopstart; - int i, j, alpha; + float alpha; + int i, j; if(brush->vertexpaint_tool==VP_BLUR) { unsigned int blend[5] = {0}; @@ -2050,7 +2051,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P for (i=0; i<mpoly->totloop; i++, ml++) { alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*ml->v, mval, pressure); - if(alpha) vpaint_blend(vp, lcol+i, lcolorig+i, vpd->paintcol, alpha); + if(alpha > 0.0f) vpaint_blend(vp, lcol+i, lcolorig+i, vpd->paintcol, (int)(alpha*255.0f)); } #ifdef CPYCOL diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 64289f9bd0a..532c13314fd 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -688,7 +688,7 @@ void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, out[2] = uz; } -/* use above call to get projecting mat */ +/* use view3d_get_object_project_mat to get projecting mat */ void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4]) { float vec4[4]; @@ -708,7 +708,7 @@ void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4]) } } -/* use above call to get projecting mat */ +/* use view3d_get_object_project_mat to get projecting mat */ void view3d_project_float_v3(ARegion *ar, float *vec, float *adr, float mat[4][4]) { float vec4[4]; diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index aa377f063e1..3fdbe0bcc13 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -44,7 +44,7 @@ #include "ED_keyframing.h" #include "ED_keyframes_edit.h" - + EnumPropertyItem fmodifier_type_items[] = { {FMODIFIER_TYPE_NULL, "NULL", 0, "Invalid", ""}, {FMODIFIER_TYPE_GENERATOR, "GENERATOR", 0, "Generator", ""}, |