diff options
author | Joseph Eagar <joeedh@gmail.com> | 2010-09-25 05:54:58 +0400 |
---|---|---|
committer | Joseph Eagar <joeedh@gmail.com> | 2010-09-25 05:54:58 +0400 |
commit | 421823e34e5d45dc8c974189b7f0fa5423fde3a0 (patch) | |
tree | 1b498339c2ff523ed350b0813a060865a62505d6 | |
parent | 82432d0d99f2101ee2ceba86bdc49669b5fa306f (diff) |
=BMesh: Super Knife Tool Alpha=
Implemented a new "super knife". Activate with k. Holding CTRL
will allow extended cutting ala old lines mode. Confirm with enter
and escape. You cannot cancel, btw, you can only confirm (and undo
later if you want). Hopefully I'll support undo within the tool soon.
* Supports cutting edges, into faces, etc. You can pretty much do whatever
you want. Will snap to vertices too.
* Note that if you cut into a face, it must be valid topologically when
you press enter to confirm.
* It's pretty and graphical :)
* You can only cut visible geometry.
* UVs/vcols are a little buggy still
Now, thou shalt all cease and desist all lack of motivation for
testing! No longer shall users put off testing until "it's cooler"!
:P
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", ""}, |