2009-01-14 12:26:45 +00:00
|
|
|
/**
|
|
|
|
* $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) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
#else
|
|
|
|
#include <io.h>
|
|
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "BMF_Api.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_arithb.h"
|
|
|
|
#include "BLI_dynstr.h"
|
|
|
|
#include "BLI_rand.h"
|
|
|
|
|
|
|
|
#include "DNA_curve_types.h"
|
|
|
|
#include "DNA_key_types.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
#include "DNA_space_types.h"
|
|
|
|
#include "DNA_view3d_types.h"
|
|
|
|
#include "DNA_userdef_types.h"
|
|
|
|
|
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_curve.h"
|
|
|
|
#include "BKE_depsgraph.h"
|
2.5: Blender "Animato" - New Animation System
Finally, here is the basic (functional) prototype of the new animation system which will allow for the infamous "everything is animatable", and which also addresses several of the more serious shortcomings of the old system. Unfortunately, this will break old animation files (especially right now, as I haven't written the version patching code yet), however, this is for the future.
Highlights of the new system:
* Scrapped IPO-Curves/IPO/(Action+Constraint-Channels)/Action system, and replaced it with F-Curve/Action.
- F-Curves (animators from other packages will feel at home with this name) replace IPO-Curves.
- The 'new' Actions, act as the containers for F-Curves, so that they can be reused. They are therefore more akin to the old 'IPO' blocks, except they do not have the blocktype restriction, so you can store materials/texture/geometry F-Curves in the same Action as Object transforms, etc.
* F-Curves use RNA-paths for Data Access, hence allowing "every" (where sensible/editable that is) user-accessible setting from RNA to be animated.
* Drivers are no longer mixed with Animation Data, so rigs will not be that easily broken and several dependency problems can be eliminated. (NOTE: drivers haven't been hooked up yet, but the code is in place)
* F-Curve modifier system allows useful 'large-scale' manipulation of F-Curve values, including (I've only included implemented ones here): envelope deform (similar to lattices to allow broad-scale reshaping of curves), curve generator (polynomial or py-expression), cycles (replacing the old cyclic extrapolation modes, giving more control over this). (NOTE: currently this cannot be tested, as there's not access to them, but the code is all in place)
* NLA system with 'tracks' (i.e. layers), and multiple strips per track. (NOTE: NLA system is not yet functional, as it's only partially coded still)
There are more nice things that I will be preparing some nice docs for soon, but for now, check for more details:
http://lists.blender.org/pipermail/bf-taskforce25/2009-January/000260.html
So, what currently works:
* I've implemented two basic operators for the 3D-view only to Insert and Delete Keyframes. These are tempolary ones only that will be replaced in due course with 'proper' code.
* Object Loc/Rot/Scale can be keyframed. Also, the colour of the 'active' material (Note: this should really be for nth material instead, but that doesn't work yet in RNA) can also be keyframed into the same datablock.
* Standard animation refresh (i.e. animation resulting from NLA and Action evaluation) is now done completely separate from drivers before anything else is done after a frame change. Drivers are handled after this in a separate pass, as dictated by depsgraph flags, etc.
Notes:
* Drivers haven't been hooked up yet
* Only objects and data directly linked to objects can be animated.
* Depsgraph will need further tweaks. Currently, I've only made sure that it will update some things in the most basic cases (i.e. frame change).
* Animation Editors are currently broken (in terms of editing stuff). This will be my next target (priority to get Dopesheet working first, then F-Curve editor - i.e. old IPO Editor)
* I've had to put in large chunks of XXX sandboxing for old animation system code all around the place. This will be cleaned up in due course, as some places need special review.
In particular, the particles and sequencer code have far too many manual calls to calculate + flush animation info, which is really bad (this is a 'please explain yourselves' call to Physics coders!).
2009-01-17 03:12:50 +00:00
|
|
|
#include "BKE_fcurve.h"
|
2009-01-14 12:26:45 +00:00
|
|
|
#include "BKE_key.h"
|
|
|
|
#include "BKE_library.h"
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_main.h"
|
|
|
|
#include "BKE_object.h"
|
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
|
2009-02-04 17:40:50 +00:00
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
2009-01-14 12:26:45 +00:00
|
|
|
#include "ED_anim_api.h"
|
|
|
|
#include "ED_keyframes_edit.h"
|
|
|
|
#include "ED_object.h"
|
|
|
|
#include "ED_types.h"
|
|
|
|
#include "ED_util.h"
|
|
|
|
#include "ED_view3d.h"
|
|
|
|
|
|
|
|
/* still need to eradicate a few :( */
|
|
|
|
#define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name)
|
|
|
|
|
2.5: Blender "Animato" - New Animation System
Finally, here is the basic (functional) prototype of the new animation system which will allow for the infamous "everything is animatable", and which also addresses several of the more serious shortcomings of the old system. Unfortunately, this will break old animation files (especially right now, as I haven't written the version patching code yet), however, this is for the future.
Highlights of the new system:
* Scrapped IPO-Curves/IPO/(Action+Constraint-Channels)/Action system, and replaced it with F-Curve/Action.
- F-Curves (animators from other packages will feel at home with this name) replace IPO-Curves.
- The 'new' Actions, act as the containers for F-Curves, so that they can be reused. They are therefore more akin to the old 'IPO' blocks, except they do not have the blocktype restriction, so you can store materials/texture/geometry F-Curves in the same Action as Object transforms, etc.
* F-Curves use RNA-paths for Data Access, hence allowing "every" (where sensible/editable that is) user-accessible setting from RNA to be animated.
* Drivers are no longer mixed with Animation Data, so rigs will not be that easily broken and several dependency problems can be eliminated. (NOTE: drivers haven't been hooked up yet, but the code is in place)
* F-Curve modifier system allows useful 'large-scale' manipulation of F-Curve values, including (I've only included implemented ones here): envelope deform (similar to lattices to allow broad-scale reshaping of curves), curve generator (polynomial or py-expression), cycles (replacing the old cyclic extrapolation modes, giving more control over this). (NOTE: currently this cannot be tested, as there's not access to them, but the code is all in place)
* NLA system with 'tracks' (i.e. layers), and multiple strips per track. (NOTE: NLA system is not yet functional, as it's only partially coded still)
There are more nice things that I will be preparing some nice docs for soon, but for now, check for more details:
http://lists.blender.org/pipermail/bf-taskforce25/2009-January/000260.html
So, what currently works:
* I've implemented two basic operators for the 3D-view only to Insert and Delete Keyframes. These are tempolary ones only that will be replaced in due course with 'proper' code.
* Object Loc/Rot/Scale can be keyframed. Also, the colour of the 'active' material (Note: this should really be for nth material instead, but that doesn't work yet in RNA) can also be keyframed into the same datablock.
* Standard animation refresh (i.e. animation resulting from NLA and Action evaluation) is now done completely separate from drivers before anything else is done after a frame change. Drivers are handled after this in a separate pass, as dictated by depsgraph flags, etc.
Notes:
* Drivers haven't been hooked up yet
* Only objects and data directly linked to objects can be animated.
* Depsgraph will need further tweaks. Currently, I've only made sure that it will update some things in the most basic cases (i.e. frame change).
* Animation Editors are currently broken (in terms of editing stuff). This will be my next target (priority to get Dopesheet working first, then F-Curve editor - i.e. old IPO Editor)
* I've had to put in large chunks of XXX sandboxing for old animation system code all around the place. This will be cleaned up in due course, as some places need special review.
In particular, the particles and sequencer code have far too many manual calls to calculate + flush animation info, which is really bad (this is a 'please explain yourselves' call to Physics coders!).
2009-01-17 03:12:50 +00:00
|
|
|
/* for curve objects in editmode that can have hidden handles */
|
2009-01-14 12:26:45 +00:00
|
|
|
#define BEZSELECTED_HIDDENHANDLES(bezt) ((G.f & G_HIDDENHANDLES) ? (bezt)->f2 & SELECT : BEZSELECTED(bezt))
|
|
|
|
|
|
|
|
/* XXX */
|
|
|
|
static void BIF_undo_push() {}
|
|
|
|
static void waitcursor() {}
|
|
|
|
static void error() {}
|
|
|
|
static int okee() {return 0;}
|
|
|
|
static int pupmenu() {return 0;}
|
|
|
|
static int button() {return 0;}
|
|
|
|
static float fbutton() {return 0;}
|
|
|
|
static void adduplicate() {}
|
|
|
|
static void error_libdata() {}
|
|
|
|
/* XXX */
|
|
|
|
|
|
|
|
float nurbcircle[8][2]= {
|
|
|
|
{0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0, 1.0},
|
|
|
|
{0.0, 1.0}, { 1.0, 1.0}, { 1.0, 0.0}, { 1.0, -1.0}
|
|
|
|
};
|
|
|
|
|
|
|
|
ListBase *curve_get_editcurve(Object *ob)
|
|
|
|
{
|
|
|
|
if(ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
|
|
|
|
Curve *cu= ob->data;
|
|
|
|
return cu->editnurb;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this replaces the active flag used in uv/face mode */
|
|
|
|
void set_actNurb(Object *obedit, Nurb *nu)
|
|
|
|
{
|
|
|
|
Curve *cu= obedit->data;
|
|
|
|
|
|
|
|
if (nu==NULL) {
|
|
|
|
cu->actnu = -1;
|
|
|
|
} else {
|
|
|
|
cu->actnu = BLI_findindex(cu->editnurb, nu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Nurb *get_actNurb(Object *obedit)
|
|
|
|
{
|
|
|
|
Curve *cu= obedit->data;
|
|
|
|
|
|
|
|
return BLI_findlink(cu->editnurb, cu->actnu);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ******************* SELECTION FUNCTIONS ********************* */
|
|
|
|
|
|
|
|
#define HIDDEN 1
|
|
|
|
#define VISIBLE 0
|
|
|
|
|
|
|
|
#define FIRST 1
|
|
|
|
#define LAST 0
|
|
|
|
|
|
|
|
|
|
|
|
/* returns 1 in case (de)selection was successful */
|
|
|
|
static short select_beztriple(BezTriple *bezt, short selstatus, short flag, short hidden)
|
|
|
|
{
|
|
|
|
if(bezt) {
|
|
|
|
if((bezt->hide==0) || (hidden==1)) {
|
|
|
|
if(selstatus==1) { /* selects */
|
|
|
|
bezt->f1 |= flag;
|
|
|
|
bezt->f2 |= flag;
|
|
|
|
bezt->f3 |= flag;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else { /* deselects */
|
|
|
|
bezt->f1 &= ~flag;
|
|
|
|
bezt->f2 &= ~flag;
|
|
|
|
bezt->f3 &= ~flag;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns 1 in case (de)selection was successful */
|
|
|
|
static short select_bpoint(BPoint *bp, short selstatus, short flag, short hidden)
|
|
|
|
{
|
|
|
|
if(bp) {
|
|
|
|
if((bp->hide==0) || (hidden==1)) {
|
|
|
|
if(selstatus==1) {
|
|
|
|
bp->f1 |= flag;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp->f1 &= ~flag;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static short swap_selection_beztriple(BezTriple *bezt)
|
|
|
|
{
|
|
|
|
if(bezt->f2 & SELECT)
|
|
|
|
return select_beztriple(bezt, DESELECT, 1, VISIBLE);
|
|
|
|
else
|
|
|
|
return select_beztriple(bezt, SELECT, 1, VISIBLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static short swap_selection_bpoint(BPoint *bp)
|
|
|
|
{
|
|
|
|
if(bp->f1 & SELECT)
|
|
|
|
return select_bpoint(bp, DESELECT, 1, VISIBLE);
|
|
|
|
else
|
|
|
|
return select_bpoint(bp, SELECT, 1, VISIBLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
short isNurbsel(Nurb *nu)
|
|
|
|
{
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
a= nu->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
if( (bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT) ) return 1;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
while(a--) {
|
|
|
|
if( (bp->f1 & SELECT) ) return 1;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int isNurbsel_count(Nurb *nu)
|
|
|
|
{
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a, sel=0;
|
|
|
|
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
a= nu->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
if (BEZSELECTED_HIDDENHANDLES(bezt)) sel++;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
while(a--) {
|
|
|
|
if( (bp->f1 & SELECT) ) sel++;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sel;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************* PRINTS ********************* */
|
|
|
|
|
|
|
|
void printknots(Object *obedit)
|
|
|
|
{
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
int a, num;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if(isNurbsel(nu) && (nu->type & 7)==CU_NURBS) {
|
|
|
|
if(nu->knotsu) {
|
|
|
|
num= KNOTSU(nu);
|
|
|
|
for(a=0;a<num;a++) printf("knotu %d: %f\n", a, nu->knotsu[a]);
|
|
|
|
}
|
|
|
|
if(nu->knotsv) {
|
|
|
|
num= KNOTSV(nu);
|
|
|
|
for(a=0;a<num;a++) printf("knotv %d: %f\n", a, nu->knotsv[a]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ********************* LOAD and MAKE *************** */
|
|
|
|
|
|
|
|
/* load editNurb in object */
|
|
|
|
void load_editNurb(Object *obedit)
|
|
|
|
{
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
|
|
|
|
if(obedit==NULL) return;
|
|
|
|
|
|
|
|
if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
|
|
|
|
Curve *cu= obedit->data;
|
|
|
|
Nurb *nu, *newnu;
|
|
|
|
KeyBlock *actkey;
|
|
|
|
int totvert= count_curveverts(editnurb);
|
|
|
|
|
|
|
|
/* are there keys? */
|
|
|
|
actkey = ob_get_keyblock(obedit);
|
|
|
|
if(actkey) {
|
|
|
|
/* active key: the vertices */
|
|
|
|
|
|
|
|
if(totvert) {
|
|
|
|
if(actkey->data) MEM_freeN(actkey->data);
|
|
|
|
|
|
|
|
actkey->data= MEM_callocN(cu->key->elemsize*totvert, "actkey->data");
|
|
|
|
actkey->totelem= totvert;
|
|
|
|
|
|
|
|
curve_to_key(cu, actkey, editnurb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(cu->key && actkey!=cu->key->refkey) {
|
|
|
|
;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
freeNurblist(&(cu->nurb));
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
newnu= duplicateNurb(nu);
|
|
|
|
BLI_addtail(&(cu->nurb), newnu);
|
|
|
|
|
|
|
|
if((nu->type & 7)==CU_NURBS) {
|
|
|
|
clamp_nurb_order_u(nu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_actNurb(obedit, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make copy in cu->editnurb */
|
|
|
|
void make_editNurb(Object *obedit)
|
|
|
|
{
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu, *newnu;
|
|
|
|
KeyBlock *actkey;
|
|
|
|
|
|
|
|
if(obedit==NULL) return;
|
|
|
|
|
|
|
|
if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
|
|
|
|
Curve *cu= obedit->data;
|
|
|
|
|
|
|
|
if(editnurb)
|
|
|
|
freeNurblist(editnurb);
|
|
|
|
else
|
|
|
|
editnurb= cu->editnurb= MEM_callocN(sizeof(ListBase), "editnurb");
|
|
|
|
|
|
|
|
nu= cu->nurb.first;
|
|
|
|
cu->lastselbp= NULL; /* for select row */
|
|
|
|
|
|
|
|
while(nu) {
|
|
|
|
newnu= duplicateNurb(nu);
|
|
|
|
test2DNurb(newnu); // after join, or any other creation of curve
|
|
|
|
BLI_addtail(editnurb, newnu);
|
|
|
|
nu= nu->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
actkey = ob_get_keyblock(obedit);
|
|
|
|
if(actkey) {
|
2009-01-15 15:01:39 +00:00
|
|
|
// XXX strcpy(G.editModeTitleExtra, "(Key) ");
|
2009-01-14 12:26:45 +00:00
|
|
|
key_to_curve(actkey, cu, editnurb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_actNurb(obedit, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void remake_editNurb(Object *obedit)
|
|
|
|
{
|
|
|
|
|
|
|
|
if(okee("Reload original data")==0) return;
|
|
|
|
|
|
|
|
make_editNurb(obedit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_editNurb(Object *obedit)
|
|
|
|
{
|
|
|
|
Curve *cu= obedit->data;
|
|
|
|
|
|
|
|
if(cu->editnurb) {
|
|
|
|
freeNurblist(cu->editnurb);
|
|
|
|
MEM_freeN(cu->editnurb);
|
|
|
|
cu->editnurb= NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void separate_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
View3D *v3d= NULL; // XXX
|
|
|
|
Nurb *nu, *nu1;
|
|
|
|
Object *oldob;
|
|
|
|
Base *base, *oldbase;
|
|
|
|
Curve *cu;
|
|
|
|
ListBase editnurbo;
|
|
|
|
|
|
|
|
if( v3d==0 || (v3d->lay & obedit->lay)==0 ) return;
|
|
|
|
|
|
|
|
if(okee("Separate")==0) return;
|
|
|
|
|
|
|
|
waitcursor(1);
|
|
|
|
|
|
|
|
cu= obedit->data;
|
|
|
|
if(cu->key) {
|
|
|
|
error("Can't separate a curve with vertex keys");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we are going to trick everything as follows:
|
|
|
|
* 1. duplicate base: this is the new one, remember old pointer
|
|
|
|
* 2. set aside all NOT selected curves/nurbs
|
|
|
|
* 3. load_ebaseNurb(): this will be the new base
|
|
|
|
* 4. freelist and restore old nurbs
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* only edit-base selected */
|
|
|
|
base= FIRSTBASE;
|
|
|
|
while(base) {
|
|
|
|
if(base->lay & v3d->lay) {
|
|
|
|
if(base->object==obedit) base->flag |= 1;
|
|
|
|
else base->flag &= ~1;
|
|
|
|
}
|
|
|
|
base= base->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set aside: everything that is not selected */
|
|
|
|
editnurbo.first= editnurbo.last= 0;
|
|
|
|
nu= editnurb->first;
|
|
|
|
while(nu) {
|
|
|
|
nu1= nu->next;
|
|
|
|
if(isNurbsel(nu)==0) {
|
|
|
|
BLI_remlink(editnurb, nu);
|
|
|
|
BLI_addtail(&editnurbo, nu);
|
|
|
|
}
|
|
|
|
nu= nu1;
|
|
|
|
}
|
|
|
|
|
|
|
|
oldob= obedit;
|
|
|
|
oldbase= BASACT;
|
|
|
|
|
|
|
|
adduplicate(1, 0); /* no transform and zero so do get a linked dupli */
|
|
|
|
|
|
|
|
obedit= BASACT->object; /* basact is set in adduplicate() */
|
|
|
|
|
|
|
|
obedit->data= copy_curve(cu);
|
|
|
|
/* because new curve is a copy: reduce user count */
|
|
|
|
cu->id.us--;
|
|
|
|
|
|
|
|
load_editNurb(obedit);
|
|
|
|
|
|
|
|
BASACT->flag &= ~SELECT;
|
|
|
|
|
|
|
|
if(editnurb->first) freeNurblist(editnurb);
|
|
|
|
|
|
|
|
*editnurb= editnurbo;
|
|
|
|
|
|
|
|
obedit= 0; /* displists behave different in edit mode */
|
|
|
|
DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA); /* this is the separated one */
|
|
|
|
DAG_object_flush_update(scene, oldob, OB_RECALC_DATA); /* this is the original one */
|
|
|
|
|
|
|
|
obedit= oldob;
|
|
|
|
BASACT= oldbase;
|
|
|
|
BASACT->flag |= SELECT;
|
|
|
|
|
|
|
|
waitcursor(0);
|
|
|
|
|
|
|
|
set_actNurb(obedit, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************* FLAGS ********************* */
|
|
|
|
|
|
|
|
|
|
|
|
short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
|
|
|
|
{
|
|
|
|
/* return u!=-1: 1 row in u-direction selected. U has value between 0-pntsv
|
|
|
|
* return v!=-1: 1 collumn in v-direction selected. V has value between 0-pntsu
|
|
|
|
*/
|
|
|
|
BPoint *bp;
|
|
|
|
int a, b, sel;
|
|
|
|
|
|
|
|
*u= *v= -1;
|
|
|
|
|
|
|
|
bp= nu->bp;
|
|
|
|
for(b=0; b<nu->pntsv; b++) {
|
|
|
|
sel= 0;
|
|
|
|
for(a=0; a<nu->pntsu; a++, bp++) {
|
|
|
|
if(bp->f1 & flag) sel++;
|
|
|
|
}
|
|
|
|
if(sel==nu->pntsu) {
|
|
|
|
if(*u== -1) *u= b;
|
|
|
|
else return 0;
|
|
|
|
}
|
|
|
|
else if(sel>1) return 0; /* because sel==1 is still ok */
|
|
|
|
}
|
|
|
|
|
|
|
|
for(a=0; a<nu->pntsu; a++) {
|
|
|
|
sel= 0;
|
|
|
|
bp= nu->bp+a;
|
|
|
|
for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
|
|
|
|
if(bp->f1 & flag) sel++;
|
|
|
|
}
|
|
|
|
if(sel==nu->pntsv) {
|
|
|
|
if(*v== -1) *v= a;
|
|
|
|
else return 0;
|
|
|
|
}
|
|
|
|
else if(sel>1) return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(*u==-1 && *v>-1) return 1;
|
|
|
|
if(*v==-1 && *u>-1) return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setflagsNurb(ListBase *editnurb, short flag)
|
|
|
|
{
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if( (nu->type & 7)==CU_BEZIER) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
while(a--) {
|
|
|
|
bezt->f1= bezt->f2= bezt->f3= flag;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
bp->f1= flag;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void rotateflagNurb(ListBase *editnurb, short flag, float *cent, float rotmat[][3])
|
|
|
|
{
|
|
|
|
/* all verts with (flag & 'flag') rotate */
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if((nu->type & 7)==CU_NURBS) {
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
|
|
|
|
while(a--) {
|
|
|
|
if(bp->f1 & flag) {
|
|
|
|
bp->vec[0]-=cent[0];
|
|
|
|
bp->vec[1]-=cent[1];
|
|
|
|
bp->vec[2]-=cent[2];
|
|
|
|
Mat3MulVecfl(rotmat, bp->vec);
|
|
|
|
bp->vec[0]+=cent[0];
|
|
|
|
bp->vec[1]+=cent[1];
|
|
|
|
bp->vec[2]+=cent[2];
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void translateflagNurb(ListBase *editnurb, short flag, float *vec)
|
|
|
|
{
|
|
|
|
/* all verts with ('flag' & flag) translate */
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if( (nu->type & 7)==CU_BEZIER) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
while(a--) {
|
|
|
|
if(bezt->f1 & flag) VecAddf(bezt->vec[0], bezt->vec[0], vec);
|
|
|
|
if(bezt->f2 & flag) VecAddf(bezt->vec[1], bezt->vec[1], vec);
|
|
|
|
if(bezt->f3 & flag) VecAddf(bezt->vec[2], bezt->vec[2], vec);
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
if(bp->f1 & flag) VecAddf(bp->vec, bp->vec, vec);
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
test2DNurb(nu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void weightflagNurb(ListBase *editnurb, short flag, float w, int mode) /* mode==0: replace, mode==1: multiply */
|
|
|
|
{
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if((nu->type & 7)==CU_NURBS) {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
if(bp->f1 & flag) {
|
|
|
|
if(mode==1) bp->vec[3]*= w;
|
|
|
|
else bp->vec[3]= w;
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deleteflagNurb(Scene *scene, short flag)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
Curve *cu= obedit->data;
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu, *next;
|
|
|
|
BPoint *bp, *bpn, *newbp;
|
|
|
|
int a, b, newu, newv, sel;
|
|
|
|
|
|
|
|
if(obedit && obedit->type==OB_SURF);
|
|
|
|
else return;
|
|
|
|
|
|
|
|
cu->lastselbp= NULL;
|
|
|
|
|
|
|
|
nu= editnurb->first;
|
|
|
|
while(nu) {
|
|
|
|
next= nu->next;
|
|
|
|
|
|
|
|
/* is entire nurb selected */
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
while(a) {
|
|
|
|
a--;
|
|
|
|
if(bp->f1 & flag);
|
|
|
|
else break;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
if(a==0) {
|
|
|
|
BLI_remlink(editnurb, nu);
|
|
|
|
freeNurb(nu); nu=NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* is nurb in U direction selected */
|
|
|
|
newv= nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
for(b=0; b<nu->pntsv; b++) {
|
|
|
|
sel= 0;
|
|
|
|
for(a=0; a<nu->pntsu; a++, bp++) {
|
|
|
|
if(bp->f1 & flag) sel++;
|
|
|
|
}
|
|
|
|
if(sel==nu->pntsu) {
|
|
|
|
newv--;
|
|
|
|
}
|
|
|
|
else if(sel>=1) {
|
|
|
|
/* don't delete */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(newv!=nu->pntsv && b==nu->pntsv) {
|
|
|
|
/* delete */
|
|
|
|
bp= nu->bp;
|
|
|
|
bpn = newbp =
|
|
|
|
(BPoint*) MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
|
|
|
|
for(b=0; b<nu->pntsv; b++) {
|
|
|
|
if((bp->f1 & flag)==0) {
|
|
|
|
memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
|
|
|
|
bpn+= nu->pntsu;
|
|
|
|
}
|
|
|
|
bp+= nu->pntsu;
|
|
|
|
}
|
|
|
|
nu->pntsv= newv;
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= newbp;
|
|
|
|
clamp_nurb_order_v(nu);
|
|
|
|
|
|
|
|
makeknots(nu, 2, nu->flagv>>1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* is the nurb in V direction selected */
|
|
|
|
newu= nu->pntsu;
|
|
|
|
for(a=0; a<nu->pntsu; a++) {
|
|
|
|
bp= nu->bp+a;
|
|
|
|
sel= 0;
|
|
|
|
for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
|
|
|
|
if(bp->f1 & flag) sel++;
|
|
|
|
}
|
|
|
|
if(sel==nu->pntsv) {
|
|
|
|
newu--;
|
|
|
|
}
|
|
|
|
else if(sel>=1) {
|
|
|
|
/* don't delete */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(newu!=nu->pntsu && a==nu->pntsu) {
|
|
|
|
/* delete */
|
|
|
|
bp= nu->bp;
|
|
|
|
bpn = newbp =
|
|
|
|
(BPoint*) MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
|
|
|
|
for(b=0; b<nu->pntsv; b++) {
|
|
|
|
for(a=0; a<nu->pntsu; a++, bp++) {
|
|
|
|
if((bp->f1 & flag)==0) {
|
|
|
|
*bpn= *bp;
|
|
|
|
bpn++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= newbp;
|
|
|
|
if(newu==1 && nu->pntsv>1) { /* make a U spline */
|
|
|
|
nu->pntsu= nu->pntsv;
|
|
|
|
nu->pntsv= 1;
|
|
|
|
SWAP(short, nu->orderu, nu->orderv);
|
|
|
|
clamp_nurb_order_u(nu);
|
|
|
|
if(nu->knotsv) MEM_freeN(nu->knotsv);
|
|
|
|
nu->knotsv= NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nu->pntsu= newu;
|
|
|
|
clamp_nurb_order_u(nu);
|
|
|
|
}
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nu= next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* only for OB_SURF */
|
|
|
|
short extrudeflagNurb(ListBase *editnurb, int flag)
|
|
|
|
{
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp, *bpn, *newbp;
|
|
|
|
int ok= 0, a, u, v, len;
|
|
|
|
|
|
|
|
nu= editnurb->first;
|
|
|
|
while(nu) {
|
|
|
|
|
|
|
|
if(nu->pntsv==1) {
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu;
|
|
|
|
while(a) {
|
|
|
|
if(bp->f1 & flag);
|
|
|
|
else break;
|
|
|
|
bp++;
|
|
|
|
a--;
|
|
|
|
}
|
|
|
|
if(a==0) {
|
|
|
|
ok= 1;
|
|
|
|
newbp =
|
|
|
|
(BPoint*)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
|
|
|
|
memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) );
|
|
|
|
bp= newbp+ nu->pntsu;
|
|
|
|
memcpy(bp, nu->bp, nu->pntsu*sizeof(BPoint) );
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= newbp;
|
|
|
|
a= nu->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
select_bpoint(bp, SELECT, flag, HIDDEN);
|
|
|
|
select_bpoint(newbp, DESELECT, flag, HIDDEN);
|
|
|
|
bp++;
|
|
|
|
newbp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
nu->pntsv= 2;
|
|
|
|
nu->orderv= 2;
|
|
|
|
makeknots(nu, 2, nu->flagv>>1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* which row or collumn is selected */
|
|
|
|
|
|
|
|
if( isNurbselUV(nu, &u, &v, flag) ) {
|
|
|
|
|
|
|
|
/* deselect all */
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
while(a--) {
|
|
|
|
select_bpoint(bp, DESELECT, flag, HIDDEN);
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(u==0 || u== nu->pntsv-1) { /* row in u-direction selected */
|
|
|
|
ok= 1;
|
|
|
|
newbp =
|
|
|
|
(BPoint*) MEM_mallocN(nu->pntsu*(nu->pntsv + 1)
|
|
|
|
* sizeof(BPoint), "extrudeNurb1");
|
|
|
|
if(u==0) {
|
|
|
|
len= nu->pntsv*nu->pntsu;
|
|
|
|
memcpy(newbp+nu->pntsu, nu->bp, len*sizeof(BPoint) );
|
|
|
|
memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) );
|
|
|
|
bp= newbp;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
len= nu->pntsv*nu->pntsu;
|
|
|
|
memcpy(newbp, nu->bp, len*sizeof(BPoint) );
|
|
|
|
memcpy(newbp+len, nu->bp+len-nu->pntsu, nu->pntsu*sizeof(BPoint) );
|
|
|
|
bp= newbp+len;
|
|
|
|
}
|
|
|
|
|
|
|
|
a= nu->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
select_bpoint(bp, SELECT, flag, HIDDEN);
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= newbp;
|
|
|
|
nu->pntsv++;
|
|
|
|
makeknots(nu, 2, nu->flagv>>1);
|
|
|
|
}
|
|
|
|
else if(v==0 || v== nu->pntsu-1) { /* collumn in v-direction selected */
|
|
|
|
ok= 1;
|
|
|
|
bpn = newbp =
|
|
|
|
(BPoint*) MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
|
|
|
|
bp= nu->bp;
|
|
|
|
|
|
|
|
for(a=0; a<nu->pntsv; a++) {
|
|
|
|
if(v==0) {
|
|
|
|
*bpn= *bp;
|
|
|
|
bpn->f1 |= flag;
|
|
|
|
bpn++;
|
|
|
|
}
|
|
|
|
memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
|
|
|
|
bp+= nu->pntsu;
|
|
|
|
bpn+= nu->pntsu;
|
|
|
|
if(v== nu->pntsu-1) {
|
|
|
|
*bpn= *(bp-1);
|
|
|
|
bpn->f1 |= flag;
|
|
|
|
bpn++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= newbp;
|
|
|
|
nu->pntsu++;
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nu= nu->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
void adduplicateflagNurb(Scene *scene, short flag)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu, *newnu;
|
|
|
|
BezTriple *bezt, *bezt1;
|
|
|
|
BPoint *bp, *bp1;
|
|
|
|
int a, b, starta, enda, newu, newv;
|
|
|
|
char *usel;
|
|
|
|
|
|
|
|
nu= editnurb->last;
|
|
|
|
while(nu) {
|
|
|
|
if( (nu->type & 7)==CU_BEZIER) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
for(a=0; a<nu->pntsu; a++) {
|
|
|
|
enda= -1;
|
|
|
|
starta= a;
|
|
|
|
while( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) {
|
|
|
|
select_beztriple(bezt, DESELECT, flag, HIDDEN);
|
|
|
|
enda=a;
|
|
|
|
if(a>=nu->pntsu-1) break;
|
|
|
|
a++;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
if(enda>=starta) {
|
|
|
|
newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN");
|
|
|
|
memcpy(newnu, nu, sizeof(Nurb));
|
|
|
|
BLI_addtail(editnurb, newnu);
|
|
|
|
set_actNurb(obedit, newnu);
|
|
|
|
newnu->pntsu= enda-starta+1;
|
|
|
|
newnu->bezt=
|
|
|
|
(BezTriple*)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN");
|
|
|
|
memcpy(newnu->bezt, nu->bezt+starta, newnu->pntsu*sizeof(BezTriple));
|
|
|
|
|
|
|
|
b= newnu->pntsu;
|
|
|
|
bezt1= newnu->bezt;
|
|
|
|
while(b--) {
|
|
|
|
select_beztriple(bezt1, SELECT, flag, HIDDEN);
|
|
|
|
bezt1++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(nu->flagu & CU_CYCLIC) {
|
|
|
|
if(starta!=0 || enda!=nu->pntsu-1) {
|
|
|
|
newnu->flagu &= ~CU_CYCLIC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nu->pntsv==1) { /* because UV Nurb has a different method for dupli */
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0; a<nu->pntsu; a++) {
|
|
|
|
enda= -1;
|
|
|
|
starta= a;
|
|
|
|
while(bp->f1 & flag) {
|
|
|
|
select_bpoint(bp, DESELECT, flag, HIDDEN);
|
|
|
|
enda= a;
|
|
|
|
if(a>=nu->pntsu-1) break;
|
|
|
|
a++;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
if(enda>=starta) {
|
|
|
|
newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN3");
|
|
|
|
memcpy(newnu, nu, sizeof(Nurb));
|
|
|
|
set_actNurb(obedit, newnu);
|
|
|
|
BLI_addtail(editnurb, newnu);
|
|
|
|
newnu->pntsu= enda-starta+1;
|
|
|
|
newnu->bp = (BPoint*)MEM_mallocN((enda-starta+1) * sizeof(BPoint), "adduplicateN4");
|
|
|
|
memcpy(newnu->bp, nu->bp+starta, newnu->pntsu*sizeof(BPoint));
|
|
|
|
|
|
|
|
b= newnu->pntsu;
|
|
|
|
bp1= newnu->bp;
|
|
|
|
while(b--) {
|
|
|
|
select_bpoint(bp1, SELECT, flag, HIDDEN);
|
|
|
|
bp1++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(nu->flagu & CU_CYCLIC) {
|
|
|
|
if(starta!=0 || enda!=nu->pntsu-1) {
|
|
|
|
newnu->flagu &= ~CU_CYCLIC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* knots */
|
|
|
|
newnu->knotsu= NULL;
|
|
|
|
makeknots(newnu, 1, newnu->flagu>>1);
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* a rectangular area in nurb has to be selected */
|
|
|
|
if(isNurbsel(nu)) {
|
|
|
|
usel= MEM_callocN(nu->pntsu, "adduplicateN4");
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0; a<nu->pntsv; a++) {
|
|
|
|
for(b=0; b<nu->pntsu; b++, bp++) {
|
|
|
|
if(bp->f1 & flag) usel[b]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
newu= 0;
|
|
|
|
newv= 0;
|
|
|
|
for(a=0; a<nu->pntsu; a++) {
|
|
|
|
if(usel[a]) {
|
|
|
|
if(newv==0 || usel[a]==newv) {
|
|
|
|
newv= usel[a];
|
|
|
|
newu++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
newv= 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(newu==0 || newv==0) {
|
|
|
|
printf("Can't duplicate Nurb\n");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
if(newu==1) SWAP(short, newu, newv);
|
|
|
|
|
|
|
|
newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN5");
|
|
|
|
memcpy(newnu, nu, sizeof(Nurb));
|
|
|
|
BLI_addtail(editnurb, newnu);
|
|
|
|
set_actNurb(obedit, newnu);
|
|
|
|
newnu->pntsu= newu;
|
|
|
|
newnu->pntsv= newv;
|
|
|
|
newnu->bp =
|
|
|
|
(BPoint*)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6");
|
|
|
|
clamp_nurb_order_u(newnu);
|
|
|
|
clamp_nurb_order_v(newnu);
|
|
|
|
|
|
|
|
newnu->knotsu= newnu->knotsv= NULL;
|
|
|
|
|
|
|
|
bp= newnu->bp;
|
|
|
|
bp1= nu->bp;
|
|
|
|
for(a=0; a<nu->pntsv; a++) {
|
|
|
|
for(b=0; b<nu->pntsu; b++, bp1++) {
|
|
|
|
if(bp1->f1 & flag) {
|
|
|
|
memcpy(bp, bp1, sizeof(BPoint));
|
|
|
|
select_bpoint(bp1, DESELECT, flag, HIDDEN);
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (check_valid_nurb_u(newnu)) {
|
|
|
|
if(nu->pntsu==newnu->pntsu && nu->knotsu) {
|
|
|
|
newnu->knotsu= MEM_dupallocN( nu->knotsu );
|
|
|
|
} else {
|
|
|
|
makeknots(newnu, 1, newnu->flagu>>1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (check_valid_nurb_v(newnu)) {
|
|
|
|
if(nu->pntsv==newnu->pntsv && nu->knotsv) {
|
|
|
|
newnu->knotsv= MEM_dupallocN( nu->knotsv );
|
|
|
|
} else {
|
|
|
|
makeknots(newnu, 2, newnu->flagv>>1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MEM_freeN(usel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nu= nu->prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* actnu changed */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void switchdirectionNurb2(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
View3D *v3d= NULL; // XXX
|
|
|
|
Nurb *nu;
|
|
|
|
|
|
|
|
if(v3d==0 || !(obedit->lay & v3d->lay))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if( isNurbsel(nu) ) switchdirectionNurb(nu);
|
|
|
|
}
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
|
|
|
|
BIF_undo_push("Switch direction");
|
|
|
|
}
|
|
|
|
|
|
|
|
void switchdirection_knots(float *base, int tot)
|
|
|
|
{
|
|
|
|
float *fp1, *fp2, *tempf;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
if(base==NULL || tot==0) return;
|
|
|
|
|
|
|
|
/* reverse knots */
|
|
|
|
a= tot;
|
|
|
|
fp1= base;
|
|
|
|
fp2= fp1+(a-1);
|
|
|
|
a/= 2;
|
|
|
|
while(fp1!=fp2 && a>0) {
|
|
|
|
SWAP(float, *fp1, *fp2);
|
|
|
|
a--;
|
|
|
|
fp1++;
|
|
|
|
fp2--;
|
|
|
|
}
|
|
|
|
/* and make in increasing order again */
|
|
|
|
a= tot;
|
|
|
|
fp1= base;
|
|
|
|
fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect");
|
|
|
|
while(a--) {
|
|
|
|
fp2[0]= fabs(fp1[1]-fp1[0]);
|
|
|
|
fp1++;
|
|
|
|
fp2++;
|
|
|
|
}
|
|
|
|
|
|
|
|
a= tot-1;
|
|
|
|
fp1= base;
|
|
|
|
fp2= tempf;
|
|
|
|
fp1[0]= 0.0;
|
|
|
|
fp1++;
|
|
|
|
while(a--) {
|
|
|
|
fp1[0]= fp1[-1]+fp2[0];
|
|
|
|
fp1++;
|
|
|
|
fp2++;
|
|
|
|
}
|
|
|
|
MEM_freeN(tempf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setweightNurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
static float weight= 1.0f;
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
if(fbutton(&weight, 0.0f, 1.0f, 10, 10, "Set Weight")) {
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if(nu->bezt) {
|
|
|
|
for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
|
|
|
|
if(bezt->f2 & SELECT)
|
|
|
|
bezt->weight= weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nu->bp) {
|
|
|
|
for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
|
|
|
|
if(bp->f1 & SELECT)
|
|
|
|
bp->weight= weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BIF_undo_push("Set Curve Weight");
|
|
|
|
DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setradiusNurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
static float radius= 1.0f;
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
if(fbutton(&radius, 0.0001f, 10.0f, 10, 10, "Set Radius")) {
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if(nu->bezt) {
|
|
|
|
for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
|
|
|
|
if(bezt->f2 & SELECT)
|
|
|
|
bezt->radius= radius;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nu->bp) {
|
|
|
|
for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
|
|
|
|
if(bp->f1 & SELECT)
|
|
|
|
bp->radius= radius;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BIF_undo_push("Set Curve Radius");
|
|
|
|
DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
void smoothNurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt, *beztOrig;
|
|
|
|
BPoint *bp, *bpOrig;
|
|
|
|
int a, i, change = 0;
|
|
|
|
|
|
|
|
/* floats for smoothing */
|
|
|
|
float val, newval, offset;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if(nu->bezt) {
|
|
|
|
change = 0;
|
|
|
|
beztOrig = MEM_dupallocN( nu->bezt );
|
|
|
|
for(bezt=nu->bezt+1, a=1; a<nu->pntsu-1; a++, bezt++) {
|
|
|
|
if(bezt->f2 & SELECT) {
|
|
|
|
for(i=0; i<3; i++) {
|
|
|
|
val = bezt->vec[1][i];
|
|
|
|
newval = ((beztOrig+(a-1))->vec[1][i] * 0.5) + ((beztOrig+(a+1))->vec[1][i] * 0.5);
|
|
|
|
offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
|
|
|
|
/* offset handles */
|
|
|
|
bezt->vec[1][i] += offset;
|
|
|
|
bezt->vec[0][i] += offset;
|
|
|
|
bezt->vec[2][i] += offset;
|
|
|
|
}
|
|
|
|
change = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MEM_freeN(beztOrig);
|
|
|
|
if (change)
|
|
|
|
calchandlesNurb(nu);
|
|
|
|
} else if (nu->bp) {
|
|
|
|
bpOrig = MEM_dupallocN( nu->bp );
|
|
|
|
/* Same as above, keep these the same! */
|
|
|
|
for(bp=nu->bp+1, a=1; a<nu->pntsu-1; a++, bp++) {
|
|
|
|
if(bp->f1 & SELECT) {
|
|
|
|
for(i=0; i<3; i++) {
|
|
|
|
val = bp->vec[i];
|
|
|
|
newval = ((bpOrig+(a-1))->vec[i] * 0.5) + ((bpOrig+(a+1))->vec[i] * 0.5);
|
|
|
|
offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
|
|
|
|
|
|
|
|
bp->vec[i] += offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MEM_freeN(bpOrig);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BIF_undo_push("Smooth Curve");
|
|
|
|
DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO, make smoothing distance based */
|
|
|
|
void smoothradiusNurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
/* use for smoothing */
|
|
|
|
int last_sel;
|
|
|
|
int start_sel, end_sel; /* selection indicies, inclusive */
|
|
|
|
float start_rad, end_rad, fac, range;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if(nu->bezt) {
|
|
|
|
|
|
|
|
for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
|
|
|
|
/* loop over selection segments of a curve, smooth each */
|
|
|
|
|
|
|
|
/* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
|
|
|
|
start_sel = end_sel = -1;
|
|
|
|
for(bezt=nu->bezt+last_sel, a=last_sel; a<nu->pntsu; a++, bezt++) {
|
|
|
|
if(bezt->f2 & SELECT) {
|
|
|
|
start_sel = a;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* incase there are no other selected verts */
|
|
|
|
end_sel = start_sel;
|
|
|
|
for(bezt=nu->bezt+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bezt++) {
|
|
|
|
if((bezt->f2 & SELECT)==0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
end_sel = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (start_sel == -1) {
|
|
|
|
last_sel = nu->pntsu; /* next... */
|
|
|
|
} else {
|
|
|
|
last_sel = end_sel; /* before we modify it */
|
|
|
|
|
|
|
|
/* now blend between start and end sel */
|
|
|
|
start_rad = end_rad = -1.0;
|
|
|
|
|
|
|
|
if (start_sel == end_sel) {
|
|
|
|
/* simple, only 1 point selected */
|
|
|
|
if (start_sel>0) start_rad = (nu->bezt+start_sel-1)->radius;
|
|
|
|
if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bezt+start_sel+1)->radius;
|
|
|
|
|
|
|
|
if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bezt+start_sel)->radius = (start_rad + end_rad)/2;
|
|
|
|
else if (start_rad >= 0.0) (nu->bezt+start_sel)->radius = start_rad;
|
|
|
|
else if (end_rad >= 0.0) (nu->bezt+start_sel)->radius = end_rad;
|
|
|
|
} else {
|
|
|
|
/* if endpoints selected, then use them */
|
|
|
|
if (start_sel==0) {
|
|
|
|
start_rad = (nu->bezt+start_sel)->radius;
|
|
|
|
start_sel++; /* we dont want to edit the selected endpoint */
|
|
|
|
} else {
|
|
|
|
start_rad = (nu->bezt+start_sel-1)->radius;
|
|
|
|
}
|
|
|
|
if (end_sel==nu->pntsu-1) {
|
|
|
|
end_rad = (nu->bezt+end_sel)->radius;
|
|
|
|
end_sel--; /* we dont want to edit the selected endpoint */
|
|
|
|
} else {
|
|
|
|
end_rad = (nu->bezt+end_sel+1)->radius;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now Blend between the points */
|
|
|
|
range = (float)(end_sel - start_sel) + 2.0f;
|
|
|
|
for(bezt=nu->bezt+start_sel, a=start_sel; a<=end_sel; a++, bezt++) {
|
|
|
|
fac = (float)(1+a-start_sel) / range;
|
|
|
|
bezt->radius = start_rad*(1.0-fac) + end_rad*fac;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (nu->bp) {
|
|
|
|
/* Same as above, keep these the same! */
|
|
|
|
for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
|
|
|
|
/* loop over selection segments of a curve, smooth each */
|
|
|
|
|
|
|
|
/* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
|
|
|
|
start_sel = end_sel = -1;
|
|
|
|
for(bp=nu->bp+last_sel, a=last_sel; a<nu->pntsu; a++, bp++) {
|
|
|
|
if(bp->f1 & SELECT) {
|
|
|
|
start_sel = a;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* incase there are no other selected verts */
|
|
|
|
end_sel = start_sel;
|
|
|
|
for(bp=nu->bp+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bp++) {
|
|
|
|
if((bp->f1 & SELECT)==0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
end_sel = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (start_sel == -1) {
|
|
|
|
last_sel = nu->pntsu; /* next... */
|
|
|
|
} else {
|
|
|
|
last_sel = end_sel; /* before we modify it */
|
|
|
|
|
|
|
|
/* now blend between start and end sel */
|
|
|
|
start_rad = end_rad = -1.0;
|
|
|
|
|
|
|
|
if (start_sel == end_sel) {
|
|
|
|
/* simple, only 1 point selected */
|
|
|
|
if (start_sel>0) start_rad = (nu->bp+start_sel-1)->radius;
|
|
|
|
if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bp+start_sel+1)->radius;
|
|
|
|
|
|
|
|
if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bp+start_sel)->radius = (start_rad + end_rad)/2;
|
|
|
|
else if (start_rad >= 0.0) (nu->bp+start_sel)->radius = start_rad;
|
|
|
|
else if (end_rad >= 0.0) (nu->bp+start_sel)->radius = end_rad;
|
|
|
|
} else {
|
|
|
|
/* if endpoints selected, then use them */
|
|
|
|
if (start_sel==0) {
|
|
|
|
start_rad = (nu->bp+start_sel)->radius;
|
|
|
|
start_sel++; /* we dont want to edit the selected endpoint */
|
|
|
|
} else {
|
|
|
|
start_rad = (nu->bp+start_sel-1)->radius;
|
|
|
|
}
|
|
|
|
if (end_sel==nu->pntsu-1) {
|
|
|
|
end_rad = (nu->bp+end_sel)->radius;
|
|
|
|
end_sel--; /* we dont want to edit the selected endpoint */
|
|
|
|
} else {
|
|
|
|
end_rad = (nu->bp+end_sel+1)->radius;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now Blend between the points */
|
|
|
|
range = (float)(end_sel - start_sel) + 2.0f;
|
|
|
|
for(bp=nu->bp+start_sel, a=start_sel; a<=end_sel; a++, bp++) {
|
|
|
|
fac = (float)(1+a-start_sel) / range;
|
|
|
|
bp->radius = start_rad*(1.0-fac) + end_rad*fac;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BIF_undo_push("Smooth Curve Radius");
|
|
|
|
DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* **************** EDIT ************************ */
|
|
|
|
|
|
|
|
/* next == 1 -> select next */
|
|
|
|
/* next == -1 -> select previous */
|
|
|
|
/* cont == 1 -> select continuously */
|
|
|
|
/* selstatus, inverts behaviour */
|
|
|
|
static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus)
|
|
|
|
{
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
short lastsel= 0, sel=0;
|
|
|
|
|
|
|
|
if(next==0) return;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
lastsel=0;
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
if(next < 0) bezt= (nu->bezt + (a-1));
|
|
|
|
while(a--) {
|
|
|
|
if(a-abs(next) < 0) break;
|
|
|
|
sel= 0;
|
|
|
|
if((lastsel==0) && (bezt->hide==0) && ((bezt->f2 & SELECT) || (selstatus==0))) {
|
|
|
|
bezt+=next;
|
|
|
|
if(!(bezt->f2 & SELECT) || (selstatus==0)) {
|
|
|
|
sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
|
|
|
|
if((sel==1) && (cont==0)) lastsel= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bezt+=next;
|
|
|
|
lastsel= 0;
|
|
|
|
}
|
|
|
|
/* move around in zigzag way so that we go through each */
|
|
|
|
bezt-=(next-next/abs(next));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
if(next < 0) bp= (nu->bp + (a-1));
|
|
|
|
while(a--) {
|
|
|
|
if(a-abs(next) < 0) break;
|
|
|
|
sel=0;
|
|
|
|
if((lastsel==0) && (bp->hide==0) && ((bp->f1 & SELECT) || (selstatus==0))) {
|
|
|
|
bp+=next;
|
|
|
|
if(!(bp->f1 & SELECT) || (selstatus==0)) {
|
|
|
|
sel= select_bpoint(bp, selstatus, 1, VISIBLE);
|
|
|
|
if((sel==1) && (cont==0)) lastsel= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp+=next;
|
|
|
|
lastsel= 0;
|
|
|
|
}
|
|
|
|
/* move around in zigzag way so that we go through each */
|
|
|
|
bp-=(next-next/abs(next));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static short nurb_has_selected_cps(ListBase *editnurb)
|
|
|
|
{
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
while(a--) {
|
|
|
|
if(bezt->hide==0) {
|
|
|
|
if((bezt->f1 & SELECT)
|
|
|
|
|| (bezt->f2 & SELECT)
|
|
|
|
|| (bezt->f3 & SELECT)) return 1;
|
|
|
|
}
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
if((bp->hide==0) && (bp->f1 & SELECT)) return 1;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* (de)selects first or last of visible part of each Nurb depending on selFirst */
|
|
|
|
/* selFirst: defines the end of which to select */
|
|
|
|
/* doswap: defines if selection state of each first/last control point is swapped */
|
|
|
|
/* selstatus: selection status in case doswap is false */
|
|
|
|
void selectend_nurb(Scene *scene, short selfirst, short doswap, short selstatus)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp;
|
|
|
|
BezTriple *bezt;
|
|
|
|
int a;
|
|
|
|
short sel;
|
|
|
|
|
|
|
|
if(obedit==0) return;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
sel= 0;
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
|
|
|
|
/* which point? */
|
|
|
|
if(selfirst==0) { /* select last */
|
|
|
|
bezt= (nu->bezt + (a-1));
|
|
|
|
}
|
|
|
|
else { /* select first */
|
|
|
|
bezt= nu->bezt;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(a--) {
|
|
|
|
if(doswap) sel= swap_selection_beztriple(bezt);
|
|
|
|
else sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
|
|
|
|
|
|
|
|
if(sel==1) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
|
|
|
|
/* which point? */
|
|
|
|
if(selfirst==0) { /* select last */
|
|
|
|
bp= (nu->bp + (a-1));
|
|
|
|
}
|
|
|
|
else{ /* select first */
|
|
|
|
bp= nu->bp;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(a--) {
|
|
|
|
if (bp->hide == 0) {
|
|
|
|
if(doswap) sel= swap_selection_bpoint(bp);
|
|
|
|
else sel= select_bpoint(bp, selstatus, 1, VISIBLE);
|
|
|
|
|
|
|
|
if(sel==1) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("Select/Deselect End");
|
|
|
|
}
|
|
|
|
|
|
|
|
void deselectall_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
View3D *v3d= NULL; // XXX
|
|
|
|
|
|
|
|
if(!v3d || !(obedit->lay & v3d->lay))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(nurb_has_selected_cps(editnurb)) { /* deselect all */
|
|
|
|
selectend_nurb(scene, FIRST, 0, DESELECT); /* set first control points as unselected */
|
|
|
|
select_adjacent_cp(editnurb, 1, 1, DESELECT); /* cascade selection */
|
|
|
|
}
|
|
|
|
else { /* select all */
|
|
|
|
selectend_nurb(scene, FIRST, 0, SELECT); /* set first control points as selected */
|
|
|
|
select_adjacent_cp(editnurb, 1, 1, SELECT); /* cascade selection */
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("Deselect all");
|
|
|
|
}
|
|
|
|
|
|
|
|
void hideNurb(Scene *scene, int swap)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp;
|
|
|
|
BezTriple *bezt;
|
|
|
|
int a, sel;
|
|
|
|
|
|
|
|
if(obedit==0) return;
|
|
|
|
|
|
|
|
BIF_undo_push("Hide");
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
a= nu->pntsu;
|
|
|
|
sel= 0;
|
|
|
|
while(a--) {
|
|
|
|
if(BEZSELECTED_HIDDENHANDLES(bezt)) {
|
|
|
|
select_beztriple(bezt, DESELECT, 1, HIDDEN);
|
|
|
|
bezt->hide= 1;
|
|
|
|
}
|
|
|
|
if(bezt->hide) sel++;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
if(sel==nu->pntsu) nu->hide= 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
sel= 0;
|
|
|
|
while(a--) {
|
|
|
|
if(swap==0 && (bp->f1 & SELECT)) {
|
|
|
|
select_bpoint(bp, DESELECT, 1, HIDDEN);
|
|
|
|
bp->hide= 1;
|
|
|
|
}
|
|
|
|
else if(swap && (bp->f1 & SELECT)==0) {
|
|
|
|
select_bpoint(bp, DESELECT, 1, HIDDEN);
|
|
|
|
bp->hide= 1;
|
|
|
|
}
|
|
|
|
if(bp->hide) sel++;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
if(sel==nu->pntsu*nu->pntsv) nu->hide= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
void revealNurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp;
|
|
|
|
BezTriple *bezt;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
if(obedit==0) return;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
nu->hide= 0;
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
a= nu->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
if(bezt->hide) {
|
|
|
|
select_beztriple(bezt, SELECT, 1, HIDDEN);
|
|
|
|
bezt->hide= 0;
|
|
|
|
}
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
while(a--) {
|
|
|
|
if(bp->hide) {
|
|
|
|
select_bpoint(bp, SELECT, 1, HIDDEN);
|
|
|
|
bp->hide= 0;
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
BIF_undo_push("Reveal");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void selectswapNurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp;
|
|
|
|
BezTriple *bezt;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
if(obedit==0) return;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
a= nu->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
if(bezt->hide==0) {
|
|
|
|
bezt->f2 ^= SELECT; /* always do the center point */
|
|
|
|
if ((G.f & G_HIDDENHANDLES)==0) {
|
|
|
|
bezt->f1 ^= SELECT;
|
|
|
|
bezt->f3 ^= SELECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
while(a--) {
|
|
|
|
swap_selection_bpoint(bp);
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("Select swap");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Divide the line segments associated with the currently selected
|
|
|
|
* curve nodes (Bezier or NURB). If there are no valid segment
|
|
|
|
* selections within the current selection, nothing happens.
|
|
|
|
*
|
|
|
|
* @deffunc subdividenurb subdivideNurb(void)
|
|
|
|
* @return Nothing
|
|
|
|
* @param None
|
|
|
|
*/
|
|
|
|
void subdivideNurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *prevbezt, *bezt, *beztnew, *beztn;
|
|
|
|
BPoint *bp, *prevbp, *bpnew, *bpn;
|
|
|
|
float vec[15];
|
|
|
|
int a, b, sel, amount, *usel, *vsel;
|
|
|
|
|
|
|
|
// printf("*** subdivideNurb: entering subdivide\n");
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
amount= 0;
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
/*
|
|
|
|
Insert a point into a 2D Bezier curve.
|
|
|
|
Endpoints are preserved. Otherwise, all selected and inserted points are
|
|
|
|
newly created. Old points are discarded.
|
|
|
|
*/
|
|
|
|
/* count */
|
|
|
|
if(nu->flagu & CU_CYCLIC) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
prevbezt= bezt+(a-1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu-1;
|
|
|
|
prevbezt= nu->bezt;
|
|
|
|
bezt= prevbezt+1;
|
|
|
|
}
|
|
|
|
while(a--) {
|
|
|
|
if( BEZSELECTED_HIDDENHANDLES(prevbezt) && BEZSELECTED_HIDDENHANDLES(bezt) ) amount++;
|
|
|
|
prevbezt= bezt;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(amount) {
|
|
|
|
/* insert */
|
|
|
|
beztnew =
|
|
|
|
(BezTriple*)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
|
|
|
|
beztn= beztnew;
|
|
|
|
if(nu->flagu & CU_CYCLIC) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
prevbezt= bezt+(a-1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu-1;
|
|
|
|
prevbezt= nu->bezt;
|
|
|
|
bezt= prevbezt+1;
|
|
|
|
}
|
|
|
|
while(a--) {
|
|
|
|
memcpy(beztn, prevbezt, sizeof(BezTriple));
|
|
|
|
beztn++;
|
|
|
|
|
|
|
|
if( BEZSELECTED_HIDDENHANDLES(prevbezt) && BEZSELECTED_HIDDENHANDLES(bezt) ) {
|
|
|
|
memcpy(beztn, bezt, sizeof(BezTriple));
|
|
|
|
|
|
|
|
/* midpoint subdividing */
|
|
|
|
VecMidf(vec, prevbezt->vec[1], prevbezt->vec[2]);
|
|
|
|
VecMidf(vec+3, prevbezt->vec[2], bezt->vec[0]);
|
|
|
|
VecMidf(vec+6, bezt->vec[0], bezt->vec[1]);
|
|
|
|
|
|
|
|
VecMidf(vec+9, vec, vec+3);
|
|
|
|
VecMidf(vec+12, vec+3, vec+6);
|
|
|
|
|
|
|
|
/* change handle of prev beztn */
|
|
|
|
VECCOPY((beztn-1)->vec[2], vec);
|
|
|
|
/* new point */
|
|
|
|
VECCOPY(beztn->vec[0], vec+9);
|
|
|
|
VecMidf(beztn->vec[1], vec+9, vec+12);
|
|
|
|
VECCOPY(beztn->vec[2], vec+12);
|
|
|
|
/* handle of next bezt */
|
|
|
|
if(a==0 && (nu->flagu & CU_CYCLIC)) {VECCOPY(beztnew->vec[0], vec+6);}
|
|
|
|
else {VECCOPY(bezt->vec[0], vec+6);}
|
|
|
|
|
|
|
|
beztn->radius = (prevbezt->radius + bezt->radius)/2.0f;
|
|
|
|
beztn->weight = (prevbezt->weight + bezt->weight)/2.0f;
|
|
|
|
|
|
|
|
beztn++;
|
|
|
|
}
|
|
|
|
|
|
|
|
prevbezt= bezt;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
/* last point */
|
|
|
|
if((nu->flagu & CU_CYCLIC)==0) memcpy(beztn, prevbezt, sizeof(BezTriple));
|
|
|
|
|
|
|
|
MEM_freeN(nu->bezt);
|
|
|
|
nu->bezt= beztnew;
|
|
|
|
nu->pntsu+= amount;
|
|
|
|
|
|
|
|
calchandlesNurb(nu);
|
|
|
|
}
|
|
|
|
} /* End of 'if((nu->type & 7)==CU_BEZIER)' */
|
|
|
|
else if (nu->pntsv==1) {
|
|
|
|
/*
|
|
|
|
All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves
|
|
|
|
are handled together with the regular NURB plane division, as it
|
|
|
|
should be. I split it off just now, let's see if it is
|
|
|
|
stable... nzc 30-5-'00
|
|
|
|
*/
|
|
|
|
/* count */
|
|
|
|
if(nu->flagu & CU_CYCLIC) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bp= nu->bp;
|
|
|
|
prevbp= bp+(a-1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu-1;
|
|
|
|
prevbp= nu->bp;
|
|
|
|
bp= prevbp+1;
|
|
|
|
}
|
|
|
|
while(a--) {
|
|
|
|
if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) amount++;
|
|
|
|
prevbp= bp;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(amount) {
|
|
|
|
/* insert */
|
|
|
|
bpnew =
|
|
|
|
(BPoint*)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
|
|
|
|
bpn= bpnew;
|
|
|
|
|
|
|
|
if(nu->flagu & CU_CYCLIC) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bp= nu->bp;
|
|
|
|
prevbp= bp+(a-1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu-1;
|
|
|
|
prevbp= nu->bp;
|
|
|
|
bp= prevbp+1;
|
|
|
|
}
|
|
|
|
while(a--) {
|
|
|
|
memcpy(bpn, prevbp, sizeof(BPoint));
|
|
|
|
bpn++;
|
|
|
|
|
|
|
|
if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) {
|
|
|
|
// printf("*** subdivideNurb: insert 'linear' point\n");
|
|
|
|
memcpy(bpn, bp, sizeof(BPoint));
|
|
|
|
bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
|
|
|
|
bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
|
|
|
|
bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
|
|
|
|
bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
|
|
|
|
bpn++;
|
|
|
|
|
|
|
|
}
|
|
|
|
prevbp= bp;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
if((nu->flagu & CU_CYCLIC)==0) memcpy(bpn, prevbp, sizeof(BPoint)); /* last point */
|
|
|
|
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= bpnew;
|
|
|
|
nu->pntsu+= amount;
|
|
|
|
|
|
|
|
if(nu->type & 4) {
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* End of 'else if(nu->pntsv==1)' */
|
|
|
|
else if((nu->type & 7)==CU_NURBS) {
|
|
|
|
/* This is a very strange test ... */
|
|
|
|
/**
|
|
|
|
Subdivide NURB surfaces - nzc 30-5-'00 -
|
|
|
|
|
|
|
|
Subdivision of a NURB curve can be effected by adding a
|
|
|
|
control point (insertion of a knot), or by raising the
|
|
|
|
degree of the functions used to build the NURB. The
|
|
|
|
expression
|
|
|
|
|
|
|
|
degree = #knots - #controlpoints + 1 (J Walter piece)
|
|
|
|
degree = #knots - #controlpoints (Blender
|
|
|
|
implementation)
|
|
|
|
( this is confusing.... what is true? Another concern
|
|
|
|
is that the JW piece allows the curve to become
|
|
|
|
explicitly 1st order derivative discontinuous, while
|
|
|
|
this is not what we want here... )
|
|
|
|
|
|
|
|
is an invariant for a single NURB curve. Raising the degree
|
|
|
|
of the NURB is done elsewhere; the degree is assumed
|
|
|
|
constant during this opration. Degree is a property shared
|
|
|
|
by all controlpoints in a curve (even though it is stored
|
|
|
|
per control point - this can be misleading).
|
|
|
|
Adding a knot is done by searching for the place in the
|
|
|
|
knot vector where a certain knot value must be inserted, or
|
|
|
|
by picking an appropriate knot value between two existing
|
|
|
|
ones. The number of controlpoints that is influenced by the
|
|
|
|
insertion depends on the order of the curve. A certain
|
|
|
|
minimum number of knots is needed to form high-order
|
|
|
|
curves, as can be seen from the equation above. In Blender,
|
|
|
|
currently NURBs may be up to 6th order, so we modify at
|
|
|
|
most 6 points. One point is added. For an n-degree curve,
|
|
|
|
n points are discarded, and n+1 points inserted
|
|
|
|
(so effectively, n points are modified). (that holds for
|
|
|
|
the JW piece, but it seems not for our NURBs)
|
|
|
|
In practice, the knot spacing is copied, but the tail
|
|
|
|
(the points following the insertion point) need to be
|
|
|
|
offset to keep the knot series ascending. The knot series
|
|
|
|
is always a series of monotonically ascending integers in
|
|
|
|
Blender. When not enough control points are available to
|
|
|
|
fit the order, duplicates of the endpoints are added as
|
|
|
|
needed.
|
|
|
|
*/
|
|
|
|
/* selection-arrays */
|
|
|
|
usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3");
|
|
|
|
vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3");
|
|
|
|
sel= 0;
|
|
|
|
|
|
|
|
/* Count the number of selected points. */
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0; a<nu->pntsv; a++) {
|
|
|
|
for(b=0; b<nu->pntsu; b++) {
|
|
|
|
if(bp->f1 & SELECT) {
|
|
|
|
usel[b]++;
|
|
|
|
vsel[a]++;
|
|
|
|
sel++;
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( sel == (nu->pntsu*nu->pntsv) ) { /* subdivide entire nurb */
|
|
|
|
/* Global subdivision is a special case of partial
|
|
|
|
subdivision. Strange it is considered separately... */
|
|
|
|
bpn=bpnew= MEM_mallocN( (2*nu->pntsu-1)*(2*nu->pntsv-1)*sizeof(BPoint), "subdivideNurb4");
|
|
|
|
bp= nu->bp;
|
|
|
|
/* first subdivide rows */
|
|
|
|
for(a=0; a<nu->pntsv; a++) {
|
|
|
|
for(b=0; b<nu->pntsu; b++) {
|
|
|
|
*bpn= *bp;
|
|
|
|
bpn++;
|
|
|
|
bp++;
|
|
|
|
if(b<nu->pntsu-1) {
|
|
|
|
*bpn= *bp;
|
|
|
|
prevbp= bp-1;
|
|
|
|
bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
|
|
|
|
bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
|
|
|
|
bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
|
|
|
|
bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
|
|
|
|
bpn++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bpn+= (2*nu->pntsu-1);
|
|
|
|
}
|
|
|
|
/* now insert new */
|
|
|
|
bpn= bpnew+(2*nu->pntsu-1);
|
|
|
|
bp= bpnew+(4*nu->pntsu-2);
|
|
|
|
prevbp= bpnew;
|
|
|
|
for(a=1; a<nu->pntsv; a++) {
|
|
|
|
|
|
|
|
for(b=0; b<2*nu->pntsu-1; b++) {
|
|
|
|
*bpn= *bp;
|
|
|
|
bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
|
|
|
|
bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
|
|
|
|
bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
|
|
|
|
bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
|
|
|
|
bpn++;
|
|
|
|
bp++;
|
|
|
|
prevbp++;
|
|
|
|
}
|
|
|
|
bp+= (2*nu->pntsu-1);
|
|
|
|
bpn+= (2*nu->pntsu-1);
|
|
|
|
prevbp+= (2*nu->pntsu-1);
|
|
|
|
}
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= bpnew;
|
|
|
|
nu->pntsu= 2*nu->pntsu-1;
|
|
|
|
nu->pntsv= 2*nu->pntsv-1;
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
makeknots(nu, 2, nu->flagv>>1);
|
|
|
|
} /* End of 'if(sel== nu->pntsu*nu->pntsv)' (subdivide entire NURB) */
|
|
|
|
else {
|
|
|
|
/* subdivide in v direction? */
|
|
|
|
sel= 0;
|
|
|
|
for(a=0; a<nu->pntsv-1; a++) {
|
|
|
|
if(vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu) sel++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(sel) { /* V ! */
|
|
|
|
bpn=bpnew= MEM_mallocN( (sel+nu->pntsv)*nu->pntsu*sizeof(BPoint), "subdivideNurb4");
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0; a<nu->pntsv; a++) {
|
|
|
|
for(b=0; b<nu->pntsu; b++) {
|
|
|
|
*bpn= *bp;
|
|
|
|
bpn++;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
if( (a<nu->pntsv-1) && vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu ) {
|
|
|
|
prevbp= bp- nu->pntsu;
|
|
|
|
for(b=0; b<nu->pntsu; b++) {
|
|
|
|
/*
|
|
|
|
This simple bisection must be replaces by a
|
|
|
|
subtle resampling of a number of points. Our
|
|
|
|
task is made slightly easier because each
|
|
|
|
point in our curve is a separate data
|
|
|
|
node. (is it?)
|
|
|
|
*/
|
|
|
|
*bpn= *prevbp;
|
|
|
|
bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
|
|
|
|
bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
|
|
|
|
bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
|
|
|
|
bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
|
|
|
|
bpn++;
|
|
|
|
prevbp++;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
bp-= nu->pntsu;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= bpnew;
|
|
|
|
nu->pntsv+= sel;
|
|
|
|
makeknots(nu, 2, nu->flagv>>1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* or in u direction? */
|
|
|
|
sel= 0;
|
|
|
|
for(a=0; a<nu->pntsu-1; a++) {
|
|
|
|
if(usel[a]==nu->pntsv && usel[a+1]==nu->pntsv) sel++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(sel) { /* U ! */
|
|
|
|
/* Inserting U points is sort of 'default' Flat curves only get */
|
|
|
|
/* U points inserted in them. */
|
|
|
|
bpn=bpnew= MEM_mallocN( (sel+nu->pntsu)*nu->pntsv*sizeof(BPoint), "subdivideNurb4");
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0; a<nu->pntsv; a++) {
|
|
|
|
for(b=0; b<nu->pntsu; b++) {
|
|
|
|
*bpn= *bp;
|
|
|
|
bpn++;
|
|
|
|
bp++;
|
|
|
|
if( (b<nu->pntsu-1) && usel[b]==nu->pntsv && usel[b+1]==nu->pntsv ) {
|
|
|
|
/*
|
|
|
|
One thing that bugs me here is that the
|
|
|
|
orders of things are not the same as in
|
|
|
|
the JW piece. Also, this implies that we
|
|
|
|
handle at most 3rd order curves? I miss
|
|
|
|
some symmetry here...
|
|
|
|
*/
|
|
|
|
prevbp= bp- 1;
|
|
|
|
*bpn= *prevbp;
|
|
|
|
bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
|
|
|
|
bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
|
|
|
|
bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
|
|
|
|
bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
|
|
|
|
bpn++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= bpnew;
|
|
|
|
nu->pntsu+= sel;
|
|
|
|
makeknots(nu, 1, nu->flagu>>1); /* shift knots
|
|
|
|
forward */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MEM_freeN(usel);
|
|
|
|
MEM_freeN(vsel);
|
|
|
|
|
|
|
|
} /* End of 'if((nu->type & 7)==CU_NURBS)' */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
|
|
|
|
BIF_undo_push("Subdivide");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void findnearestNurbvert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
|
|
|
|
{
|
|
|
|
struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; short dist, hpoint, select, mval[2]; } *data = userData;
|
|
|
|
|
|
|
|
short flag;
|
|
|
|
short temp;
|
|
|
|
|
|
|
|
if (bp) {
|
|
|
|
flag = bp->f1;
|
|
|
|
} else {
|
|
|
|
if (beztindex==0) {
|
|
|
|
flag = bezt->f1;
|
|
|
|
} else if (beztindex==1) {
|
|
|
|
flag = bezt->f2;
|
|
|
|
} else {
|
|
|
|
flag = bezt->f3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
|
|
|
|
if ((flag&1)==data->select) temp += 5;
|
|
|
|
if (bezt && beztindex==1) temp += 3; /* middle points get a small disadvantage */
|
|
|
|
|
|
|
|
if (temp<data->dist) {
|
|
|
|
data->dist = temp;
|
|
|
|
|
|
|
|
data->bp = bp;
|
|
|
|
data->bezt = bezt;
|
|
|
|
data->nurb = nu;
|
|
|
|
data->hpoint = bezt?beztindex:0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static short findnearestNurbvert(ViewContext *vc, short sel, short mval[2], Nurb **nurb, BezTriple **bezt, BPoint **bp)
|
|
|
|
{
|
|
|
|
/* sel==1: selected gets a disadvantage */
|
|
|
|
/* in nurb and bezt or bp the nearest is written */
|
|
|
|
/* return 0 1 2: handlepunt */
|
|
|
|
struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; short dist, hpoint, select, mval[2]; } data = {0};
|
|
|
|
|
|
|
|
data.dist = 100;
|
|
|
|
data.hpoint = 0;
|
|
|
|
data.select = sel;
|
|
|
|
data.mval[0] = mval[0];
|
|
|
|
data.mval[1] = mval[1];
|
|
|
|
|
|
|
|
nurbs_foreachScreenVert(vc, findnearestNurbvert__doClosest, &data);
|
|
|
|
|
|
|
|
*nurb = data.nurb;
|
|
|
|
*bezt = data.bezt;
|
|
|
|
*bp = data.bp;
|
|
|
|
|
|
|
|
return data.hpoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void findselectedNurbvert(ListBase *editnurb, Nurb **nu, BezTriple **bezt, BPoint **bp)
|
|
|
|
{
|
|
|
|
/* in nu and (bezt or bp) selected are written if there's 1 sel. */
|
|
|
|
/* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
|
|
|
|
Nurb *nu1;
|
|
|
|
BezTriple *bezt1;
|
|
|
|
BPoint *bp1;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
*nu= 0;
|
|
|
|
*bezt= 0;
|
|
|
|
*bp= 0;
|
|
|
|
for(nu1= editnurb->first; nu1; nu1= nu1->next) {
|
|
|
|
if((nu1->type & 7)==CU_BEZIER) {
|
|
|
|
bezt1= nu1->bezt;
|
|
|
|
a= nu1->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
if( (bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT) ) {
|
|
|
|
if(*nu!=0 && *nu!= nu1) {
|
|
|
|
*nu= 0;
|
|
|
|
*bp= 0;
|
|
|
|
*bezt= 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if(*bezt || *bp) {
|
|
|
|
*bp= 0;
|
|
|
|
*bezt= 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*bezt= bezt1;
|
|
|
|
*nu= nu1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bezt1++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp1= nu1->bp;
|
|
|
|
a= nu1->pntsu*nu1->pntsv;
|
|
|
|
while(a--) {
|
|
|
|
if( bp1->f1 & 1 ) {
|
|
|
|
if(*nu!=0 && *nu!= nu1) {
|
|
|
|
*bp= 0;
|
|
|
|
*bezt= 0;
|
|
|
|
*nu= 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if(*bezt || *bp) {
|
|
|
|
*bp= 0;
|
|
|
|
*bezt= 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*bp= bp1;
|
|
|
|
*nu= nu1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bp1++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int convertspline(short type, Nurb *nu)
|
|
|
|
{
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a, c, nr;
|
|
|
|
|
|
|
|
if((nu->type & 7)==0) { /* Poly */
|
|
|
|
if(type==CU_BEZIER) { /* to Bezier with vecthandles */
|
|
|
|
nr= nu->pntsu;
|
|
|
|
bezt =
|
|
|
|
(BezTriple*)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
|
|
|
|
nu->bezt= bezt;
|
|
|
|
a= nr;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
VECCOPY(bezt->vec[1], bp->vec);
|
|
|
|
bezt->f1=bezt->f2=bezt->f3= bp->f1;
|
|
|
|
bezt->h1= bezt->h2= HD_VECT;
|
|
|
|
bezt->weight= bp->weight;
|
|
|
|
bezt->radius= bp->radius;
|
|
|
|
bp++;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= 0;
|
|
|
|
nu->pntsu= nr;
|
|
|
|
nu->type &= ~7;
|
|
|
|
nu->type |= 1;
|
|
|
|
calchandlesNurb(nu);
|
|
|
|
}
|
|
|
|
else if(type==CU_NURBS) {
|
|
|
|
nu->type &= ~7;
|
|
|
|
nu->type+= 4;
|
|
|
|
nu->orderu= 4;
|
|
|
|
nu->flagu &= CU_CYCLIC; /* disable all flags except for cyclic */
|
|
|
|
nu->flagu += 4;
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
bp->vec[3]= 1.0;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if((nu->type & 7)==CU_BEZIER) { /* Bezier */
|
|
|
|
if(type==0 || type==4) { /* to Poly or Nurb */
|
|
|
|
nr= 3*nu->pntsu;
|
|
|
|
nu->bp = MEM_callocN(nr * sizeof(BPoint), "setsplinetype");
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
if(type==0 && bezt->h1==HD_VECT && bezt->h2==HD_VECT) {
|
|
|
|
/* vector handle becomes 1 poly vertice */
|
|
|
|
VECCOPY(bp->vec, bezt->vec[1]);
|
|
|
|
bp->vec[3]= 1.0;
|
|
|
|
bp->f1= bezt->f2;
|
|
|
|
nr-= 2;
|
|
|
|
bp->radius= bezt->radius;
|
|
|
|
bp->weight= bezt->weight;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for(c=0;c<3;c++) {
|
|
|
|
VECCOPY(bp->vec, bezt->vec[c]);
|
|
|
|
bp->vec[3]= 1.0;
|
|
|
|
if(c==0) bp->f1= bezt->f1;
|
|
|
|
else if(c==1) bp->f1= bezt->f2;
|
|
|
|
else bp->f1= bezt->f3;
|
|
|
|
bp->radius= bezt->radius;
|
|
|
|
bp->weight= bezt->weight;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
MEM_freeN(nu->bezt);
|
|
|
|
nu->bezt= 0;
|
|
|
|
nu->pntsu= nr;
|
|
|
|
nu->pntsv= 1;
|
|
|
|
nu->orderu= 4;
|
|
|
|
nu->orderv= 1;
|
|
|
|
nu->type &= ~7;
|
|
|
|
nu->type+= type;
|
|
|
|
if(nu->flagu & CU_CYCLIC) c= nu->orderu-1;
|
|
|
|
else c= 0;
|
|
|
|
if(type== 4) {
|
|
|
|
nu->flagu &= CU_CYCLIC; /* disable all flags except for cyclic */
|
|
|
|
nu->flagu += 4;
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( (nu->type & 7)==CU_NURBS) {
|
|
|
|
if(type==0) { /* to Poly */
|
|
|
|
nu->type &= ~7;
|
|
|
|
if(nu->knotsu) MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
|
|
|
|
nu->knotsu= NULL;
|
|
|
|
if(nu->knotsv) MEM_freeN(nu->knotsv);
|
|
|
|
nu->knotsv= NULL;
|
|
|
|
}
|
|
|
|
else if(type==CU_BEZIER) { /* to Bezier */
|
|
|
|
nr= nu->pntsu/3;
|
|
|
|
|
|
|
|
if(nr<2)
|
|
|
|
return 1; /* conversion impossible */
|
|
|
|
else {
|
|
|
|
bezt = MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
|
|
|
|
nu->bezt= bezt;
|
|
|
|
a= nr;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
VECCOPY(bezt->vec[0], bp->vec);
|
|
|
|
bezt->f1= bp->f1;
|
|
|
|
bp++;
|
|
|
|
VECCOPY(bezt->vec[1], bp->vec);
|
|
|
|
bezt->f2= bp->f1;
|
|
|
|
bp++;
|
|
|
|
VECCOPY(bezt->vec[2], bp->vec);
|
|
|
|
bezt->f3= bp->f1;
|
|
|
|
bezt->radius= bp->radius;
|
|
|
|
bezt->weight= bp->weight;
|
|
|
|
bp++;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= 0;
|
|
|
|
MEM_freeN(nu->knotsu);
|
|
|
|
nu->knotsu= NULL;
|
|
|
|
nu->pntsu= nr;
|
|
|
|
nu->type &= ~7;
|
|
|
|
nu->type+= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setsplinetype(Scene *scene, short type)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
|
|
|
|
if(type==CU_CARDINAL || type==CU_BSPLINE) {
|
|
|
|
error("Not implemented yet");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if(isNurbsel(nu)) {
|
|
|
|
if (convertspline(type, nu))
|
|
|
|
error("no conversion possible");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BIF_undo_push("Set spline type");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************** SKINNING LOFTING!!! ******************** */
|
|
|
|
|
|
|
|
void rotate_direction_nurb(Nurb *nu)
|
|
|
|
{
|
|
|
|
BPoint *bp1, *bp2, *temp;
|
|
|
|
int u, v;
|
|
|
|
|
|
|
|
SWAP(short, nu->pntsu, nu->pntsv);
|
|
|
|
SWAP(short, nu->orderu, nu->orderv);
|
|
|
|
SWAP(short, nu->resolu, nu->resolv);
|
|
|
|
SWAP(short, nu->flagu, nu->flagv);
|
|
|
|
|
|
|
|
SWAP(float *, nu->knotsu, nu->knotsv);
|
|
|
|
switchdirection_knots(nu->knotsv, KNOTSV(nu) );
|
|
|
|
|
|
|
|
temp= MEM_dupallocN(nu->bp);
|
|
|
|
bp1= nu->bp;
|
|
|
|
for(v=0; v<nu->pntsv; v++) {
|
|
|
|
for(u=0; u<nu->pntsu; u++, bp1++) {
|
|
|
|
bp2= temp + (nu->pntsu-u-1)*(nu->pntsv) + v;
|
|
|
|
*bp1= *bp2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
int is_u_selected(Nurb *nu, int u)
|
|
|
|
{
|
|
|
|
BPoint *bp;
|
|
|
|
int v;
|
|
|
|
|
|
|
|
/* what about resolu == 2? */
|
|
|
|
bp= nu->bp+u;
|
|
|
|
for(v=0; v<nu->pntsv-1; v++, bp+=nu->pntsu) {
|
|
|
|
if(v) if(bp->f1 & SELECT) return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************************** */
|
|
|
|
|
|
|
|
typedef struct NurbSort {
|
|
|
|
struct NurbSort *next, *prev;
|
|
|
|
Nurb *nu;
|
|
|
|
float vec[3];
|
|
|
|
} NurbSort;
|
|
|
|
|
|
|
|
static ListBase nsortbase= {0, 0};
|
|
|
|
/* static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
|
|
|
|
|
|
|
|
void make_selection_list_nurb(ListBase *editnurb)
|
|
|
|
{
|
|
|
|
ListBase nbase= {0, 0};
|
|
|
|
NurbSort *nus, *nustest, *headdo, *taildo;
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp;
|
|
|
|
float dist, headdist, taildist;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if( isNurbsel(nu) ) {
|
|
|
|
|
|
|
|
nus = (NurbSort*)MEM_callocN(sizeof(NurbSort), "sort");
|
|
|
|
BLI_addhead(&nbase, nus);
|
|
|
|
nus->nu= nu;
|
|
|
|
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
VecAddf(nus->vec, nus->vec, bp->vec);
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
VecMulf(nus->vec, 1.0/(float)nu->pntsu);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* just add the first one */
|
|
|
|
nus= nbase.first;
|
|
|
|
BLI_remlink(&nbase, nus);
|
|
|
|
BLI_addtail( &nsortbase, nus);
|
|
|
|
|
|
|
|
/* now add, either at head or tail, the closest one */
|
|
|
|
while(nbase.first) {
|
|
|
|
|
|
|
|
headdist= taildist= 1.0e30;
|
|
|
|
headdo= taildo= 0;
|
|
|
|
|
|
|
|
nustest= nbase.first;
|
|
|
|
while(nustest) {
|
|
|
|
dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.first)->vec);
|
|
|
|
|
|
|
|
if(dist<headdist) {
|
|
|
|
headdist= dist;
|
|
|
|
headdo= nustest;
|
|
|
|
}
|
|
|
|
dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.last)->vec);
|
|
|
|
|
|
|
|
if(dist<taildist) {
|
|
|
|
taildist= dist;
|
|
|
|
taildo= nustest;
|
|
|
|
}
|
|
|
|
nustest= nustest->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(headdist<taildist) {
|
|
|
|
BLI_remlink(&nbase, headdo);
|
|
|
|
BLI_addhead(&nsortbase, headdo);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_remlink(&nbase, taildo);
|
|
|
|
BLI_addtail(&nsortbase, taildo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void merge_2_nurb(ListBase *editnurb, Nurb *nu1, Nurb *nu2)
|
|
|
|
{
|
|
|
|
BPoint *bp, *bp1, *bp2, *temp;
|
|
|
|
float len1, len2;
|
|
|
|
int origu, u, v;
|
|
|
|
|
|
|
|
/* first nurbs will be changed to make u = resolu-1 selected */
|
|
|
|
/* 2nd nurbs will be changed to make u = 0 selected */
|
|
|
|
|
|
|
|
/* first nurbs: u = resolu-1 selected */
|
|
|
|
|
|
|
|
if( is_u_selected(nu1, nu1->pntsu-1) );
|
|
|
|
else {
|
|
|
|
rotate_direction_nurb(nu1);
|
|
|
|
if( is_u_selected(nu1, nu1->pntsu-1) );
|
|
|
|
else {
|
|
|
|
rotate_direction_nurb(nu1);
|
|
|
|
if( is_u_selected(nu1, nu1->pntsu-1) );
|
|
|
|
else {
|
|
|
|
rotate_direction_nurb(nu1);
|
|
|
|
if( is_u_selected(nu1, nu1->pntsu-1) );
|
|
|
|
else {
|
|
|
|
/* rotate again, now its OK! */
|
|
|
|
if(nu1->pntsv!=1) rotate_direction_nurb(nu1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 2nd nurbs: u = 0 selected */
|
|
|
|
if( is_u_selected(nu2, 0) );
|
|
|
|
else {
|
|
|
|
rotate_direction_nurb(nu2);
|
|
|
|
if( is_u_selected(nu2, 0) );
|
|
|
|
else {
|
|
|
|
rotate_direction_nurb(nu2);
|
|
|
|
if( is_u_selected(nu2, 0) );
|
|
|
|
else {
|
|
|
|
rotate_direction_nurb(nu2);
|
|
|
|
if( is_u_selected(nu2, 0) );
|
|
|
|
else {
|
|
|
|
/* rotate again, now its OK! */
|
|
|
|
if(nu1->pntsu==1) rotate_direction_nurb(nu1);
|
|
|
|
if(nu2->pntsv!=1) rotate_direction_nurb(nu2);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( nu1->pntsv != nu2->pntsv ) {
|
|
|
|
error("Resolution doesn't match");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ok, now nu1 has the rightmost collumn and nu2 the leftmost collumn selected */
|
|
|
|
/* maybe we need a 'v' flip of nu2? */
|
|
|
|
|
|
|
|
bp1= nu1->bp+nu1->pntsu-1;
|
|
|
|
bp2= nu2->bp;
|
|
|
|
len1= 0.0;
|
|
|
|
|
|
|
|
for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2+=nu2->pntsu) {
|
|
|
|
len1+= VecLenf(bp1->vec, bp2->vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
bp1= nu1->bp + nu1->pntsu-1;
|
|
|
|
bp2= nu2->bp + nu2->pntsu*(nu2->pntsv-1);
|
|
|
|
len2= 0.0;
|
|
|
|
|
|
|
|
for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2-=nu2->pntsu) {
|
|
|
|
len2+= VecLenf(bp1->vec, bp2->vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* merge */
|
|
|
|
origu= nu1->pntsu;
|
|
|
|
nu1->pntsu+= nu2->pntsu;
|
|
|
|
if(nu1->orderu<3) nu1->orderu++;
|
|
|
|
if(nu1->orderv<3) nu1->orderv++;
|
|
|
|
temp= nu1->bp;
|
|
|
|
nu1->bp= MEM_mallocN(nu1->pntsu*nu1->pntsv*sizeof(BPoint), "mergeBP");
|
|
|
|
|
|
|
|
bp= nu1->bp;
|
|
|
|
bp1= temp;
|
|
|
|
|
|
|
|
for(v=0; v<nu1->pntsv; v++) {
|
|
|
|
|
|
|
|
/* switch direction? */
|
|
|
|
if(len1<len2) bp2= nu2->bp + v*nu2->pntsu;
|
|
|
|
else bp2= nu2->bp + (nu1->pntsv-v-1)*nu2->pntsu;
|
|
|
|
|
|
|
|
for(u=0; u<nu1->pntsu; u++, bp++) {
|
|
|
|
if(u<origu) {
|
|
|
|
*bp= *bp1; bp1++;
|
|
|
|
select_bpoint(bp, SELECT, 1, HIDDEN);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*bp= *bp2; bp2++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if((nu1->type & 7)==4) {
|
|
|
|
/* merge knots */
|
|
|
|
makeknots(nu1, 1, nu1->flagu>>1);
|
|
|
|
|
|
|
|
/* make knots, for merged curved for example */
|
|
|
|
makeknots(nu1, 2, nu1->flagv>>1);
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(temp);
|
|
|
|
BLI_remlink(editnurb, nu2);
|
|
|
|
freeNurb(nu2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void merge_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
NurbSort *nus1, *nus2;
|
|
|
|
int ok= 1;
|
|
|
|
|
|
|
|
make_selection_list_nurb(editnurb);
|
|
|
|
|
|
|
|
if(nsortbase.first == nsortbase.last) {
|
|
|
|
BLI_freelistN(&nsortbase);
|
|
|
|
error("Too few selections to merge");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nus1= nsortbase.first;
|
|
|
|
nus2= nus1->next;
|
|
|
|
|
|
|
|
/* resolution match, to avoid uv rotations */
|
|
|
|
if(nus1->nu->pntsv==1) {
|
|
|
|
if(nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsu==nus2->nu->pntsv);
|
|
|
|
else ok= 0;
|
|
|
|
}
|
|
|
|
else if(nus2->nu->pntsv==1) {
|
|
|
|
if(nus2->nu->pntsu==nus1->nu->pntsu || nus2->nu->pntsu==nus1->nu->pntsv);
|
|
|
|
else ok= 0;
|
|
|
|
}
|
|
|
|
else if( nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsv==nus2->nu->pntsv);
|
|
|
|
else if( nus1->nu->pntsu==nus2->nu->pntsv || nus1->nu->pntsv==nus2->nu->pntsu);
|
|
|
|
else {
|
|
|
|
ok= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ok==0) {
|
|
|
|
error("Resolution doesn't match");
|
|
|
|
BLI_freelistN(&nsortbase);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(nus2) {
|
|
|
|
merge_2_nurb(editnurb, nus1->nu, nus2->nu);
|
|
|
|
nus2= nus2->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_freelistN(&nsortbase);
|
|
|
|
|
|
|
|
set_actNurb(obedit, NULL);
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
|
|
|
|
BIF_undo_push("Merge");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void addsegment_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
/* joins 2 curves */
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu, *nu1=0, *nu2=0;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
float *fp, offset;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
/* first decide if this is a surface merge! */
|
|
|
|
if(obedit->type==OB_SURF) nu= editnurb->first;
|
|
|
|
else nu= NULL;
|
|
|
|
|
|
|
|
while(nu) {
|
|
|
|
if( isNurbsel(nu) ) {
|
|
|
|
|
|
|
|
if(nu->pntsu>1 && nu->pntsv>1) break;
|
|
|
|
if(isNurbsel_count(nu)>1) break;
|
|
|
|
if(isNurbsel_count(nu)==1) {
|
|
|
|
/* only 1 selected, not first or last, a little complex, but intuitive */
|
|
|
|
if(nu->pntsv==1) {
|
|
|
|
if( (nu->bp->f1 & SELECT) || ((nu->bp+nu->pntsu-1)->f1 & SELECT));
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nu= nu->next;
|
|
|
|
}
|
|
|
|
if(nu) {
|
|
|
|
merge_nurb(scene);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find both nurbs and points, nu1 will be put behind nu2 */
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if((nu->flagu & CU_CYCLIC)==0) { /* not cyclic */
|
|
|
|
if( (nu->type & 7)==CU_BEZIER ) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
if(nu1==0) {
|
|
|
|
if( BEZSELECTED_HIDDENHANDLES(bezt) ) nu1= nu;
|
|
|
|
else {
|
|
|
|
bezt= bezt+(nu->pntsu-1);
|
|
|
|
if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
|
|
|
|
nu1= nu;
|
|
|
|
switchdirectionNurb(nu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nu2==0) {
|
|
|
|
if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
|
|
|
|
nu2= nu;
|
|
|
|
switchdirectionNurb(nu);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bezt= bezt+(nu->pntsu-1);
|
|
|
|
if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
|
|
|
|
nu2= nu;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
else if(nu->pntsv==1) {
|
|
|
|
bp= nu->bp;
|
|
|
|
if(nu1==0) {
|
|
|
|
if( bp->f1 & SELECT) nu1= nu;
|
|
|
|
else {
|
|
|
|
bp= bp+(nu->pntsu-1);
|
|
|
|
if( bp->f1 & SELECT ) {
|
|
|
|
nu1= nu;
|
|
|
|
switchdirectionNurb(nu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nu2==0) {
|
|
|
|
if( bp->f1 & SELECT ) {
|
|
|
|
nu2= nu;
|
|
|
|
switchdirectionNurb(nu);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp= bp+(nu->pntsu-1);
|
|
|
|
if( bp->f1 & SELECT ) {
|
|
|
|
nu2= nu;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if((nu1 && nu2) && (nu1!=nu2)) {
|
|
|
|
if( nu1->type==nu2->type) {
|
|
|
|
if((nu1->type & 7)==CU_BEZIER) {
|
|
|
|
bezt =
|
|
|
|
(BezTriple*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BezTriple), "addsegmentN");
|
|
|
|
memcpy(bezt, nu2->bezt, nu2->pntsu*sizeof(BezTriple));
|
|
|
|
memcpy(bezt+nu2->pntsu, nu1->bezt, nu1->pntsu*sizeof(BezTriple));
|
|
|
|
MEM_freeN(nu1->bezt);
|
|
|
|
nu1->bezt= bezt;
|
|
|
|
nu1->pntsu+= nu2->pntsu;
|
|
|
|
BLI_remlink(editnurb, nu2);
|
|
|
|
freeNurb(nu2); nu2= NULL;
|
|
|
|
calchandlesNurb(nu1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp =
|
|
|
|
(BPoint*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BPoint), "addsegmentN2");
|
|
|
|
memcpy(bp, nu2->bp, nu2->pntsu*sizeof(BPoint) );
|
|
|
|
memcpy(bp+nu2->pntsu, nu1->bp, nu1->pntsu*sizeof(BPoint));
|
|
|
|
MEM_freeN(nu1->bp);
|
|
|
|
nu1->bp= bp;
|
|
|
|
|
|
|
|
a= nu1->pntsu+nu1->orderu;
|
|
|
|
|
|
|
|
nu1->pntsu+= nu2->pntsu;
|
|
|
|
BLI_remlink(editnurb, nu2);
|
|
|
|
|
|
|
|
/* now join the knots */
|
|
|
|
if((nu1->type & 7)==4) {
|
|
|
|
if(nu1->knotsu==NULL) {
|
|
|
|
makeknots(nu1, 1, nu1->flagu>>1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fp= MEM_mallocN(sizeof(float)*KNOTSU(nu1), "addsegment3");
|
|
|
|
memcpy(fp, nu1->knotsu, sizeof(float)*a);
|
|
|
|
MEM_freeN(nu1->knotsu);
|
|
|
|
nu1->knotsu= fp;
|
|
|
|
|
|
|
|
|
|
|
|
offset= nu1->knotsu[a-1] +1.0;
|
|
|
|
fp= nu1->knotsu+a;
|
|
|
|
for(a=0; a<nu2->pntsu; a++, fp++) {
|
|
|
|
if(nu2->knotsu)
|
|
|
|
*fp= offset+nu2->knotsu[a+1];
|
|
|
|
else
|
|
|
|
*fp = offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
freeNurb(nu2); nu2= NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_actNurb(obedit, NULL); /* for selected */
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
|
|
|
|
BIF_undo_push("Add segment");
|
|
|
|
|
|
|
|
}
|
|
|
|
else error("Can't make segment");
|
|
|
|
}
|
|
|
|
|
|
|
|
void mouse_nurb(bContext *C, short mval[2], int extend)
|
|
|
|
{
|
2009-02-04 17:40:50 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-01-14 12:26:45 +00:00
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Curve *cu= obedit->data;
|
|
|
|
ViewContext vc;
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt=0;
|
|
|
|
BPoint *bp=0;
|
|
|
|
short hand;
|
|
|
|
|
|
|
|
view3d_set_viewcontext(C, &vc);
|
|
|
|
|
|
|
|
hand= findnearestNurbvert(&vc, 1, mval, &nu, &bezt, &bp);
|
|
|
|
|
|
|
|
if(bezt || bp) {
|
|
|
|
if(extend==0) {
|
|
|
|
|
|
|
|
setflagsNurb(editnurb, 0);
|
|
|
|
|
|
|
|
if(bezt) {
|
|
|
|
|
|
|
|
if(hand==1) select_beztriple(bezt, SELECT, 1, HIDDEN);
|
|
|
|
else if(hand==0) bezt->f1|= SELECT;
|
|
|
|
else bezt->f3|= SELECT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cu->lastselbp= bp;
|
|
|
|
select_bpoint(bp, SELECT, 1, HIDDEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(bezt) {
|
|
|
|
if(hand==1) {
|
|
|
|
if(bezt->f2 & SELECT) select_beztriple(bezt, DESELECT, 1, HIDDEN);
|
|
|
|
else select_beztriple(bezt, SELECT, 1, HIDDEN);
|
|
|
|
} else if(hand==0) {
|
|
|
|
bezt->f1 ^= SELECT;
|
|
|
|
} else {
|
|
|
|
bezt->f3 ^= SELECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(bp->f1 & SELECT) select_bpoint(bp, DESELECT, 1, HIDDEN);
|
|
|
|
else {
|
|
|
|
select_bpoint(bp, SELECT, 1, HIDDEN);
|
|
|
|
cu->lastselbp= bp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-02-04 17:40:50 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
|
2009-01-14 12:26:45 +00:00
|
|
|
|
|
|
|
if(nu!=get_actNurb(obedit)) {
|
|
|
|
set_actNurb(obedit, nu);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* from what I can gather, the mode==0 magic number spins and bridges the nurbs based on the
|
|
|
|
* orientation of the global 3d view (yuck yuck!) mode==1 does the same, but doesn't bridge up
|
|
|
|
* up the new geometry, mode==2 now does the same as 0, but aligned to world axes, not the view.
|
|
|
|
*/
|
|
|
|
static void spin_nurb(Scene *scene, Object *obedit, float *dvec, short mode)
|
|
|
|
{
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
RegionView3D *rv3d= NULL; // XXX
|
2009-01-14 12:26:45 +00:00
|
|
|
View3D *v3d= NULL; // XXX
|
|
|
|
Nurb *nu;
|
|
|
|
float *curs, si,phi,n[3],q[4],cmat[3][3],tmat[3][3],imat[3][3];
|
|
|
|
float cent[3],bmat[3][3], rotmat[3][3], scalemat1[3][3], scalemat2[3][3];
|
|
|
|
float persmat[3][3], persinv[3][3];
|
|
|
|
short a,ok;
|
|
|
|
|
|
|
|
if(v3d==0 || obedit==0 || obedit->type!=OB_SURF) return;
|
|
|
|
if( (v3d->lay & obedit->lay)==0 ) return;
|
|
|
|
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
if (mode != 2) Mat3CpyMat4(persmat, rv3d->viewmat);
|
2009-01-14 12:26:45 +00:00
|
|
|
else Mat3One(persmat);
|
|
|
|
Mat3Inv(persinv, persmat);
|
|
|
|
|
|
|
|
/* imat and center and size */
|
|
|
|
Mat3CpyMat4(bmat, obedit->obmat);
|
|
|
|
Mat3Inv(imat, bmat);
|
|
|
|
|
|
|
|
curs= give_cursor(scene, v3d);
|
|
|
|
VECCOPY(cent, curs);
|
|
|
|
VecSubf(cent, cent, obedit->obmat[3]);
|
|
|
|
Mat3MulVecfl(imat,cent);
|
|
|
|
|
|
|
|
if(dvec || mode==2) {
|
|
|
|
n[0]=n[1]= 0.0;
|
|
|
|
n[2]= 1.0;
|
|
|
|
} else {
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
n[0]= rv3d->viewinv[2][0];
|
|
|
|
n[1]= rv3d->viewinv[2][1];
|
|
|
|
n[2]= rv3d->viewinv[2][2];
|
2009-01-14 12:26:45 +00:00
|
|
|
Normalize(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
phi= M_PI/8.0;
|
|
|
|
q[0]= cos(phi);
|
|
|
|
si= sin(phi);
|
|
|
|
q[1]= n[0]*si;
|
|
|
|
q[2]= n[1]*si;
|
|
|
|
q[3]= n[2]*si;
|
|
|
|
QuatToMat3(q, cmat);
|
|
|
|
Mat3MulMat3(tmat, cmat, bmat);
|
|
|
|
Mat3MulMat3(rotmat, imat, tmat);
|
|
|
|
|
|
|
|
Mat3One(scalemat1);
|
|
|
|
scalemat1[0][0]= sqrt(2.0);
|
|
|
|
scalemat1[1][1]= sqrt(2.0);
|
|
|
|
|
|
|
|
Mat3MulMat3(tmat,persmat,bmat);
|
|
|
|
Mat3MulMat3(cmat,scalemat1,tmat);
|
|
|
|
Mat3MulMat3(tmat,persinv,cmat);
|
|
|
|
Mat3MulMat3(scalemat1,imat,tmat);
|
|
|
|
|
|
|
|
Mat3One(scalemat2);
|
|
|
|
scalemat2[0][0]/= sqrt(2.0);
|
|
|
|
scalemat2[1][1]/= sqrt(2.0);
|
|
|
|
|
|
|
|
Mat3MulMat3(tmat,persmat,bmat);
|
|
|
|
Mat3MulMat3(cmat,scalemat2,tmat);
|
|
|
|
Mat3MulMat3(tmat,persinv,cmat);
|
|
|
|
Mat3MulMat3(scalemat2,imat,tmat);
|
|
|
|
|
|
|
|
ok= 1;
|
|
|
|
|
|
|
|
for(a=0;a<7;a++) {
|
|
|
|
if(mode==0 || mode==2) ok= extrudeflagNurb(editnurb, 1);
|
|
|
|
else adduplicateflagNurb(scene, 1);
|
|
|
|
if(ok==0) {
|
|
|
|
error("Can't spin");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rotateflagNurb(editnurb, 1,cent,rotmat);
|
|
|
|
|
|
|
|
if(mode==0 || mode==2) {
|
|
|
|
if( (a & 1)==0 ) {
|
|
|
|
rotateflagNurb(editnurb, 1,cent,scalemat1);
|
|
|
|
weightflagNurb(editnurb, 1, 0.25*sqrt(2.0), 1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rotateflagNurb(editnurb, 1,cent,scalemat2);
|
|
|
|
weightflagNurb(editnurb, 1, 4.0/sqrt(2.0), 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(dvec) {
|
|
|
|
Mat3MulVecfl(bmat,dvec);
|
|
|
|
translateflagNurb(editnurb, 1,dvec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ok) {
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if(isNurbsel(nu)) {
|
|
|
|
nu->orderv= 4;
|
|
|
|
nu->flagv |= CU_CYCLIC;
|
|
|
|
makeknots(nu, 2, nu->flagv>>1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* external one, for undo */
|
|
|
|
void spinNurb(Scene *scene, float *dvec, short mode)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
|
|
|
|
spin_nurb(scene, obedit, dvec, mode);
|
|
|
|
BIF_undo_push("Spin");
|
|
|
|
}
|
|
|
|
|
|
|
|
void addvert_Nurb(Scene *scene, int mode)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
View3D *v3d= NULL; // XXX
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt, *newbezt = NULL;
|
|
|
|
BPoint *bp, *newbp = NULL;
|
|
|
|
float *curs, mat[3][3],imat[3][3], temp[3];
|
|
|
|
|
|
|
|
if(obedit==0 || v3d == 0) return;
|
|
|
|
if( (v3d->lay & obedit->lay)==0 ) return;
|
|
|
|
|
|
|
|
Mat3CpyMat4(mat, obedit->obmat);
|
|
|
|
Mat3Inv(imat,mat);
|
|
|
|
|
|
|
|
findselectedNurbvert(editnurb, &nu, &bezt, &bp);
|
|
|
|
if(bezt==0 && bp==0) return;
|
|
|
|
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
/* which bezpoint? */
|
|
|
|
if(bezt== nu->bezt) { /* first */
|
|
|
|
BEZ_DESEL(bezt);
|
|
|
|
newbezt =
|
|
|
|
(BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb");
|
|
|
|
memcpy(newbezt+1, bezt, nu->pntsu*sizeof(BezTriple));
|
|
|
|
*newbezt= *bezt;
|
|
|
|
BEZ_SEL(newbezt);
|
|
|
|
newbezt->h2= newbezt->h1;
|
|
|
|
VECCOPY(temp, bezt->vec[1]);
|
|
|
|
MEM_freeN(nu->bezt);
|
|
|
|
nu->bezt= newbezt;
|
|
|
|
bezt= newbezt+1;
|
|
|
|
}
|
|
|
|
else if(bezt== (nu->bezt+nu->pntsu-1)) { /* last */
|
|
|
|
BEZ_DESEL(bezt);
|
|
|
|
newbezt =
|
|
|
|
(BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb");
|
|
|
|
memcpy(newbezt, nu->bezt, nu->pntsu*sizeof(BezTriple));
|
|
|
|
*(newbezt+nu->pntsu)= *bezt;
|
|
|
|
VECCOPY(temp, bezt->vec[1]);
|
|
|
|
MEM_freeN(nu->bezt);
|
|
|
|
nu->bezt= newbezt;
|
|
|
|
newbezt+= nu->pntsu;
|
|
|
|
BEZ_SEL(newbezt);
|
|
|
|
newbezt->h2= newbezt->h1;
|
|
|
|
bezt= nu->bezt+nu->pntsu-1;
|
|
|
|
}
|
|
|
|
else bezt= 0;
|
|
|
|
|
|
|
|
if(bezt) {
|
|
|
|
nu->pntsu++;
|
|
|
|
|
|
|
|
if(mode=='e') {
|
|
|
|
VECCOPY(newbezt->vec[0], bezt->vec[0]);
|
|
|
|
VECCOPY(newbezt->vec[1], bezt->vec[1]);
|
|
|
|
VECCOPY(newbezt->vec[2], bezt->vec[2]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
curs= give_cursor(scene, v3d);
|
|
|
|
|
|
|
|
VECCOPY(newbezt->vec[1], curs);
|
|
|
|
VecSubf(newbezt->vec[1],newbezt->vec[1], obedit->obmat[3]);
|
|
|
|
Mat3MulVecfl(imat,newbezt->vec[1]);
|
|
|
|
VecSubf(temp, newbezt->vec[1],temp);
|
|
|
|
VecAddf(newbezt->vec[0], bezt->vec[0],temp);
|
|
|
|
VecAddf(newbezt->vec[2], bezt->vec[2],temp);
|
|
|
|
calchandlesNurb(nu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nu->pntsv==1) {
|
|
|
|
/* which b-point? */
|
|
|
|
if(bp== nu->bp) { /* first */
|
|
|
|
bp->f1= 0;
|
|
|
|
newbp =
|
|
|
|
(BPoint*)MEM_callocN((nu->pntsu+1) * sizeof(BPoint), "addvert_Nurb3");
|
|
|
|
memcpy(newbp+1, bp, nu->pntsu*sizeof(BPoint));
|
|
|
|
*newbp= *bp;
|
|
|
|
newbp->f1= 1;
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= newbp;
|
|
|
|
bp= newbp + 1;
|
|
|
|
}
|
|
|
|
else if(bp== (nu->bp+nu->pntsu-1)) { /* last */
|
|
|
|
bp->f1= 0;
|
|
|
|
newbp =
|
|
|
|
(BPoint*)MEM_callocN((nu->pntsu+1) * sizeof(BPoint), "addvert_Nurb4");
|
|
|
|
memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint));
|
|
|
|
*(newbp+nu->pntsu)= *bp;
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= newbp;
|
|
|
|
newbp+= nu->pntsu;
|
|
|
|
newbp->f1= 1;
|
|
|
|
bp= newbp - 1;
|
|
|
|
}
|
|
|
|
else bp= 0;
|
|
|
|
|
|
|
|
if(bp) {
|
|
|
|
nu->pntsu++;
|
|
|
|
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
|
|
|
|
if(mode=='e') {
|
|
|
|
VECCOPY(newbp->vec, bp->vec);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
curs= give_cursor(scene, v3d);
|
|
|
|
|
|
|
|
VECCOPY(newbp->vec, curs);
|
|
|
|
VecSubf(newbp->vec, newbp->vec, obedit->obmat[3]);
|
|
|
|
Mat3MulVecfl(imat,newbp->vec);
|
|
|
|
newbp->vec[3]= 1.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX retopo_do_all();
|
|
|
|
|
|
|
|
test2DNurb(nu);
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
|
|
|
|
if(mode=='e') {
|
|
|
|
// XXX BIF_TransformSetUndo("Extrude");
|
|
|
|
// initTransform(TFM_TRANSLATION, CTX_NO_PET);
|
|
|
|
// Transform();
|
|
|
|
}
|
|
|
|
// else while(get_mbut()&R_MOUSE) BIF_wait_for_statechange();
|
|
|
|
|
|
|
|
if(mode!='e') {
|
|
|
|
/* dependencies with other objects, should become event */
|
|
|
|
BIF_undo_push("Add vertex");
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void extrude_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
int ok= 0;
|
|
|
|
|
|
|
|
if(obedit && obedit->type==OB_SURF) {
|
|
|
|
|
|
|
|
/* first test: curve? */
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if(nu->pntsv==1 && isNurbsel_count(nu)==1 ) break;
|
|
|
|
}
|
|
|
|
if(nu) {
|
|
|
|
addvert_Nurb(scene, 'e');
|
|
|
|
} else {
|
|
|
|
ok= extrudeflagNurb(editnurb, 1); /* '1'= flag */
|
|
|
|
|
|
|
|
if(ok) {
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
// XXX BIF_TransformSetUndo("Extrude");
|
|
|
|
// initTransform(TFM_TRANSLATION, CTX_NO_PET);
|
|
|
|
// Transform();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void makecyclicNurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
float *fp;
|
|
|
|
int a, b, cyclmode=0;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if( nu->pntsu>1 || nu->pntsv>1) {
|
|
|
|
if( (nu->type & 7)==0 ) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
if( bp->f1 & SELECT ) {
|
|
|
|
if(nu->flagu & CU_CYCLIC) nu->flagu &= ~CU_CYCLIC;
|
|
|
|
else nu->flagu |= CU_CYCLIC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( (nu->type & 7)==CU_BEZIER ) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
while(a--) {
|
|
|
|
if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
|
|
|
|
if(nu->flagu & CU_CYCLIC) nu->flagu &= ~CU_CYCLIC;
|
|
|
|
else nu->flagu |= CU_CYCLIC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
calchandlesNurb(nu);
|
|
|
|
}
|
|
|
|
else if(nu->pntsv==1 && (nu->type & 7)==CU_NURBS) {
|
|
|
|
if (nu->knotsu) { /* if check_valid_nurb_u fails the knotsu can be NULL */
|
|
|
|
a= nu->pntsu;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
if( bp->f1 & SELECT ) {
|
|
|
|
if(nu->flagu & CU_CYCLIC) nu->flagu &= ~CU_CYCLIC;
|
|
|
|
else {
|
|
|
|
nu->flagu |= CU_CYCLIC;
|
|
|
|
nu->flagu &= ~2; /* endpoint flag, fixme */
|
|
|
|
fp= MEM_mallocN(sizeof(float)*KNOTSU(nu), "makecyclicN");
|
|
|
|
b= (nu->orderu+nu->pntsu);
|
|
|
|
memcpy(fp, nu->knotsu, sizeof(float)*b);
|
|
|
|
MEM_freeN(nu->knotsu);
|
|
|
|
nu->knotsu= fp;
|
|
|
|
|
|
|
|
makeknots(nu, 1, 0); /* 1==u 0==uniform */
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nu->type==CU_NURBS) {
|
|
|
|
if(cyclmode==0) {
|
|
|
|
cyclmode= pupmenu("Toggle %t|cyclic U%x1|cyclic V%x2");
|
|
|
|
if(cyclmode < 1) return;
|
|
|
|
}
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
|
|
|
|
if( bp->f1 & SELECT) {
|
|
|
|
if(cyclmode==1 && nu->pntsu>1) {
|
|
|
|
if(nu->flagu & CU_CYCLIC) nu->flagu &= ~CU_CYCLIC;
|
|
|
|
else {
|
|
|
|
nu->flagu |= CU_CYCLIC;
|
|
|
|
if (check_valid_nurb_u(nu)) {
|
|
|
|
fp= MEM_mallocN(sizeof(float)*KNOTSU(nu), "makecyclicN");
|
|
|
|
b= (nu->orderu+nu->pntsu);
|
|
|
|
if (nu->knotsu) { /* null if check_valid_nurb_u failed before but is valid now */
|
|
|
|
memcpy(fp, nu->knotsu, sizeof(float)*b);
|
|
|
|
MEM_freeN(nu->knotsu);
|
|
|
|
}
|
|
|
|
nu->knotsu= fp;
|
|
|
|
|
|
|
|
makeknots(nu, 1, 0); /* 1==u 0==uniform */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(cyclmode==2 && nu->pntsv>1) {
|
|
|
|
if(nu->flagv & 1) nu->flagv--;
|
|
|
|
else {
|
|
|
|
nu->flagv++;
|
|
|
|
if (check_valid_nurb_v(nu)) {
|
|
|
|
fp= MEM_mallocN(sizeof(float)*KNOTSV(nu), "makecyclicN");
|
|
|
|
b= (nu->orderv+nu->pntsv);
|
|
|
|
if (nu->knotsv) { /* null if check_valid_nurb_v failed before but is valid now */
|
|
|
|
memcpy(fp, nu->knotsv, sizeof(float)*b);
|
|
|
|
MEM_freeN(nu->knotsv);
|
|
|
|
}
|
|
|
|
nu->knotsv= fp;
|
|
|
|
|
|
|
|
makeknots(nu, 2, 0); /* 2==v 0==uniform */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
BIF_undo_push("Cyclic");
|
|
|
|
}
|
|
|
|
|
|
|
|
void selectconnected_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
ViewContext vc;
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
short mval[2], shift= 0; // XXX
|
|
|
|
|
|
|
|
|
|
|
|
findnearestNurbvert(&vc, 1, mval, &nu, &bezt, &bp);
|
|
|
|
if(bezt) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
while(a--) {
|
|
|
|
if(shift) select_beztriple(bezt, DESELECT, 1, VISIBLE);
|
|
|
|
else select_beztriple(bezt, SELECT, 1, VISIBLE);
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(bp) {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
if(shift) select_bpoint(bp, DESELECT, 1, VISIBLE);
|
|
|
|
else select_bpoint(bp, SELECT, 1, VISIBLE);
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("Select connected");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void selectrow_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Curve *cu= obedit->data;
|
|
|
|
static BPoint *last=0;
|
|
|
|
static int direction=0;
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp;
|
|
|
|
int u = 0, v = 0, a, b, ok=0;
|
|
|
|
|
|
|
|
if(editnurb->first==0) return;
|
|
|
|
if(obedit==NULL || obedit->type!=OB_SURF) return;
|
|
|
|
if(cu->lastselbp==NULL) return;
|
|
|
|
|
|
|
|
/* find the correct nurb and toggle with u of v */
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
bp= nu->bp;
|
|
|
|
for(v=0; v<nu->pntsv; v++) {
|
|
|
|
for(u=0; u<nu->pntsu; u++, bp++) {
|
|
|
|
if(bp==cu->lastselbp) {
|
|
|
|
if(bp->f1 & SELECT) {
|
|
|
|
ok= 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(ok) break;
|
|
|
|
}
|
|
|
|
if(ok) {
|
|
|
|
if(last==cu->lastselbp) {
|
|
|
|
direction= 1-direction;
|
|
|
|
setflagsNurb(editnurb, 0);
|
|
|
|
}
|
|
|
|
last= cu->lastselbp;
|
|
|
|
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0; a<nu->pntsv; a++) {
|
|
|
|
for(b=0; b<nu->pntsu; b++, bp++) {
|
|
|
|
if(direction) {
|
|
|
|
if(a==v) select_bpoint(bp, SELECT, 1, VISIBLE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(b==u) select_bpoint(bp, SELECT, 1, VISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BIF_undo_push("Select Row");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void select_next_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
|
|
|
|
if(obedit==0) return;
|
|
|
|
|
|
|
|
select_adjacent_cp(editnurb, 1, 0, SELECT);
|
|
|
|
|
|
|
|
BIF_undo_push("Select Next");
|
|
|
|
}
|
|
|
|
|
|
|
|
void select_prev_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
|
|
|
|
if(obedit==NULL) return;
|
|
|
|
|
|
|
|
select_adjacent_cp(editnurb, -1, 0, SELECT);
|
|
|
|
|
|
|
|
BIF_undo_push("Select Previous");
|
|
|
|
}
|
|
|
|
|
|
|
|
void select_more_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp, *tempbp;
|
|
|
|
int a;
|
|
|
|
short sel= 0;
|
|
|
|
short *selbpoints;
|
|
|
|
|
|
|
|
if(obedit==0) return;
|
|
|
|
|
|
|
|
/* note that NURBS surface is a special case because we mimic */
|
|
|
|
/* the behaviour of "select more" of mesh tools. */
|
|
|
|
/* The algorithm is designed to work in planar cases so it */
|
|
|
|
/* may not be optimal always (example: end of NURBS sphere) */
|
|
|
|
if(obedit->type==OB_SURF) {
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
selbpoints= MEM_callocN(sizeof(short)*a-nu->pntsu, "selectlist");
|
|
|
|
while(a > 0) {
|
|
|
|
if((selbpoints[a]!=1) && (bp->hide==0) && (bp->f1 & SELECT)) {
|
|
|
|
/* upper control point */
|
|
|
|
if(a%nu->pntsu != 0) {
|
|
|
|
tempbp= bp-1;
|
|
|
|
if(!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, 1, VISIBLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* left control point. select only if it is not selected already */
|
|
|
|
if(a-nu->pntsu > 0) {
|
|
|
|
sel= 0;
|
|
|
|
tempbp= bp+nu->pntsu;
|
|
|
|
if(!(tempbp->f1 & SELECT)) sel= select_bpoint(tempbp, SELECT, 1, VISIBLE);
|
|
|
|
/* make sure selected bpoint is discarded */
|
|
|
|
if(sel == 1) selbpoints[a-nu->pntsu]= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* right control point */
|
|
|
|
if(a+nu->pntsu < nu->pntsu*nu->pntsv) {
|
|
|
|
tempbp= bp-nu->pntsu;
|
|
|
|
if(!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, 1, VISIBLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* lower control point. skip next bp in case selection was made */
|
|
|
|
if(a%nu->pntsu != 1) {
|
|
|
|
sel= 0;
|
|
|
|
tempbp= bp+1;
|
|
|
|
if(!(tempbp->f1 & 1)) sel= select_bpoint(tempbp, SELECT, 1, VISIBLE);
|
|
|
|
if(sel) {
|
|
|
|
bp++;
|
|
|
|
a--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bp++;
|
|
|
|
a--;
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(selbpoints);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
select_adjacent_cp(editnurb, 1, 0, SELECT);
|
|
|
|
select_adjacent_cp(editnurb, -1, 0, SELECT);
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("Select More");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* basic method: deselect if control point doesn't have all neighbours selected */
|
|
|
|
void select_less_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BPoint *bp;
|
|
|
|
BezTriple *bezt;
|
|
|
|
int a;
|
|
|
|
short sel= 0, lastsel= 0;
|
|
|
|
short *selbpoints;
|
|
|
|
|
|
|
|
if(obedit==0) return;
|
|
|
|
|
|
|
|
if(obedit->type==OB_SURF) {
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
selbpoints= MEM_callocN(sizeof(short)*a, "selectlist");
|
|
|
|
while(a--) {
|
|
|
|
if((bp->hide==0) && (bp->f1 & SELECT)) {
|
|
|
|
sel= 0;
|
|
|
|
|
|
|
|
/* check if neighbours have been selected */
|
|
|
|
/* edges of surface are an exception */
|
|
|
|
if((a+1)%nu->pntsu==0) sel++;
|
|
|
|
else {
|
|
|
|
bp--;
|
|
|
|
if((selbpoints[a+1]==1) || ((bp->hide==0) && (bp->f1 & SELECT))) sel++;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((a+1)%nu->pntsu==1) sel++;
|
|
|
|
else {
|
|
|
|
bp++;
|
|
|
|
if((bp->hide==0) && (bp->f1 & SELECT)) sel++;
|
|
|
|
bp--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(a+1 > nu->pntsu*nu->pntsv-nu->pntsu) sel++;
|
|
|
|
else {
|
|
|
|
bp-=nu->pntsu;
|
|
|
|
if((selbpoints[a+nu->pntsu]==1) || ((bp->hide==0) && (bp->f1 & SELECT))) sel++;
|
|
|
|
bp+=nu->pntsu;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(a < nu->pntsu) sel++;
|
|
|
|
else {
|
|
|
|
bp+=nu->pntsu;
|
|
|
|
if((bp->hide==0) && (bp->f1 & SELECT)) sel++;
|
|
|
|
bp-=nu->pntsu;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(sel!=4) {
|
|
|
|
select_bpoint(bp, DESELECT, 1, VISIBLE);
|
|
|
|
selbpoints[a]= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else lastsel= 0;
|
|
|
|
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(selbpoints);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
lastsel=0;
|
|
|
|
/* check what type of curve/nurb it is */
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
while(a--) {
|
|
|
|
if((bezt->hide==0) && (bezt->f2 & SELECT)) {
|
|
|
|
if(lastsel==1) sel= 1;
|
|
|
|
else sel= 0;
|
|
|
|
|
|
|
|
/* check if neighbours have been selected */
|
|
|
|
/* first and last are exceptions */
|
|
|
|
if(a==nu->pntsu-1) sel++;
|
|
|
|
else {
|
|
|
|
bezt--;
|
|
|
|
if((bezt->hide==0) && (bezt->f2 & SELECT)) sel++;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(a==0) sel++;
|
|
|
|
else {
|
|
|
|
bezt++;
|
|
|
|
if((bezt->hide==0) && (bezt->f2 & SELECT)) sel++;
|
|
|
|
bezt--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(sel!=2) {
|
|
|
|
select_beztriple(bezt, DESELECT, 1, VISIBLE);
|
|
|
|
lastsel= 1;
|
|
|
|
}
|
|
|
|
else lastsel= 0;
|
|
|
|
}
|
|
|
|
else lastsel= 0;
|
|
|
|
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
if((lastsel==0) && (bp->hide==0) && (bp->f1 & SELECT)) {
|
|
|
|
if(lastsel!=0) sel= 1;
|
|
|
|
else sel= 0;
|
|
|
|
|
|
|
|
/* first and last are exceptions */
|
|
|
|
if(a==nu->pntsu*nu->pntsv-1) sel++;
|
|
|
|
else {
|
|
|
|
bp--;
|
|
|
|
if((bp->hide==0) && (bp->f1 & SELECT)) sel++;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(a==0) sel++;
|
|
|
|
else {
|
|
|
|
bp++;
|
|
|
|
if((bp->hide==0) && (bp->f1 & SELECT)) sel++;
|
|
|
|
bp--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(sel!=2) {
|
|
|
|
select_bpoint(bp, DESELECT, 1, VISIBLE);
|
|
|
|
lastsel= 1;
|
|
|
|
}
|
|
|
|
else lastsel= 0;
|
|
|
|
}
|
|
|
|
else lastsel= 0;
|
|
|
|
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("Select Less");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this function could be moved elsewhere as it can be reused in other parts of the source needing randomized list */
|
|
|
|
/* returns list containing -1 in indices that have been left out of the list. otherwise index contains reference */
|
|
|
|
/* to next index. basically *list contains a linked list */
|
|
|
|
static void generate_pickable_list(int *list, int size, int pickamount)
|
|
|
|
{
|
|
|
|
int i, j, removable;
|
|
|
|
|
|
|
|
BLI_srand( BLI_rand() ); /* random seed */
|
|
|
|
|
|
|
|
/* generate list in form 0->1, 1->2, 2->3, ... i-2->i-1, i->0 */
|
|
|
|
for(i=0; i<size; i++) {
|
|
|
|
if(i == size-1) list[i]= 0;
|
|
|
|
else list[i]= i+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i=0; i<size-pickamount; i++) {
|
|
|
|
removable= floor(BLI_frand()*(size-1)+0.5); /* with rounding. frand returns [0,1] */
|
|
|
|
|
|
|
|
/* seek proper item as the one randomly selected might not be appropriate */
|
|
|
|
for(j=0; j<size; j++, removable++) {
|
|
|
|
if(list[removable] != -1) break;
|
|
|
|
if(removable == size-1) removable= -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* pick unwanted item out of the list */
|
|
|
|
list[list[removable]]= -1; /* mark former last as invalid */
|
|
|
|
|
|
|
|
if(list[removable] == size-1) list[removable]= 0;
|
|
|
|
else list[removable]= list[removable]+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void select_random_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
static short randfac= 50;
|
|
|
|
int amounttoselect, amountofcps, a, i, k= 0;
|
|
|
|
int *itemstobeselected;
|
|
|
|
|
|
|
|
if(!obedit) return;
|
|
|
|
|
|
|
|
if(!button(&randfac,0, 100,"Percentage:")) return;
|
|
|
|
|
|
|
|
if(randfac == 0) return;
|
|
|
|
|
|
|
|
amountofcps= count_curveverts_without_handles(editnurb);
|
|
|
|
itemstobeselected= MEM_callocN(sizeof(int) * amountofcps, "selectitems");
|
|
|
|
amounttoselect= floor(randfac * amountofcps / 100 + 0.5);
|
|
|
|
generate_pickable_list(itemstobeselected, amountofcps, amounttoselect);
|
|
|
|
|
|
|
|
/* select elements */
|
|
|
|
for(i=1, nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
a= nu->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
if(itemstobeselected[k] != -1) select_beztriple(bezt, SELECT, 1, VISIBLE);
|
|
|
|
k++;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
while(a--) {
|
|
|
|
if(itemstobeselected[k] != -1) select_bpoint(bp, SELECT, 1, VISIBLE);
|
|
|
|
k++;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(itemstobeselected);
|
|
|
|
|
|
|
|
BIF_undo_push("Select Random");
|
|
|
|
}
|
|
|
|
|
|
|
|
void select_every_nth_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
static short nfac= 2;
|
|
|
|
|
|
|
|
if(!obedit) return;
|
|
|
|
|
|
|
|
if(!button(&nfac, 2, 25,"N:")) return;
|
|
|
|
|
|
|
|
select_adjacent_cp(editnurb, nfac, 1, SELECT);
|
|
|
|
select_adjacent_cp(editnurb, -nfac, 1, SELECT);
|
|
|
|
|
|
|
|
BIF_undo_push("Select Every Nth");
|
|
|
|
}
|
|
|
|
|
|
|
|
void adduplicate_nurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX use context
|
|
|
|
View3D *v3d= NULL; // XXX
|
|
|
|
|
|
|
|
if(v3d==0 || (v3d->lay & obedit->lay)==0 ) return;
|
|
|
|
|
|
|
|
adduplicateflagNurb(scene, 1);
|
|
|
|
|
|
|
|
// XXX BIF_TransformSetUndo("Add Duplicate");
|
|
|
|
// initTransform(TFM_TRANSLATION, CTX_NO_PET);
|
|
|
|
// Transform();
|
|
|
|
}
|
|
|
|
|
|
|
|
void delNurb(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
View3D *v3d= NULL; // XXX
|
|
|
|
Nurb *nu, *next, *nu1;
|
|
|
|
BezTriple *bezt, *bezt1, *bezt2;
|
|
|
|
BPoint *bp, *bp1, *bp2;
|
|
|
|
int a;
|
|
|
|
short event, cut = 0;
|
|
|
|
|
|
|
|
if(obedit==0 ) return;
|
|
|
|
if(v3d==0 || (v3d->lay & obedit->lay)==0 ) return;
|
|
|
|
|
|
|
|
if(obedit->type==OB_SURF) event= pupmenu("Erase %t|Selected%x0|All%x2");
|
|
|
|
else event= pupmenu("Erase %t|Selected%x0|Segment%x1|All%x2");
|
|
|
|
|
|
|
|
if(event== -1) return;
|
|
|
|
|
|
|
|
if(obedit->type==OB_SURF) {
|
|
|
|
if(event==0) deleteflagNurb(scene, 1);
|
|
|
|
else freeNurblist(editnurb);
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
BIF_undo_push("Delete");
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(event==0) {
|
|
|
|
/* first loop, can we remove entire pieces? */
|
|
|
|
nu= editnurb->first;
|
|
|
|
while(nu) {
|
|
|
|
next= nu->next;
|
|
|
|
if( (nu->type & 7)==CU_BEZIER ) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
a= nu->pntsu;
|
|
|
|
if(a) {
|
|
|
|
while(a) {
|
|
|
|
if( BEZSELECTED_HIDDENHANDLES(bezt) );
|
|
|
|
else break;
|
|
|
|
a--;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
if(a==0) {
|
|
|
|
BLI_remlink(editnurb, nu);
|
|
|
|
freeNurb(nu); nu= NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
if(a) {
|
|
|
|
while(a) {
|
|
|
|
if(bp->f1 & SELECT);
|
|
|
|
else break;
|
|
|
|
a--;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
if(a==0) {
|
|
|
|
BLI_remlink(editnurb, nu);
|
|
|
|
freeNurb(nu); nu= NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Never allow the order to exceed the number of points
|
|
|
|
- note, this is ok but changes unselected nurbs, disable for now */
|
|
|
|
/*
|
|
|
|
if ((nu!= NULL) && ((nu->type & 7)==CU_NURBS)) {
|
|
|
|
clamp_nurb_order_u(nu);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
nu= next;
|
|
|
|
}
|
|
|
|
/* 2nd loop, delete small pieces: just for curves */
|
|
|
|
nu= editnurb->first;
|
|
|
|
while(nu) {
|
|
|
|
next= nu->next;
|
|
|
|
event= 0;
|
|
|
|
if( (nu->type & 7)==CU_BEZIER ) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
for(a=0;a<nu->pntsu;a++) {
|
|
|
|
if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
|
|
|
|
memmove(bezt, bezt+1, (nu->pntsu-a-1)*sizeof(BezTriple));
|
|
|
|
nu->pntsu--;
|
|
|
|
a--;
|
|
|
|
event= 1;
|
|
|
|
}
|
|
|
|
else bezt++;
|
|
|
|
}
|
|
|
|
if(event) {
|
|
|
|
bezt1 =
|
|
|
|
(BezTriple*)MEM_mallocN((nu->pntsu) * sizeof(BezTriple), "delNurb");
|
|
|
|
memcpy(bezt1, nu->bezt, (nu->pntsu)*sizeof(BezTriple) );
|
|
|
|
MEM_freeN(nu->bezt);
|
|
|
|
nu->bezt= bezt1;
|
|
|
|
calchandlesNurb(nu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nu->pntsv==1) {
|
|
|
|
bp= nu->bp;
|
|
|
|
|
|
|
|
for(a=0;a<nu->pntsu;a++) {
|
|
|
|
if( bp->f1 & SELECT ) {
|
|
|
|
memmove(bp, bp+1, (nu->pntsu-a-1)*sizeof(BPoint));
|
|
|
|
nu->pntsu--;
|
|
|
|
a--;
|
|
|
|
event= 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(event) {
|
|
|
|
bp1 = (BPoint*)MEM_mallocN(nu->pntsu * sizeof(BPoint), "delNurb2");
|
|
|
|
memcpy(bp1, nu->bp, (nu->pntsu)*sizeof(BPoint) );
|
|
|
|
MEM_freeN(nu->bp);
|
|
|
|
nu->bp= bp1;
|
|
|
|
|
|
|
|
/* Never allow the order to exceed the number of points\
|
|
|
|
- note, this is ok but changes unselected nurbs, disable for now */
|
|
|
|
/*
|
|
|
|
if ((nu->type & 7)==CU_NURBS) {
|
|
|
|
clamp_nurb_order_u(nu);
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
}
|
|
|
|
nu= next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(event==1) { /* erase segment */
|
|
|
|
/* find the 2 selected points */
|
|
|
|
bezt1= bezt2= 0;
|
|
|
|
bp1= bp2= 0;
|
|
|
|
nu= editnurb->first;
|
|
|
|
nu1= 0;
|
|
|
|
while(nu) {
|
|
|
|
next= nu->next;
|
|
|
|
if( (nu->type & 7)==CU_BEZIER ) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
for(a=0; a<nu->pntsu-1; a++) {
|
|
|
|
if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
|
|
|
|
bezt1= bezt;
|
|
|
|
bezt2= bezt+1;
|
|
|
|
if( (bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT) ) ;
|
|
|
|
else { /* maybe do not make cyclic */
|
|
|
|
if(a==0 && (nu->flagu & CU_CYCLIC) ) {
|
|
|
|
bezt2= bezt+(nu->pntsu-1);
|
|
|
|
if( (bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT) ) {
|
|
|
|
nu->flagu &= ~CU_CYCLIC;
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
BIF_undo_push("Delete");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cut= a;
|
|
|
|
nu1= nu;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nu->pntsv==1) {
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0; a<nu->pntsu-1; a++) {
|
|
|
|
if( bp->f1 & SELECT ) {
|
|
|
|
bp1= bp;
|
|
|
|
bp2= bp+1;
|
|
|
|
if( bp2->f1 & 1 ) ;
|
|
|
|
else { /* maybe do not make cyclic */
|
|
|
|
if(a==0 && (nu->flagu & CU_CYCLIC) ) {
|
|
|
|
bp2= bp+(nu->pntsu-1);
|
|
|
|
if( bp2->f1 & SELECT ) {
|
|
|
|
nu->flagu &= ~CU_CYCLIC;
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
BIF_undo_push("Delete");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cut= a;
|
|
|
|
nu1= nu;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(nu1) break;
|
|
|
|
|
|
|
|
nu= nu->next;
|
|
|
|
}
|
|
|
|
if(nu1) {
|
|
|
|
if(bezt1) {
|
|
|
|
if(nu1->pntsu==2) { /* remove completely */
|
|
|
|
BLI_remlink(editnurb, nu);
|
|
|
|
freeNurb(nu); nu = NULL;
|
|
|
|
}
|
|
|
|
else if(nu1->flagu & CU_CYCLIC) { /* cyclic */
|
|
|
|
bezt =
|
|
|
|
(BezTriple*)MEM_mallocN((cut+1) * sizeof(BezTriple), "delNurb1");
|
|
|
|
memcpy(bezt, nu1->bezt,(cut+1)*sizeof(BezTriple));
|
|
|
|
a= nu1->pntsu-cut-1;
|
|
|
|
memcpy(nu1->bezt, bezt2, a*sizeof(BezTriple));
|
|
|
|
memcpy(nu1->bezt+a, bezt, (cut+1)*sizeof(BezTriple));
|
|
|
|
nu1->flagu &= ~CU_CYCLIC;
|
|
|
|
MEM_freeN(bezt);
|
|
|
|
calchandlesNurb(nu);
|
|
|
|
}
|
|
|
|
else { /* add new curve */
|
|
|
|
|
|
|
|
/* seems to be an error here... but where? (a can become zero) */
|
|
|
|
|
|
|
|
nu =
|
|
|
|
(Nurb*)MEM_mallocN(sizeof(Nurb), "delNurb2");
|
|
|
|
memcpy(nu, nu1, sizeof(Nurb));
|
|
|
|
BLI_addtail(editnurb, nu);
|
|
|
|
nu->bezt =
|
|
|
|
(BezTriple*)MEM_mallocN((cut+1) * sizeof(BezTriple), "delNurb3");
|
|
|
|
memcpy(nu->bezt, nu1->bezt,(cut+1)*sizeof(BezTriple));
|
|
|
|
a= nu1->pntsu-cut-1;
|
|
|
|
|
|
|
|
bezt =
|
|
|
|
(BezTriple*)MEM_mallocN(a * sizeof(BezTriple), "delNurb4");
|
|
|
|
memcpy(bezt, nu1->bezt+cut+1,a*sizeof(BezTriple));
|
|
|
|
MEM_freeN(nu1->bezt);
|
|
|
|
nu1->bezt= bezt;
|
|
|
|
nu1->pntsu= a;
|
|
|
|
nu->pntsu= cut+1;
|
|
|
|
|
|
|
|
|
|
|
|
calchandlesNurb(nu);
|
|
|
|
calchandlesNurb(nu1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(bp1) {
|
|
|
|
if(nu1->pntsu==2) { /* remove completely */
|
|
|
|
BLI_remlink(editnurb, nu);
|
|
|
|
freeNurb(nu); nu= NULL;
|
|
|
|
}
|
|
|
|
else if(nu1->flagu & CU_CYCLIC) { /* cyclic */
|
|
|
|
bp =
|
|
|
|
(BPoint*)MEM_mallocN((cut+1) * sizeof(BPoint), "delNurb5");
|
|
|
|
memcpy(bp, nu1->bp,(cut+1)*sizeof(BPoint));
|
|
|
|
a= nu1->pntsu-cut-1;
|
|
|
|
memcpy(nu1->bp, bp2, a*sizeof(BPoint));
|
|
|
|
memcpy(nu1->bp+a, bp, (cut+1)*sizeof(BPoint));
|
|
|
|
nu1->flagu &= ~CU_CYCLIC;
|
|
|
|
MEM_freeN(bp);
|
|
|
|
}
|
|
|
|
else { /* add new curve */
|
|
|
|
nu = (Nurb*)MEM_mallocN(sizeof(Nurb), "delNurb6");
|
|
|
|
memcpy(nu, nu1, sizeof(Nurb));
|
|
|
|
BLI_addtail(editnurb, nu);
|
|
|
|
nu->bp =
|
|
|
|
(BPoint*)MEM_mallocN((cut+1) * sizeof(BPoint), "delNurb7");
|
|
|
|
memcpy(nu->bp, nu1->bp,(cut+1)*sizeof(BPoint));
|
|
|
|
a= nu1->pntsu-cut-1;
|
|
|
|
bp =
|
|
|
|
(BPoint*)MEM_mallocN(a * sizeof(BPoint), "delNurb8");
|
|
|
|
memcpy(bp, nu1->bp+cut+1,a*sizeof(BPoint));
|
|
|
|
MEM_freeN(nu1->bp);
|
|
|
|
nu1->bp= bp;
|
|
|
|
nu1->pntsu= a;
|
|
|
|
nu->pntsu= cut+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(event==2) {
|
|
|
|
freeNurblist(editnurb);
|
|
|
|
}
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
|
|
|
|
BIF_undo_push("Delete");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void nurb_set_smooth(Scene *scene, short event)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
|
|
|
|
if(obedit==0) return;
|
|
|
|
|
|
|
|
if(obedit->type != OB_CURVE) return;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if(isNurbsel(nu)) {
|
|
|
|
if(event==1) nu->flag |= CU_SMOOTH;
|
|
|
|
else if(event==0) nu->flag &= ~CU_SMOOTH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
|
|
|
|
if(event==1) BIF_undo_push("Set Smooth");
|
|
|
|
else if(event==0) BIF_undo_push("Set Solid");
|
|
|
|
}
|
|
|
|
|
|
|
|
int join_curve(Scene *scene, int type)
|
|
|
|
{
|
|
|
|
View3D *v3d= NULL; // XXX
|
|
|
|
Base *base, *nextb;
|
|
|
|
Object *ob;
|
|
|
|
Curve *cu;
|
|
|
|
Nurb *nu, *newnu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
ListBase tempbase;
|
|
|
|
float imat[4][4], cmat[4][4];
|
|
|
|
int a;
|
|
|
|
|
|
|
|
ob= OBACT;
|
|
|
|
if (object_data_is_libdata(ob)) {
|
|
|
|
error_libdata();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!v3d || ob->type!=type) return 0;
|
|
|
|
if(ob->lay & v3d->lay); else return 0;
|
|
|
|
tempbase.first= tempbase.last= 0;
|
|
|
|
|
|
|
|
/* trasnform all selected curves inverse in obact */
|
|
|
|
Mat4Invert(imat, ob->obmat);
|
|
|
|
|
|
|
|
base= FIRSTBASE;
|
|
|
|
while(base) {
|
|
|
|
nextb= base->next;
|
|
|
|
if (TESTBASE(v3d, base)) {
|
|
|
|
if(base->object->type==type) {
|
|
|
|
if(base->object != ob) {
|
|
|
|
|
|
|
|
cu= base->object->data;
|
|
|
|
|
|
|
|
if(cu->nurb.first) {
|
|
|
|
/* watch it: switch order here really goes wrong */
|
|
|
|
Mat4MulMat4(cmat, base->object->obmat, imat);
|
|
|
|
|
|
|
|
nu= cu->nurb.first;
|
|
|
|
while(nu) {
|
|
|
|
newnu= duplicateNurb(nu);
|
|
|
|
BLI_addtail(&tempbase, newnu);
|
|
|
|
|
|
|
|
if( (bezt= newnu->bezt) ) {
|
|
|
|
a= newnu->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
Mat4MulVecfl(cmat, bezt->vec[0]);
|
|
|
|
Mat4MulVecfl(cmat, bezt->vec[1]);
|
|
|
|
Mat4MulVecfl(cmat, bezt->vec[2]);
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( (bp= newnu->bp) ) {
|
|
|
|
a= newnu->pntsu*nu->pntsv;
|
|
|
|
while(a--) {
|
|
|
|
Mat4MulVecfl(cmat, bp->vec);
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nu= nu->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ED_base_object_free_and_unlink(scene, base);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
base= nextb;
|
|
|
|
}
|
|
|
|
|
|
|
|
cu= ob->data;
|
|
|
|
addlisttolist(&cu->nurb, &tempbase);
|
|
|
|
|
|
|
|
DAG_scene_sort(scene); // because we removed object(s), call before editmode!
|
|
|
|
|
|
|
|
// XXX Context
|
|
|
|
ED_object_enter_editmode(NULL, EM_WAITCURSOR);
|
|
|
|
ED_object_exit_editmode(NULL, EM_FREEDATA|EM_WAITCURSOR);
|
|
|
|
|
|
|
|
BIF_undo_push("Join");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-01-26 15:23:29 +00:00
|
|
|
Nurb *addNurbprim(bContext *C, int type, int newname)
|
2009-01-14 12:26:45 +00:00
|
|
|
{
|
2009-01-26 15:23:29 +00:00
|
|
|
static int xzproj= 0; /* this function calls itself... */
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-01-14 12:26:45 +00:00
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
2009-01-26 15:23:29 +00:00
|
|
|
View3D *v3d= CTX_wm_view3d(C);
|
|
|
|
RegionView3D *rv3d= CTX_wm_region_view3d(C);
|
2009-01-14 12:26:45 +00:00
|
|
|
Nurb *nu = NULL;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
float *curs, cent[3],vec[3],imat[3][3],mat[3][3];
|
|
|
|
float fac,cmat[3][3], grid;
|
2009-01-26 15:23:29 +00:00
|
|
|
int a, b, cutype, stype;
|
|
|
|
|
|
|
|
cutype= type & CU_TYPE; // poly, bezier, nurbs, etc
|
|
|
|
stype= type & CU_PRIMITIVE;
|
2009-01-14 12:26:45 +00:00
|
|
|
|
|
|
|
if (v3d) grid = v3d->grid;
|
|
|
|
else grid = 1.0;
|
|
|
|
|
|
|
|
/* imat and center and size */
|
|
|
|
if(obedit) {
|
|
|
|
|
|
|
|
Mat3CpyMat4(mat, obedit->obmat);
|
|
|
|
curs= give_cursor(scene, v3d);
|
|
|
|
VECCOPY(cent, curs);
|
|
|
|
cent[0]-= obedit->obmat[3][0];
|
|
|
|
cent[1]-= obedit->obmat[3][1];
|
|
|
|
cent[2]-= obedit->obmat[3][2];
|
|
|
|
|
2009-01-26 15:23:29 +00:00
|
|
|
if (rv3d) {
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
if ( !(newname) || U.flag & USER_ADD_VIEWALIGNED)
|
|
|
|
Mat3CpyMat4(imat, rv3d->viewmat);
|
2009-01-14 12:26:45 +00:00
|
|
|
else Mat3One(imat);
|
|
|
|
Mat3MulVecfl(imat, cent);
|
|
|
|
Mat3MulMat3(cmat, imat, mat);
|
|
|
|
Mat3Inv(imat, cmat);
|
|
|
|
}
|
|
|
|
setflagsNurb(editnurb, 0);
|
|
|
|
}
|
|
|
|
else {
|
2009-01-26 15:23:29 +00:00
|
|
|
return NULL;
|
2009-01-14 12:26:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-26 15:23:29 +00:00
|
|
|
/* these types call this function to return a Nurb */
|
|
|
|
if (stype!=CU_PRIM_TUBE && stype!=CU_PRIM_DONUT) {
|
2009-01-14 12:26:45 +00:00
|
|
|
nu = (Nurb*)MEM_callocN(sizeof(Nurb), "addNurbprim");
|
|
|
|
nu->type= type;
|
|
|
|
nu->resolu= 4;
|
|
|
|
nu->resolv= 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(stype) {
|
2009-01-26 15:23:29 +00:00
|
|
|
case CU_PRIM_CURVE: /* curve */
|
2009-01-14 12:26:45 +00:00
|
|
|
nu->resolu= 12; /* set as 4 above */
|
|
|
|
if(newname) {
|
|
|
|
rename_id((ID *)obedit, "Curve");
|
|
|
|
rename_id((ID *)obedit->data, "Curve");
|
|
|
|
}
|
2009-01-26 15:23:29 +00:00
|
|
|
if(cutype==CU_BEZIER) {
|
2009-01-14 12:26:45 +00:00
|
|
|
nu->pntsu= 2;
|
|
|
|
nu->bezt =
|
|
|
|
(BezTriple*)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1");
|
|
|
|
bezt= nu->bezt;
|
|
|
|
bezt->h1= bezt->h2= HD_ALIGN;
|
|
|
|
bezt->f1= bezt->f2= bezt->f3= SELECT;
|
|
|
|
bezt->radius = 1.0;
|
|
|
|
|
|
|
|
for(a=0;a<3;a++) {
|
|
|
|
VECCOPY(bezt->vec[a], cent);
|
|
|
|
}
|
|
|
|
bezt->vec[1][0]+= -grid;
|
|
|
|
bezt->vec[0][0]+= -1.5*grid;
|
|
|
|
bezt->vec[0][1]+= -0.5*grid;
|
|
|
|
bezt->vec[2][0]+= -0.5*grid;
|
|
|
|
bezt->vec[2][1]+= 0.5*grid;
|
|
|
|
for(a=0;a<3;a++) Mat3MulVecfl(imat, bezt->vec[a]);
|
|
|
|
|
|
|
|
bezt++;
|
|
|
|
bezt->h1= bezt->h2= HD_ALIGN;
|
|
|
|
bezt->f1= bezt->f2= bezt->f3= SELECT;
|
|
|
|
bezt->radius = bezt->weight = 1.0;
|
|
|
|
|
|
|
|
for(a=0;a<3;a++) {
|
|
|
|
VECCOPY(bezt->vec[a], cent);
|
|
|
|
}
|
|
|
|
bezt->vec[1][0]+= grid;
|
|
|
|
for(a=0;a<3;a++) Mat3MulVecfl(imat, bezt->vec[a]);
|
|
|
|
|
|
|
|
calchandlesNurb(nu);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
nu->pntsu= 4;
|
|
|
|
nu->pntsv= 1;
|
|
|
|
nu->orderu= 4;
|
|
|
|
nu->bp= callocstructN(BPoint, 4, "addNurbprim3");
|
|
|
|
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0;a<4;a++, bp++) {
|
|
|
|
VECCOPY(bp->vec, cent);
|
|
|
|
bp->vec[3]= 1.0;
|
|
|
|
bp->f1= SELECT;
|
|
|
|
bp->radius = bp->weight = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bp= nu->bp;
|
|
|
|
bp->vec[0]+= -1.5*grid;
|
|
|
|
bp++;
|
|
|
|
bp->vec[0]+= -grid;
|
|
|
|
bp->vec[1]+= grid;
|
|
|
|
bp++;
|
|
|
|
bp->vec[0]+= grid;
|
|
|
|
bp->vec[1]+= grid;
|
|
|
|
bp++;
|
|
|
|
bp->vec[0]+= 1.5*grid;
|
|
|
|
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0;a<4;a++, bp++) Mat3MulVecfl(imat,bp->vec);
|
|
|
|
|
2009-01-26 15:23:29 +00:00
|
|
|
if(cutype==CU_NURBS) {
|
2009-01-14 12:26:45 +00:00
|
|
|
nu->knotsu= 0; /* makeknots allocates */
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
2009-01-26 15:23:29 +00:00
|
|
|
case CU_PRIM_PATH: /* 5 point path */
|
2009-01-14 12:26:45 +00:00
|
|
|
nu->pntsu= 5;
|
|
|
|
nu->pntsv= 1;
|
|
|
|
nu->orderu= 5;
|
|
|
|
nu->flagu= 2; /* endpoint */
|
|
|
|
nu->resolu= 8;
|
|
|
|
nu->bp= callocstructN(BPoint, 5, "addNurbprim3");
|
|
|
|
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0;a<5;a++, bp++) {
|
|
|
|
VECCOPY(bp->vec, cent);
|
|
|
|
bp->vec[3]= 1.0;
|
|
|
|
bp->f1= SELECT;
|
|
|
|
bp->radius = bp->weight = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bp= nu->bp;
|
|
|
|
bp->vec[0]+= -2.0*grid;
|
|
|
|
bp++;
|
|
|
|
bp->vec[0]+= -grid;
|
|
|
|
bp++; bp++;
|
|
|
|
bp->vec[0]+= grid;
|
|
|
|
bp++;
|
|
|
|
bp->vec[0]+= 2.0*grid;
|
|
|
|
|
|
|
|
bp= nu->bp;
|
|
|
|
for(a=0;a<5;a++, bp++) Mat3MulVecfl(imat,bp->vec);
|
|
|
|
|
2009-01-26 15:23:29 +00:00
|
|
|
if(cutype==CU_NURBS) {
|
2009-01-14 12:26:45 +00:00
|
|
|
nu->knotsu= 0; /* makeknots allocates */
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2009-01-26 15:23:29 +00:00
|
|
|
case CU_PRIM_CIRCLE: /* circle */
|
2009-01-14 12:26:45 +00:00
|
|
|
nu->resolu= 12; /* set as 4 above */
|
|
|
|
if(newname) {
|
|
|
|
rename_id((ID *)obedit, "CurveCircle");
|
|
|
|
rename_id((ID *)obedit->data, "CurveCircle");
|
|
|
|
}
|
2009-01-26 15:23:29 +00:00
|
|
|
if(cutype==CU_BEZIER) {
|
2009-01-14 12:26:45 +00:00
|
|
|
nu->pntsu= 4;
|
|
|
|
nu->bezt= callocstructN(BezTriple, 4, "addNurbprim1");
|
|
|
|
nu->flagu= CU_CYCLIC;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
|
|
|
|
for(a=0;a<3;a++) {
|
|
|
|
VECCOPY(bezt->vec[a], cent);
|
|
|
|
}
|
|
|
|
bezt->h1= bezt->h2= HD_AUTO;
|
|
|
|
bezt->f1= bezt->f2= bezt->f3= SELECT;
|
|
|
|
bezt->vec[1][0]+= -grid;
|
|
|
|
for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
|
|
|
|
bezt->radius = bezt->weight = 1.0;
|
|
|
|
|
|
|
|
bezt++;
|
|
|
|
for(a=0;a<3;a++) {
|
|
|
|
VECCOPY(bezt->vec[a], cent);
|
|
|
|
}
|
|
|
|
bezt->h1= bezt->h2= HD_AUTO;
|
|
|
|
bezt->f1= bezt->f2= bezt->f3= SELECT;
|
|
|
|
bezt->vec[1][1]+= grid;
|
|
|
|
for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
|
|
|
|
bezt->radius = bezt->weight = 1.0;
|
|
|
|
|
|
|
|
bezt++;
|
|
|
|
for(a=0;a<3;a++) {
|
|
|
|
VECCOPY(bezt->vec[a], cent);
|
|
|
|
}
|
|
|
|
bezt->h1= bezt->h2= HD_AUTO;
|
|
|
|
bezt->f1= bezt->f2= bezt->f3= SELECT;
|
|
|
|
bezt->vec[1][0]+= grid;
|
|
|
|
for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
|
|
|
|
bezt->radius = bezt->weight = 1.0;
|
|
|
|
|
|
|
|
bezt++;
|
|
|
|
for(a=0;a<3;a++) {
|
|
|
|
VECCOPY(bezt->vec[a], cent);
|
|
|
|
}
|
|
|
|
bezt->h1= bezt->h2= HD_AUTO;
|
|
|
|
bezt->f1= bezt->f2= bezt->f3= SELECT;
|
|
|
|
bezt->vec[1][1]+= -grid;
|
|
|
|
for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
|
|
|
|
bezt->radius = bezt->weight = 1.0;
|
|
|
|
|
|
|
|
calchandlesNurb(nu);
|
|
|
|
}
|
2009-01-26 15:23:29 +00:00
|
|
|
else if( cutype==CU_NURBS ) { /* nurb */
|
2009-01-14 12:26:45 +00:00
|
|
|
nu->pntsu= 8;
|
|
|
|
nu->pntsv= 1;
|
|
|
|
nu->orderu= 4;
|
|
|
|
nu->bp= callocstructN(BPoint, 8, "addNurbprim6");
|
|
|
|
nu->flagu= CU_CYCLIC;
|
|
|
|
bp= nu->bp;
|
|
|
|
|
|
|
|
for(a=0; a<8; a++) {
|
|
|
|
bp->f1= SELECT;
|
|
|
|
VECCOPY(bp->vec, cent);
|
|
|
|
|
|
|
|
if(xzproj==0) {
|
|
|
|
bp->vec[0]+= nurbcircle[a][0]*grid;
|
|
|
|
bp->vec[1]+= nurbcircle[a][1]*grid;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bp->vec[0]+= 0.25*nurbcircle[a][0]*grid-.75*grid;
|
|
|
|
bp->vec[2]+= 0.25*nurbcircle[a][1]*grid;
|
|
|
|
}
|
|
|
|
if(a & 1) bp->vec[3]= 0.25*sqrt(2.0);
|
|
|
|
else bp->vec[3]= 1.0;
|
|
|
|
Mat3MulVecfl(imat,bp->vec);
|
|
|
|
bp->radius = bp->weight = 1.0;
|
|
|
|
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
}
|
|
|
|
break;
|
2009-01-26 15:23:29 +00:00
|
|
|
case CU_PRIM_PATCH: /* 4x4 patch */
|
|
|
|
if( cutype==CU_NURBS ) { /* nurb */
|
2009-01-14 12:26:45 +00:00
|
|
|
if(newname) {
|
|
|
|
rename_id((ID *)obedit, "Surf");
|
|
|
|
rename_id((ID *)obedit->data, "Surf");
|
|
|
|
}
|
|
|
|
|
|
|
|
nu->pntsu= 4;
|
|
|
|
nu->pntsv= 4;
|
|
|
|
nu->orderu= 4;
|
|
|
|
nu->orderv= 4;
|
|
|
|
nu->flag= CU_SMOOTH;
|
|
|
|
nu->bp= callocstructN(BPoint, 4*4, "addNurbprim6");
|
|
|
|
nu->flagu= 0;
|
|
|
|
nu->flagv= 0;
|
|
|
|
bp= nu->bp;
|
|
|
|
|
|
|
|
for(a=0; a<4; a++) {
|
|
|
|
for(b=0; b<4; b++) {
|
|
|
|
VECCOPY(bp->vec, cent);
|
|
|
|
bp->f1= SELECT;
|
|
|
|
fac= (float)a -1.5;
|
|
|
|
bp->vec[0]+= fac*grid;
|
|
|
|
fac= (float)b -1.5;
|
|
|
|
bp->vec[1]+= fac*grid;
|
|
|
|
if(a==1 || a==2) if(b==1 || b==2) {
|
|
|
|
bp->vec[2]+= grid;
|
|
|
|
}
|
|
|
|
Mat3MulVecfl(imat,bp->vec);
|
|
|
|
bp->vec[3]= 1.0;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
makeknots(nu, 2, nu->flagv>>1);
|
|
|
|
}
|
|
|
|
break;
|
2009-01-26 15:23:29 +00:00
|
|
|
case CU_PRIM_TUBE: /* tube */
|
|
|
|
if( cutype==CU_NURBS ) {
|
2009-01-14 12:26:45 +00:00
|
|
|
if(newname) {
|
|
|
|
rename_id((ID *)obedit, "SurfTube");
|
|
|
|
rename_id((ID *)obedit->data, "SurfTube");
|
|
|
|
}
|
|
|
|
|
2009-01-26 15:23:29 +00:00
|
|
|
nu= addNurbprim(C, CU_NURBS|CU_2D|CU_PRIM_CIRCLE, 0); /* circle */
|
2009-01-14 12:26:45 +00:00
|
|
|
nu->resolu= 4;
|
|
|
|
nu->flag= CU_SMOOTH;
|
|
|
|
BLI_addtail(editnurb, nu); /* temporal for extrude and translate */
|
|
|
|
vec[0]=vec[1]= 0.0;
|
|
|
|
vec[2]= -grid;
|
|
|
|
Mat3MulVecfl(imat, vec);
|
|
|
|
translateflagNurb(editnurb, 1, vec);
|
|
|
|
extrudeflagNurb(editnurb, 1);
|
|
|
|
vec[0]= -2*vec[0];
|
|
|
|
vec[1]= -2*vec[1];
|
|
|
|
vec[2]= -2*vec[2];
|
|
|
|
translateflagNurb(editnurb, 1, vec);
|
|
|
|
|
|
|
|
BLI_remlink(editnurb, nu);
|
|
|
|
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a-- >0) {
|
|
|
|
bp->f1 |= SELECT;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2009-01-26 15:23:29 +00:00
|
|
|
case CU_PRIM_SPHERE: /* sphere */
|
|
|
|
if( cutype==CU_NURBS ) {
|
2009-01-14 12:26:45 +00:00
|
|
|
if(newname) {
|
|
|
|
rename_id((ID *)obedit, "SurfSphere");
|
|
|
|
rename_id((ID *)obedit->data, "SurfSphere");
|
|
|
|
}
|
|
|
|
|
|
|
|
nu->pntsu= 5;
|
|
|
|
nu->pntsv= 1;
|
|
|
|
nu->orderu= 3;
|
|
|
|
nu->resolu= 4;
|
|
|
|
nu->resolv= 4;
|
|
|
|
nu->flag= CU_SMOOTH;
|
|
|
|
nu->bp= callocstructN(BPoint, 5, "addNurbprim6");
|
|
|
|
nu->flagu= 0;
|
|
|
|
bp= nu->bp;
|
|
|
|
|
|
|
|
for(a=0; a<5; a++) {
|
|
|
|
bp->f1= SELECT;
|
|
|
|
VECCOPY(bp->vec, cent);
|
|
|
|
bp->vec[0]+= nurbcircle[a][0]*grid;
|
|
|
|
bp->vec[2]+= nurbcircle[a][1]*grid;
|
|
|
|
if(a & 1) bp->vec[3]= 0.5*sqrt(2.0);
|
|
|
|
else bp->vec[3]= 1.0;
|
|
|
|
Mat3MulVecfl(imat,bp->vec);
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
nu->flagu= 4;
|
|
|
|
makeknots(nu, 1, nu->flagu>>1);
|
|
|
|
|
|
|
|
BLI_addtail(editnurb, nu); /* temporal for spin */
|
|
|
|
if(newname && (U.flag & USER_ADD_VIEWALIGNED) == 0)
|
|
|
|
spin_nurb(scene, obedit, 0, 2);
|
|
|
|
else
|
|
|
|
spin_nurb(scene, obedit, 0, 0);
|
|
|
|
|
|
|
|
makeknots(nu, 2, nu->flagv>>1);
|
|
|
|
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a-- >0) {
|
|
|
|
bp->f1 |= SELECT;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
BLI_remlink(editnurb, nu);
|
|
|
|
}
|
|
|
|
break;
|
2009-01-26 15:23:29 +00:00
|
|
|
case CU_PRIM_DONUT: /* donut */
|
|
|
|
if( cutype==CU_NURBS ) {
|
2009-01-14 12:26:45 +00:00
|
|
|
if(newname) {
|
|
|
|
rename_id((ID *)obedit, "SurfDonut");
|
|
|
|
rename_id((ID *)obedit->data, "SurfDonut");
|
|
|
|
}
|
|
|
|
|
|
|
|
xzproj= 1;
|
2009-01-26 15:23:29 +00:00
|
|
|
nu= addNurbprim(C, CU_NURBS|CU_2D|CU_PRIM_CIRCLE, 0); /* circle */
|
2009-01-14 12:26:45 +00:00
|
|
|
xzproj= 0;
|
|
|
|
nu->resolu= 4;
|
|
|
|
nu->resolv= 4;
|
|
|
|
nu->flag= CU_SMOOTH;
|
|
|
|
BLI_addtail(editnurb, nu); /* temporal for extrude and translate */
|
|
|
|
if(newname && (U.flag & USER_ADD_VIEWALIGNED) == 0)
|
|
|
|
spin_nurb(scene, obedit, 0, 2);
|
|
|
|
else
|
|
|
|
spin_nurb(scene, obedit, 0, 0);
|
|
|
|
|
|
|
|
BLI_remlink(editnurb, nu);
|
|
|
|
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a-- >0) {
|
|
|
|
bp->f1 |= SELECT;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* always do: */
|
|
|
|
nu->flag= CU_SMOOTH;
|
|
|
|
|
|
|
|
test2DNurb(nu);
|
|
|
|
|
|
|
|
return nu;
|
|
|
|
}
|
|
|
|
|
|
|
|
void default_curve_ipo(Scene *scene, Curve *cu)
|
|
|
|
{
|
2.5: Blender "Animato" - New Animation System
Finally, here is the basic (functional) prototype of the new animation system which will allow for the infamous "everything is animatable", and which also addresses several of the more serious shortcomings of the old system. Unfortunately, this will break old animation files (especially right now, as I haven't written the version patching code yet), however, this is for the future.
Highlights of the new system:
* Scrapped IPO-Curves/IPO/(Action+Constraint-Channels)/Action system, and replaced it with F-Curve/Action.
- F-Curves (animators from other packages will feel at home with this name) replace IPO-Curves.
- The 'new' Actions, act as the containers for F-Curves, so that they can be reused. They are therefore more akin to the old 'IPO' blocks, except they do not have the blocktype restriction, so you can store materials/texture/geometry F-Curves in the same Action as Object transforms, etc.
* F-Curves use RNA-paths for Data Access, hence allowing "every" (where sensible/editable that is) user-accessible setting from RNA to be animated.
* Drivers are no longer mixed with Animation Data, so rigs will not be that easily broken and several dependency problems can be eliminated. (NOTE: drivers haven't been hooked up yet, but the code is in place)
* F-Curve modifier system allows useful 'large-scale' manipulation of F-Curve values, including (I've only included implemented ones here): envelope deform (similar to lattices to allow broad-scale reshaping of curves), curve generator (polynomial or py-expression), cycles (replacing the old cyclic extrapolation modes, giving more control over this). (NOTE: currently this cannot be tested, as there's not access to them, but the code is all in place)
* NLA system with 'tracks' (i.e. layers), and multiple strips per track. (NOTE: NLA system is not yet functional, as it's only partially coded still)
There are more nice things that I will be preparing some nice docs for soon, but for now, check for more details:
http://lists.blender.org/pipermail/bf-taskforce25/2009-January/000260.html
So, what currently works:
* I've implemented two basic operators for the 3D-view only to Insert and Delete Keyframes. These are tempolary ones only that will be replaced in due course with 'proper' code.
* Object Loc/Rot/Scale can be keyframed. Also, the colour of the 'active' material (Note: this should really be for nth material instead, but that doesn't work yet in RNA) can also be keyframed into the same datablock.
* Standard animation refresh (i.e. animation resulting from NLA and Action evaluation) is now done completely separate from drivers before anything else is done after a frame change. Drivers are handled after this in a separate pass, as dictated by depsgraph flags, etc.
Notes:
* Drivers haven't been hooked up yet
* Only objects and data directly linked to objects can be animated.
* Depsgraph will need further tweaks. Currently, I've only made sure that it will update some things in the most basic cases (i.e. frame change).
* Animation Editors are currently broken (in terms of editing stuff). This will be my next target (priority to get Dopesheet working first, then F-Curve editor - i.e. old IPO Editor)
* I've had to put in large chunks of XXX sandboxing for old animation system code all around the place. This will be cleaned up in due course, as some places need special review.
In particular, the particles and sequencer code have far too many manual calls to calculate + flush animation info, which is really bad (this is a 'please explain yourselves' call to Physics coders!).
2009-01-17 03:12:50 +00:00
|
|
|
#if 0 // XXX old animation system
|
2009-01-14 12:26:45 +00:00
|
|
|
IpoCurve *icu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
|
|
|
|
if(cu->ipo) return;
|
|
|
|
|
|
|
|
cu->ipo= add_ipo(scene, "CurveIpo", ID_CU);
|
|
|
|
|
|
|
|
icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
|
|
|
|
|
|
|
|
icu->blocktype= ID_CU;
|
|
|
|
icu->adrcode= CU_SPEED;
|
|
|
|
icu->flag= IPO_VISIBLE|IPO_SELECT|IPO_AUTO_HORIZ;
|
|
|
|
set_icu_vars(icu);
|
|
|
|
|
|
|
|
BLI_addtail( &(cu->ipo->curve), icu);
|
|
|
|
|
|
|
|
icu->bezt= bezt= MEM_callocN(2*sizeof(BezTriple), "defaultipo");
|
|
|
|
icu->totvert= 2;
|
|
|
|
|
|
|
|
bezt->hide= IPO_BEZ;
|
|
|
|
bezt->f1=bezt->f2= bezt->f3= SELECT;
|
|
|
|
bezt->h1= bezt->h2= HD_AUTO;
|
|
|
|
bezt++;
|
|
|
|
bezt->vec[1][0]= 100.0;
|
|
|
|
bezt->vec[1][1]= 1.0;
|
|
|
|
bezt->hide= IPO_BEZ;
|
|
|
|
bezt->f1=bezt->f2= bezt->f3= SELECT;
|
|
|
|
bezt->h1= bezt->h2= HD_AUTO;
|
|
|
|
|
|
|
|
calchandles_ipocurve(icu);
|
2.5: Blender "Animato" - New Animation System
Finally, here is the basic (functional) prototype of the new animation system which will allow for the infamous "everything is animatable", and which also addresses several of the more serious shortcomings of the old system. Unfortunately, this will break old animation files (especially right now, as I haven't written the version patching code yet), however, this is for the future.
Highlights of the new system:
* Scrapped IPO-Curves/IPO/(Action+Constraint-Channels)/Action system, and replaced it with F-Curve/Action.
- F-Curves (animators from other packages will feel at home with this name) replace IPO-Curves.
- The 'new' Actions, act as the containers for F-Curves, so that they can be reused. They are therefore more akin to the old 'IPO' blocks, except they do not have the blocktype restriction, so you can store materials/texture/geometry F-Curves in the same Action as Object transforms, etc.
* F-Curves use RNA-paths for Data Access, hence allowing "every" (where sensible/editable that is) user-accessible setting from RNA to be animated.
* Drivers are no longer mixed with Animation Data, so rigs will not be that easily broken and several dependency problems can be eliminated. (NOTE: drivers haven't been hooked up yet, but the code is in place)
* F-Curve modifier system allows useful 'large-scale' manipulation of F-Curve values, including (I've only included implemented ones here): envelope deform (similar to lattices to allow broad-scale reshaping of curves), curve generator (polynomial or py-expression), cycles (replacing the old cyclic extrapolation modes, giving more control over this). (NOTE: currently this cannot be tested, as there's not access to them, but the code is all in place)
* NLA system with 'tracks' (i.e. layers), and multiple strips per track. (NOTE: NLA system is not yet functional, as it's only partially coded still)
There are more nice things that I will be preparing some nice docs for soon, but for now, check for more details:
http://lists.blender.org/pipermail/bf-taskforce25/2009-January/000260.html
So, what currently works:
* I've implemented two basic operators for the 3D-view only to Insert and Delete Keyframes. These are tempolary ones only that will be replaced in due course with 'proper' code.
* Object Loc/Rot/Scale can be keyframed. Also, the colour of the 'active' material (Note: this should really be for nth material instead, but that doesn't work yet in RNA) can also be keyframed into the same datablock.
* Standard animation refresh (i.e. animation resulting from NLA and Action evaluation) is now done completely separate from drivers before anything else is done after a frame change. Drivers are handled after this in a separate pass, as dictated by depsgraph flags, etc.
Notes:
* Drivers haven't been hooked up yet
* Only objects and data directly linked to objects can be animated.
* Depsgraph will need further tweaks. Currently, I've only made sure that it will update some things in the most basic cases (i.e. frame change).
* Animation Editors are currently broken (in terms of editing stuff). This will be my next target (priority to get Dopesheet working first, then F-Curve editor - i.e. old IPO Editor)
* I've had to put in large chunks of XXX sandboxing for old animation system code all around the place. This will be cleaned up in due course, as some places need special review.
In particular, the particles and sequencer code have far too many manual calls to calculate + flush animation info, which is really bad (this is a 'please explain yourselves' call to Physics coders!).
2009-01-17 03:12:50 +00:00
|
|
|
#endif // XXX old animation system
|
2009-01-14 12:26:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void clear_tilt(Scene *scene)
|
|
|
|
{
|
|
|
|
Object *obedit= scene->obedit; // XXX
|
|
|
|
ListBase *editnurb= curve_get_editcurve(obedit);
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
if(okee("Clear tilt")==0) return;
|
|
|
|
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
if( nu->bezt ) {
|
|
|
|
bezt= nu->bezt;
|
|
|
|
a= nu->pntsu;
|
|
|
|
while(a--) {
|
|
|
|
if(BEZSELECTED_HIDDENHANDLES(bezt)) bezt->alfa= 0.0;
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nu->bp) {
|
|
|
|
bp= nu->bp;
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
while(a--) {
|
|
|
|
if(bp->f1 & SELECT) bp->alfa= 0.0;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
BIF_undo_push("Clear tilt");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int bezt_compare (const void *e1, const void *e2)
|
|
|
|
{
|
|
|
|
BezTriple *b1 = *((BezTriple**)e1);
|
|
|
|
BezTriple *b2 = *((BezTriple**)e2);
|
|
|
|
|
|
|
|
/* Check numerical values */
|
|
|
|
float val = b1->vec[1][0] - b2->vec[1][0];
|
|
|
|
|
|
|
|
if (val<0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (val>0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Check selected flags : Ensures that selected keys will be listed first */
|
|
|
|
|
|
|
|
if ((b1->f2 & SELECT) && !(b2->f2 & SELECT))
|
|
|
|
return -1;
|
|
|
|
if (!(b1->f2 & SELECT) && (b2->f2 & SELECT))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* **************** undo for curves ************** */
|
|
|
|
|
|
|
|
static void undoCurve_to_editCurve(void *lbu, void *lbe)
|
|
|
|
{
|
|
|
|
ListBase *lb= lbu;
|
|
|
|
ListBase *editnurb= lbe;
|
|
|
|
Nurb *nu, *newnu;
|
|
|
|
|
|
|
|
freeNurblist(editnurb);
|
|
|
|
|
|
|
|
/* copy */
|
|
|
|
for(nu= lb->first; nu; nu= nu->next) {
|
|
|
|
newnu= duplicateNurb(nu);
|
|
|
|
BLI_addtail(editnurb, newnu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *editCurve_to_undoCurve(void *lbe)
|
|
|
|
{
|
|
|
|
ListBase *editnurb= lbe;
|
|
|
|
ListBase *lb;
|
|
|
|
Nurb *nu, *newnu;
|
|
|
|
|
|
|
|
lb= MEM_callocN(sizeof(ListBase), "listbase undo");
|
|
|
|
|
|
|
|
/* copy */
|
|
|
|
for(nu= editnurb->first; nu; nu= nu->next) {
|
|
|
|
newnu= duplicateNurb(nu);
|
|
|
|
BLI_addtail(lb, newnu);
|
|
|
|
}
|
|
|
|
return lb;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_undoCurve(void *lbv)
|
|
|
|
{
|
|
|
|
ListBase *lb= lbv;
|
|
|
|
|
|
|
|
freeNurblist(lb);
|
|
|
|
MEM_freeN(lb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *get_data(bContext *C)
|
|
|
|
{
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
return curve_get_editcurve(obedit);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* and this is all the undo system needs to know */
|
|
|
|
void undo_push_curve(bContext *C, char *name)
|
|
|
|
{
|
|
|
|
undo_editmode_push(C, name, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***/
|