Blender  V3.3
curve.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include <cmath> /* floor */
9 #include <cstdlib>
10 #include <cstring>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_blenlib.h"
15 #include "BLI_endian_switch.h"
16 #include "BLI_ghash.h"
17 #include "BLI_index_range.hh"
18 #include "BLI_math.h"
19 #include "BLI_math_vec_types.hh"
20 #include "BLI_string.h"
21 #include "BLI_utildefines.h"
22 #include "BLT_translation.h"
23 
24 /* Allow using deprecated functionality for .blend file I/O. */
25 #define DNA_DEPRECATED_ALLOW
26 
27 #include "DNA_anim_types.h"
28 #include "DNA_curve_types.h"
29 #include "DNA_defaults.h"
30 #include "DNA_material_types.h"
31 
32 /* For dereferencing pointers. */
33 #include "DNA_key_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_vfont_types.h"
36 
37 #include "BKE_anim_data.h"
38 #include "BKE_curve.h"
39 #include "BKE_curveprofile.h"
40 #include "BKE_displist.h"
41 #include "BKE_idtype.h"
42 #include "BKE_key.h"
43 #include "BKE_lib_id.h"
44 #include "BKE_lib_query.h"
45 #include "BKE_main.h"
46 #include "BKE_object.h"
47 #include "BKE_vfont.h"
48 
49 #include "DEG_depsgraph.h"
50 #include "DEG_depsgraph_query.h"
51 
52 #include "CLG_log.h"
53 
54 #include "BLO_read_write.h"
55 
56 using blender::float3;
58 
59 /* globals */
60 
61 /* local */
62 // static CLG_LogRef LOG = {"bke.curve"};
63 
65  Valid,
70 };
71 
72 static void curve_init_data(ID *id)
73 {
74  Curve *curve = (Curve *)id;
75 
77 
79 }
80 
81 static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
82 {
83  Curve *curve_dst = (Curve *)id_dst;
84  const Curve *curve_src = (const Curve *)id_src;
85 
86  BLI_listbase_clear(&curve_dst->nurb);
87  BKE_nurbList_duplicate(&(curve_dst->nurb), &(curve_src->nurb));
88 
89  curve_dst->mat = (Material **)MEM_dupallocN(curve_src->mat);
90 
91  curve_dst->str = (char *)MEM_dupallocN(curve_src->str);
92  curve_dst->strinfo = (CharInfo *)MEM_dupallocN(curve_src->strinfo);
93  curve_dst->tb = (TextBox *)MEM_dupallocN(curve_src->tb);
94  curve_dst->batch_cache = nullptr;
95 
96  curve_dst->bevel_profile = BKE_curveprofile_copy(curve_src->bevel_profile);
97 
98  if (curve_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
99  BKE_id_copy_ex(bmain, &curve_src->key->id, (ID **)&curve_dst->key, flag);
100  /* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */
101  curve_dst->key->from = &curve_dst->id;
102  }
103 
104  curve_dst->editnurb = nullptr;
105  curve_dst->editfont = nullptr;
106 }
107 
108 static void curve_free_data(ID *id)
109 {
110  Curve *curve = (Curve *)id;
111 
113 
115 
118 
120  }
121 
123 
128 }
129 
131 {
132  Curve *curve = (Curve *)id;
137  for (int i = 0; i < curve->totcol; i++) {
139  }
144 }
145 
146 static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_address)
147 {
148  Curve *cu = (Curve *)id;
149 
150  /* Clean up, important in undo case to reduce false detection of changed datablocks. */
151  cu->editnurb = nullptr;
152  cu->editfont = nullptr;
153  cu->batch_cache = nullptr;
154 
155  /* write LibData */
156  BLO_write_id_struct(writer, Curve, id_address, &cu->id);
157  BKE_id_blend_write(writer, &cu->id);
158 
159  /* direct data */
160  BLO_write_pointer_array(writer, cu->totcol, cu->mat);
161  if (cu->adt) {
162  BKE_animdata_blend_write(writer, cu->adt);
163  }
164 
165  if (cu->vfont) {
166  BLO_write_raw(writer, cu->len + 1, cu->str);
167  BLO_write_struct_array(writer, CharInfo, cu->len_char32 + 1, cu->strinfo);
168  BLO_write_struct_array(writer, TextBox, cu->totbox, cu->tb);
169  }
170  else {
171  /* is also the order of reading */
172  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
173  BLO_write_struct(writer, Nurb, nu);
174  }
175  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
176  if (nu->type == CU_BEZIER) {
177  BLO_write_struct_array(writer, BezTriple, nu->pntsu, nu->bezt);
178  }
179  else {
180  BLO_write_struct_array(writer, BPoint, nu->pntsu * nu->pntsv, nu->bp);
181  if (nu->knotsu) {
182  BLO_write_float_array(writer, KNOTSU(nu), nu->knotsu);
183  }
184  if (nu->knotsv) {
185  BLO_write_float_array(writer, KNOTSV(nu), nu->knotsv);
186  }
187  }
188  }
189  }
190 
191  if (cu->bevel_profile != nullptr) {
193  }
194 }
195 
196 static void switch_endian_knots(Nurb *nu)
197 {
198  if (nu->knotsu) {
200  }
201  if (nu->knotsv) {
203  }
204 }
205 
206 static void curve_blend_read_data(BlendDataReader *reader, ID *id)
207 {
208  Curve *cu = (Curve *)id;
209  BLO_read_data_address(reader, &cu->adt);
210  BKE_animdata_blend_read_data(reader, cu->adt);
211 
212  /* Protect against integer overflow vulnerability. */
213  CLAMP(cu->len_char32, 0, INT_MAX - 4);
214 
215  BLO_read_pointer_array(reader, (void **)&cu->mat);
216 
217  BLO_read_data_address(reader, &cu->str);
218  BLO_read_data_address(reader, &cu->strinfo);
219  BLO_read_data_address(reader, &cu->tb);
220 
221  if (cu->vfont == nullptr) {
222  BLO_read_list(reader, &(cu->nurb));
223  }
224  else {
225  cu->nurb.first = cu->nurb.last = nullptr;
226 
227  TextBox *tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBoxread");
228  if (cu->tb) {
229  memcpy(tb, cu->tb, cu->totbox * sizeof(TextBox));
230  MEM_freeN(cu->tb);
231  cu->tb = tb;
232  }
233  else {
234  cu->totbox = 1;
235  cu->actbox = 1;
236  cu->tb = tb;
237  cu->tb[0].w = cu->linewidth;
238  }
239  if (cu->wordspace == 0.0f) {
240  cu->wordspace = 1.0f;
241  }
242  }
243 
244  cu->editnurb = nullptr;
245  cu->editfont = nullptr;
246  cu->batch_cache = nullptr;
247 
248  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
249  BLO_read_data_address(reader, &nu->bezt);
250  BLO_read_data_address(reader, &nu->bp);
251  BLO_read_data_address(reader, &nu->knotsu);
252  BLO_read_data_address(reader, &nu->knotsv);
253  if (cu->vfont == nullptr) {
254  nu->charidx = 0;
255  }
256 
257  if (BLO_read_requires_endian_switch(reader)) {
259  }
260  }
262 
263  BLO_read_data_address(reader, &cu->bevel_profile);
264  if (cu->bevel_profile != nullptr) {
266  }
267 }
268 
269 static void curve_blend_read_lib(BlendLibReader *reader, ID *id)
270 {
271  Curve *cu = (Curve *)id;
272  for (int a = 0; a < cu->totcol; a++) {
273  BLO_read_id_address(reader, cu->id.lib, &cu->mat[a]);
274  }
275 
276  BLO_read_id_address(reader, cu->id.lib, &cu->bevobj);
277  BLO_read_id_address(reader, cu->id.lib, &cu->taperobj);
278  BLO_read_id_address(reader, cu->id.lib, &cu->textoncurve);
279  BLO_read_id_address(reader, cu->id.lib, &cu->vfont);
280  BLO_read_id_address(reader, cu->id.lib, &cu->vfontb);
281  BLO_read_id_address(reader, cu->id.lib, &cu->vfonti);
282  BLO_read_id_address(reader, cu->id.lib, &cu->vfontbi);
283 
284  BLO_read_id_address(reader, cu->id.lib, &cu->ipo); /* XXX deprecated - old animation system */
285  BLO_read_id_address(reader, cu->id.lib, &cu->key);
286 }
287 
288 static void curve_blend_read_expand(BlendExpander *expander, ID *id)
289 {
290  Curve *cu = (Curve *)id;
291  for (int a = 0; a < cu->totcol; a++) {
292  BLO_expand(expander, cu->mat[a]);
293  }
294 
295  BLO_expand(expander, cu->vfont);
296  BLO_expand(expander, cu->vfontb);
297  BLO_expand(expander, cu->vfonti);
298  BLO_expand(expander, cu->vfontbi);
299  BLO_expand(expander, cu->key);
300  BLO_expand(expander, cu->ipo); /* XXX deprecated - old animation system */
301  BLO_expand(expander, cu->bevobj);
302  BLO_expand(expander, cu->taperobj);
303  BLO_expand(expander, cu->textoncurve);
304 }
305 
307  /* id_code */ ID_CU_LEGACY,
308  /* id_filter */ FILTER_ID_CU_LEGACY,
309  /* main_listbase_index */ INDEX_ID_CU_LEGACY,
310  /* struct_size */ sizeof(Curve),
311  /* name */ "Curve",
312  /* name_plural */ "curves",
313  /* translation_context */ BLT_I18NCONTEXT_ID_CURVE_LEGACY,
315  /* asset_type_info */ nullptr,
316 
317  /* init_data */ curve_init_data,
318  /* copy_data */ curve_copy_data,
319  /* free_data */ curve_free_data,
320  /* make_local */ nullptr,
321  /* foreach_id */ curve_foreach_id,
322  /* foreach_cache */ nullptr,
323  /* foreach_path */ nullptr,
324  /* owner_get */ nullptr,
325 
326  /* blend_write */ curve_blend_write,
327  /* blend_read_data */ curve_blend_read_data,
328  /* blend_read_lib */ curve_blend_read_lib,
329  /* blend_read_expand */ curve_blend_read_expand,
330 
331  /* blend_read_undo_preserve */ nullptr,
332 
333  /* lib_override_apply_post */ nullptr,
334 };
335 
337 {
338  if (cu->editfont) {
339  EditFont *ef = cu->editfont;
340 
341  if (ef->textbuf) {
342  MEM_freeN(ef->textbuf);
343  }
344  if (ef->textbufinfo) {
345  MEM_freeN(ef->textbufinfo);
346  }
347  if (ef->selboxes) {
348  MEM_freeN(ef->selboxes);
349  }
350 
351  MEM_freeN(ef);
352  cu->editfont = nullptr;
353  }
354 }
355 
357 {
358  CVKeyIndex *index = (CVKeyIndex *)val;
359  MEM_freeN(index->orig_cv);
360  MEM_freeN(val);
361 }
362 
363 void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
364 {
365  BLI_assert(keyindex != nullptr);
367 }
368 
370 {
371  if (!(*keyindex)) {
372  return;
373  }
375  *keyindex = nullptr;
376 }
377 
379 {
380  if (cu->editnurb) {
383  MEM_freeN(cu->editnurb);
384  cu->editnurb = nullptr;
385  }
386 }
387 
388 void BKE_curve_init(Curve *cu, const short curve_type)
389 {
390  curve_init_data(&cu->id);
391 
392  cu->type = curve_type;
393 
394  if (cu->type == OB_FONT) {
395  cu->flag |= CU_FRONT | CU_BACK;
396  cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
397  cu->vfont->id.us += 4;
398  cu->str = (char *)MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
399  BLI_strncpy(cu->str, "Text", 12);
400  cu->len = cu->len_char32 = cu->pos = 4;
401  cu->strinfo = (CharInfo *)MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
402  cu->totbox = cu->actbox = 1;
403  cu->tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
404  cu->tb[0].w = cu->tb[0].h = 0.0;
405  }
406  else if (cu->type == OB_SURF) {
407  cu->flag |= CU_3D;
408  cu->resolu = 4;
409  cu->resolv = 4;
410  }
411  cu->bevel_profile = nullptr;
412 }
413 
414 Curve *BKE_curve_add(Main *bmain, const char *name, int type)
415 {
416  Curve *cu;
417 
418  /* We cannot use #BKE_id_new here as we need some custom initialization code. */
419  cu = (Curve *)BKE_libblock_alloc(bmain, ID_CU_LEGACY, name, 0);
420 
421  BKE_curve_init(cu, type);
422 
423  return cu;
424 }
425 
427 {
428  if (cu->editnurb) {
429  return &cu->editnurb->nurbs;
430  }
431 
432  return nullptr;
433 }
434 
436 {
437  if (cu->editnurb) {
438  return &cu->editnurb->nurbs;
439  }
440 
441  return nullptr;
442 }
443 
444 short BKE_curve_type_get(const Curve *cu)
445 {
446  int type = cu->type;
447 
448  if (cu->vfont) {
449  return OB_FONT;
450  }
451 
452  if (!cu->type) {
454 
455  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
456  if (nu->pntsv > 1) {
457  type = OB_SURF;
458  }
459  }
460  }
461 
462  return type;
463 }
464 
466 {
467  ListBase *nurbs = BKE_curve_nurbs_get(cu);
468  bool is_2d = CU_IS_2D(cu);
469 
470  LISTBASE_FOREACH (Nurb *, nu, nurbs) {
471  if (is_2d) {
473  }
474 
475  /* since the handles are moved they need to be auto-located again */
476  if (nu->type == CU_BEZIER) {
478  }
479  }
480 }
481 
483 {
484  ob->type = BKE_curve_type_get((Curve *)ob->data);
485 
486  if (ob->type == OB_CURVES_LEGACY) {
487  Curve *cu = (Curve *)ob->data;
488  if (CU_IS_2D(cu)) {
490  }
491  }
492 }
493 
495 {
496  /* This is Object-level data access,
497  * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
498  if (ob->runtime.bb == nullptr || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
499  Curve *cu = (Curve *)ob->data;
500  float min[3], max[3];
501 
502  INIT_MINMAX(min, max);
503  if (!BKE_curve_minmax(cu, true, min, max)) {
504  copy_v3_fl(min, -1.0f);
505  copy_v3_fl(max, 1.0f);
506  }
507 
508  if (ob->runtime.bb == nullptr) {
509  ob->runtime.bb = (BoundBox *)MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
510  }
512  ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
513  }
514 
515  return ob->runtime.bb;
516 }
517 
519 {
520  if (cu->texflag & CU_AUTOSPACE) {
521  float min[3], max[3];
522 
523  INIT_MINMAX(min, max);
524  if (!BKE_curve_minmax(cu, true, min, max)) {
525  min[0] = min[1] = min[2] = -1.0f;
526  max[0] = max[1] = max[2] = 1.0f;
527  }
528 
529  float loc[3], size[3];
530  mid_v3_v3v3(loc, min, max);
531 
532  size[0] = (max[0] - min[0]) / 2.0f;
533  size[1] = (max[1] - min[1]) / 2.0f;
534  size[2] = (max[2] - min[2]) / 2.0f;
535 
536  for (int a = 0; a < 3; a++) {
537  if (size[a] == 0.0f) {
538  size[a] = 1.0f;
539  }
540  else if (size[a] > 0.0f && size[a] < 0.00001f) {
541  size[a] = 0.00001f;
542  }
543  else if (size[a] < 0.0f && size[a] > -0.00001f) {
544  size[a] = -0.00001f;
545  }
546  }
547 
548  copy_v3_v3(cu->loc, loc);
549  copy_v3_v3(cu->size, size);
550 
552  }
553 }
554 
556 {
557  if ((cu->texflag & CU_AUTOSPACE) && !(cu->texflag & CU_AUTOSPACE_EVALUATED)) {
559  }
560 }
561 
562 bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
563 {
564  int tot = 0;
565 
566  LISTBASE_FOREACH (Nurb *, nu, nurb) {
567  int tot_nu;
568  if (nu->type == CU_BEZIER) {
569  tot_nu = nu->pntsu;
570  if (index - tot < tot_nu) {
571  copy_v3_v3(r_co, nu->bezt[index - tot].vec[1]);
572  return true;
573  }
574  }
575  else {
576  tot_nu = nu->pntsu * nu->pntsv;
577  if (index - tot < tot_nu) {
578  copy_v3_v3(r_co, nu->bp[index - tot].vec);
579  return true;
580  }
581  }
582  tot += tot_nu;
583  }
584 
585  return false;
586 }
587 
589 {
590  int tot = 0;
591 
592  LISTBASE_FOREACH (const Nurb *, nu, nurb) {
593  if (nu->bezt) {
594  tot += 3 * nu->pntsu;
595  }
596  else if (nu->bp) {
597  tot += nu->pntsu * nu->pntsv;
598  }
599  }
600 
601  return tot;
602 }
603 
605 {
606  int tot = 0;
607 
608  LISTBASE_FOREACH (Nurb *, nu, nurb) {
609  if (nu->bezt) {
610  tot += nu->pntsu;
611  }
612  else if (nu->bp) {
613  tot += nu->pntsu * nu->pntsv;
614  }
615  }
616 
617  return tot;
618 }
619 
620 /* **************** NURBS ROUTINES ******************** */
621 
623 {
624  if (nu == nullptr) {
625  return;
626  }
627 
628  if (nu->bezt) {
629  MEM_freeN(nu->bezt);
630  }
631  nu->bezt = nullptr;
632  if (nu->bp) {
633  MEM_freeN(nu->bp);
634  }
635  nu->bp = nullptr;
636  if (nu->knotsu) {
637  MEM_freeN(nu->knotsu);
638  }
639  nu->knotsu = nullptr;
640  if (nu->knotsv) {
641  MEM_freeN(nu->knotsv);
642  }
643  nu->knotsv = nullptr;
644  // if (nu->trim.first) freeNurblist(&(nu->trim));
645 
646  MEM_freeN(nu);
647 }
648 
650 {
651  if (lb == nullptr) {
652  return;
653  }
654 
655  LISTBASE_FOREACH_MUTABLE (Nurb *, nu, lb) {
656  BKE_nurb_free(nu);
657  }
658  BLI_listbase_clear(lb);
659 }
660 
662 {
663  Nurb *newnu;
664  int len;
665 
666  newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplicateNurb");
667  if (newnu == nullptr) {
668  return nullptr;
669  }
670  *newnu = blender::dna::shallow_copy(*nu);
671 
672  if (nu->bezt) {
673  newnu->bezt = (BezTriple *)MEM_malloc_arrayN(nu->pntsu, sizeof(BezTriple), "duplicateNurb2");
674  memcpy(newnu->bezt, nu->bezt, nu->pntsu * sizeof(BezTriple));
675  }
676  else {
677  len = nu->pntsu * nu->pntsv;
678  newnu->bp = (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3");
679  memcpy(newnu->bp, nu->bp, len * sizeof(BPoint));
680 
681  newnu->knotsu = newnu->knotsv = nullptr;
682 
683  if (nu->knotsu) {
684  len = KNOTSU(nu);
685  if (len) {
686  newnu->knotsu = (float *)MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
687  memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len);
688  }
689  }
690  if (nu->pntsv > 1 && nu->knotsv) {
691  len = KNOTSV(nu);
692  if (len) {
693  newnu->knotsv = (float *)MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
694  memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len);
695  }
696  }
697  }
698  return newnu;
699 }
700 
701 Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
702 {
703  Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb");
704  *newnu = blender::dna::shallow_copy(*src);
705 
706  if (pntsu == 1) {
707  SWAP(int, pntsu, pntsv);
708  }
709  newnu->pntsu = pntsu;
710  newnu->pntsv = pntsv;
711 
712  /* caller can manually handle these arrays */
713  newnu->knotsu = nullptr;
714  newnu->knotsv = nullptr;
715 
716  if (src->bezt) {
717  newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2");
718  }
719  else {
720  newnu->bp = (BPoint *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BPoint), "copyNurb3");
721  }
722 
723  return newnu;
724 }
725 
727 {
728  BKE_nurbList_free(lb1);
729 
730  LISTBASE_FOREACH (const Nurb *, nu, lb2) {
731  Nurb *nurb_new = BKE_nurb_duplicate(nu);
732  BLI_addtail(lb1, nurb_new);
733  }
734 }
735 
737 {
738  BezTriple *bezt;
739  BPoint *bp;
740  int a;
741 
742  if (nu->type == CU_BEZIER) {
743  a = nu->pntsu;
744  bezt = nu->bezt;
745  while (a--) {
746  bezt->vec[0][2] = 0.0;
747  bezt->vec[1][2] = 0.0;
748  bezt->vec[2][2] = 0.0;
749  bezt++;
750  }
751  }
752  else {
753  a = nu->pntsu * nu->pntsv;
754  bp = nu->bp;
755  while (a--) {
756  bp->vec[2] = 0.0;
757  bp++;
758  }
759  }
760 }
761 
762 void BKE_nurb_minmax(const Nurb *nu, bool use_radius, float min[3], float max[3])
763 {
764  BezTriple *bezt;
765  BPoint *bp;
766  int a;
767  float point[3];
768 
769  if (nu->type == CU_BEZIER) {
770  a = nu->pntsu;
771  bezt = nu->bezt;
772  while (a--) {
773  if (use_radius) {
774  float radius_vector[3];
775  radius_vector[0] = radius_vector[1] = radius_vector[2] = bezt->radius;
776 
777  add_v3_v3v3(point, bezt->vec[1], radius_vector);
779 
780  sub_v3_v3v3(point, bezt->vec[1], radius_vector);
782  }
783  else {
784  minmax_v3v3_v3(min, max, bezt->vec[1]);
785  }
786  minmax_v3v3_v3(min, max, bezt->vec[0]);
787  minmax_v3v3_v3(min, max, bezt->vec[2]);
788  bezt++;
789  }
790  }
791  else {
792  a = nu->pntsu * nu->pntsv;
793  bp = nu->bp;
794  while (a--) {
795  if (nu->pntsv == 1 && use_radius) {
796  float radius_vector[3];
797  radius_vector[0] = radius_vector[1] = radius_vector[2] = bp->radius;
798 
799  add_v3_v3v3(point, bp->vec, radius_vector);
801 
802  sub_v3_v3v3(point, bp->vec, radius_vector);
804  }
805  else {
806  /* Surfaces doesn't use bevel, so no need to take radius into account. */
807  minmax_v3v3_v3(min, max, bp->vec);
808  }
809  bp++;
810  }
811  }
812 }
813 
814 float BKE_nurb_calc_length(const Nurb *nu, int resolution)
815 {
816  BezTriple *bezt, *prevbezt;
817  BPoint *bp, *prevbp;
818  int a, b;
819  float length = 0.0f;
820  int resolu = resolution ? resolution : nu->resolu;
821  int pntsu = nu->pntsu;
822  float *points, *pntsit, *prevpntsit;
823 
824  if (nu->type == CU_POLY) {
825  a = nu->pntsu - 1;
826  bp = nu->bp;
827  if (nu->flagu & CU_NURB_CYCLIC) {
828  a++;
829  prevbp = nu->bp + (nu->pntsu - 1);
830  }
831  else {
832  prevbp = bp;
833  bp++;
834  }
835 
836  while (a--) {
837  length += len_v3v3(prevbp->vec, bp->vec);
838  prevbp = bp;
839  bp++;
840  }
841  }
842  else if (nu->type == CU_BEZIER) {
843  points = (float *)MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
844  a = nu->pntsu - 1;
845  bezt = nu->bezt;
846  if (nu->flagu & CU_NURB_CYCLIC) {
847  a++;
848  prevbezt = nu->bezt + (nu->pntsu - 1);
849  }
850  else {
851  prevbezt = bezt;
852  bezt++;
853  }
854 
855  while (a--) {
856  if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
857  length += len_v3v3(prevbezt->vec[1], bezt->vec[1]);
858  }
859  else {
860  for (int j = 0; j < 3; j++) {
861  BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
862  prevbezt->vec[2][j],
863  bezt->vec[0][j],
864  bezt->vec[1][j],
865  points + j,
866  resolu,
867  sizeof(float[3]));
868  }
869 
870  prevpntsit = pntsit = points;
871  b = resolu;
872  while (b--) {
873  pntsit += 3;
874  length += len_v3v3(prevpntsit, pntsit);
875  prevpntsit = pntsit;
876  }
877  }
878  prevbezt = bezt;
879  bezt++;
880  }
881 
882  MEM_freeN(points);
883  }
884  else if (nu->type == CU_NURBS) {
885  if (nu->pntsv == 1) {
886  /* important to zero for BKE_nurb_makeCurve. */
887  points = (float *)MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
888 
889  BKE_nurb_makeCurve(nu, points, nullptr, nullptr, nullptr, resolu, sizeof(float[3]));
890 
891  if (nu->flagu & CU_NURB_CYCLIC) {
892  b = pntsu * resolu + 1;
893  prevpntsit = points + 3 * (pntsu * resolu - 1);
894  pntsit = points;
895  }
896  else {
897  b = (pntsu - 1) * resolu;
898  prevpntsit = points;
899  pntsit = points + 3;
900  }
901 
902  while (--b > 0) {
903  length += len_v3v3(prevpntsit, pntsit);
904  prevpntsit = pntsit;
905  pntsit += 3;
906  }
907 
908  MEM_freeN(points);
909  }
910  }
911 
912  return length;
913 }
914 
915 void BKE_nurb_points_add(Nurb *nu, int number)
916 {
917  nu->bp = (BPoint *)MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint));
918 
919  BPoint *bp;
920  int i;
921  for (i = 0, bp = &nu->bp[nu->pntsu]; i < number; i++, bp++) {
922  bp->radius = 1.0f;
923  }
924 
925  nu->pntsu += number;
926 }
927 
928 void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
929 {
930  BezTriple *bezt;
931  int i;
932 
933  nu->bezt = (BezTriple *)MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
934 
935  for (i = 0, bezt = &nu->bezt[nu->pntsu]; i < number; i++, bezt++) {
936  bezt->radius = 1.0f;
937  }
938 
939  nu->pntsu += number;
940 }
941 
942 int BKE_nurb_index_from_uv(Nurb *nu, int u, int v)
943 {
944  const int totu = nu->pntsu;
945  const int totv = nu->pntsv;
946 
947  if (nu->flagu & CU_NURB_CYCLIC) {
948  u = mod_i(u, totu);
949  }
950  else if (u < 0 || u >= totu) {
951  return -1;
952  }
953 
954  if (nu->flagv & CU_NURB_CYCLIC) {
955  v = mod_i(v, totv);
956  }
957  else if (v < 0 || v >= totv) {
958  return -1;
959  }
960 
961  return (v * totu) + u;
962 }
963 
964 void BKE_nurb_index_to_uv(Nurb *nu, int index, int *r_u, int *r_v)
965 {
966  const int totu = nu->pntsu;
967  const int totv = nu->pntsv;
968  BLI_assert(index >= 0 && index < (nu->pntsu * nu->pntsv));
969  *r_u = (index % totu);
970  *r_v = (index / totu) % totv;
971 }
972 
974 {
975  BezTriple *bezt_next;
976 
977  BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
978 
979  if (bezt == &nu->bezt[nu->pntsu - 1]) {
980  if (nu->flagu & CU_NURB_CYCLIC) {
981  bezt_next = nu->bezt;
982  }
983  else {
984  bezt_next = nullptr;
985  }
986  }
987  else {
988  bezt_next = bezt + 1;
989  }
990 
991  return bezt_next;
992 }
993 
995 {
996  BPoint *bp_next;
997 
998  BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
999 
1000  if (bp == &nu->bp[nu->pntsu - 1]) {
1001  if (nu->flagu & CU_NURB_CYCLIC) {
1002  bp_next = nu->bp;
1003  }
1004  else {
1005  bp_next = nullptr;
1006  }
1007  }
1008  else {
1009  bp_next = bp + 1;
1010  }
1011 
1012  return bp_next;
1013 }
1014 
1016 {
1017  BezTriple *bezt_prev;
1018 
1019  BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
1020  BLI_assert(nu->pntsv <= 1);
1021 
1022  if (bezt == nu->bezt) {
1023  if (nu->flagu & CU_NURB_CYCLIC) {
1024  bezt_prev = &nu->bezt[nu->pntsu - 1];
1025  }
1026  else {
1027  bezt_prev = nullptr;
1028  }
1029  }
1030  else {
1031  bezt_prev = bezt - 1;
1032  }
1033 
1034  return bezt_prev;
1035 }
1036 
1038 {
1039  BPoint *bp_prev;
1040 
1041  BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
1042  BLI_assert(nu->pntsv == 1);
1043 
1044  if (bp == nu->bp) {
1045  if (nu->flagu & CU_NURB_CYCLIC) {
1046  bp_prev = &nu->bp[nu->pntsu - 1];
1047  }
1048  else {
1049  bp_prev = nullptr;
1050  }
1051  }
1052  else {
1053  bp_prev = bp - 1;
1054  }
1055 
1056  return bp_prev;
1057 }
1058 
1059 void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), BezTriple *bezt, float r_normal[3])
1060 {
1061  /* calculate the axis matrix from the spline */
1062  float dir_prev[3], dir_next[3];
1063 
1064  sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]);
1065  sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]);
1066 
1067  normalize_v3(dir_prev);
1068  normalize_v3(dir_next);
1069 
1070  add_v3_v3v3(r_normal, dir_prev, dir_next);
1071  normalize_v3(r_normal);
1072 }
1073 
1074 void BKE_nurb_bezt_calc_plane(struct Nurb *nu, BezTriple *bezt, float r_plane[3])
1075 {
1076  float dir_prev[3], dir_next[3];
1077 
1078  sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]);
1079  sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]);
1080 
1081  normalize_v3(dir_prev);
1082  normalize_v3(dir_next);
1083 
1084  cross_v3_v3v3(r_plane, dir_prev, dir_next);
1085  if (normalize_v3(r_plane) < FLT_EPSILON) {
1086  BezTriple *bezt_prev = BKE_nurb_bezt_get_prev(nu, bezt);
1087  BezTriple *bezt_next = BKE_nurb_bezt_get_next(nu, bezt);
1088 
1089  if (bezt_prev) {
1090  sub_v3_v3v3(dir_prev, bezt_prev->vec[1], bezt->vec[1]);
1091  normalize_v3(dir_prev);
1092  }
1093  if (bezt_next) {
1094  sub_v3_v3v3(dir_next, bezt->vec[1], bezt_next->vec[1]);
1095  normalize_v3(dir_next);
1096  }
1097  cross_v3_v3v3(r_plane, dir_prev, dir_next);
1098  }
1099 
1100  /* matches with bones more closely */
1101  {
1102  float dir_mid[3], tvec[3];
1103  add_v3_v3v3(dir_mid, dir_prev, dir_next);
1104  cross_v3_v3v3(tvec, r_plane, dir_mid);
1105  copy_v3_v3(r_plane, tvec);
1106  }
1107 
1108  normalize_v3(r_plane);
1109 }
1110 
1111 void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, BPoint *bp, float r_normal[3])
1112 {
1113  BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
1114  BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
1115 
1116  zero_v3(r_normal);
1117 
1118  if (bp_prev) {
1119  float dir_prev[3];
1120  sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
1121  normalize_v3(dir_prev);
1122  add_v3_v3(r_normal, dir_prev);
1123  }
1124  if (bp_next) {
1125  float dir_next[3];
1126  sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
1127  normalize_v3(dir_next);
1128  add_v3_v3(r_normal, dir_next);
1129  }
1130 
1131  normalize_v3(r_normal);
1132 }
1133 
1134 void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3])
1135 {
1136  BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
1137  BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
1138 
1139  float dir_prev[3] = {0.0f}, dir_next[3] = {0.0f};
1140 
1141  if (bp_prev) {
1142  sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
1143  normalize_v3(dir_prev);
1144  }
1145  if (bp_next) {
1146  sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
1147  normalize_v3(dir_next);
1148  }
1149  cross_v3_v3v3(r_plane, dir_prev, dir_next);
1150 
1151  /* matches with bones more closely */
1152  {
1153  float dir_mid[3], tvec[3];
1154  add_v3_v3v3(dir_mid, dir_prev, dir_next);
1155  cross_v3_v3v3(tvec, r_plane, dir_mid);
1156  copy_v3_v3(r_plane, tvec);
1157  }
1158 
1159  normalize_v3(r_plane);
1160 }
1161 
1162 /* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */
1163 
1164 static void calcknots(float *knots, const int pnts, const short order, const short flag)
1165 {
1166  const bool is_cyclic = flag & CU_NURB_CYCLIC;
1167  const bool is_bezier = flag & CU_NURB_BEZIER;
1168  const bool is_end_point = flag & CU_NURB_ENDPOINT;
1169  /* Inner knots are always repeated once except on Bezier case. */
1170  const int repeat_inner = is_bezier ? order - 1 : 1;
1171  /* How many times to repeat 0.0 at the beginning of knot. */
1172  const int head = is_end_point ? (order - (is_cyclic ? 1 : 0)) :
1173  (is_bezier ? min_ii(2, repeat_inner) : 1);
1174  /* Number of knots replicating widths of the starting knots.
1175  * Covers both Cyclic and EndPoint cases. */
1176  const int tail = is_cyclic ? 2 * order - 1 : (is_end_point ? order : 0);
1177 
1178  const int knot_count = pnts + order + (is_cyclic ? order - 1 : 0);
1179 
1180  int r = head;
1181  float current = 0.0f;
1182 
1183  const int offset = is_end_point && is_cyclic ? 1 : 0;
1184  if (offset) {
1185  knots[0] = current;
1186  current += 1.0f;
1187  }
1188 
1189  for (const int i : IndexRange(offset, knot_count - offset - tail)) {
1190  knots[i] = current;
1191  r--;
1192  if (r == 0) {
1193  current += 1.0f;
1194  r = repeat_inner;
1195  }
1196  }
1197 
1198  const int tail_index = knot_count - tail;
1199  for (const int i : IndexRange(tail)) {
1200  knots[tail_index + i] = current + (knots[i] - knots[0]);
1201  }
1202 }
1203 
1204 static void makeknots(Nurb *nu, short uv)
1205 {
1206  if (nu->type == CU_NURBS) {
1207  if (uv == 1) {
1208  if (nu->knotsu) {
1209  MEM_freeN(nu->knotsu);
1210  }
1211  if (BKE_nurb_check_valid_u(nu)) {
1212  nu->knotsu = (float *)MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
1213  calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
1214  }
1215  else {
1216  nu->knotsu = nullptr;
1217  }
1218  }
1219  else if (uv == 2) {
1220  if (nu->knotsv) {
1221  MEM_freeN(nu->knotsv);
1222  }
1223  if (BKE_nurb_check_valid_v(nu)) {
1224  nu->knotsv = (float *)MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
1225  calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
1226  }
1227  else {
1228  nu->knotsv = nullptr;
1229  }
1230  }
1231  }
1232 }
1233 
1235 {
1236  makeknots(nu, 1);
1237 }
1238 
1240 {
1241  makeknots(nu, 2);
1242 }
1243 
1244 static void basisNurb(
1245  float t, short order, int pnts, const float *knots, float *basis, int *start, int *end)
1246 {
1247  float d, e;
1248  int i, i1 = 0, i2 = 0, j, orderpluspnts, opp2, o2;
1249 
1250  orderpluspnts = order + pnts;
1251  opp2 = orderpluspnts - 1;
1252 
1253  /* this is for float inaccuracy */
1254  if (t < knots[0]) {
1255  t = knots[0];
1256  }
1257  else if (t > knots[opp2]) {
1258  t = knots[opp2];
1259  }
1260 
1261  /* this part is order '1' */
1262  o2 = order + 1;
1263  for (i = 0; i < opp2; i++) {
1264  if (knots[i] != knots[i + 1] && t >= knots[i] && t <= knots[i + 1]) {
1265  basis[i] = 1.0;
1266  i1 = i - o2;
1267  if (i1 < 0) {
1268  i1 = 0;
1269  }
1270  i2 = i;
1271  i++;
1272  while (i < opp2) {
1273  basis[i] = 0.0;
1274  i++;
1275  }
1276  break;
1277  }
1278 
1279  basis[i] = 0.0;
1280  }
1281  basis[i] = 0.0;
1282 
1283  /* this is order 2, 3, ... */
1284  for (j = 2; j <= order; j++) {
1285 
1286  if (i2 + j >= orderpluspnts) {
1287  i2 = opp2 - j;
1288  }
1289 
1290  for (i = i1; i <= i2; i++) {
1291  if (basis[i] != 0.0f) {
1292  d = ((t - knots[i]) * basis[i]) / (knots[i + j - 1] - knots[i]);
1293  }
1294  else {
1295  d = 0.0f;
1296  }
1297 
1298  if (basis[i + 1] != 0.0f) {
1299  e = ((knots[i + j] - t) * basis[i + 1]) / (knots[i + j] - knots[i + 1]);
1300  }
1301  else {
1302  e = 0.0;
1303  }
1304 
1305  basis[i] = d + e;
1306  }
1307  }
1308 
1309  *start = 1000;
1310  *end = 0;
1311 
1312  for (i = i1; i <= i2; i++) {
1313  if (basis[i] > 0.0f) {
1314  *end = i;
1315  if (*start == 1000) {
1316  *start = i;
1317  }
1318  }
1319  }
1320 }
1321 
1322 void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv)
1323 {
1324  BPoint *bp;
1325  float *basisu, *basis, *basisv, *sum, *fp, *in;
1326  float u, v, ustart, uend, ustep, vstart, vend, vstep, sumdiv;
1327  int i, j, iofs, jofs, cycl, len, curu, curv;
1328  int istart, iend, jsta, jen, *jstart, *jend, ratcomp;
1329 
1330  int totu = nu->pntsu * resolu, totv = nu->pntsv * resolv;
1331 
1332  if (nu->knotsu == nullptr || nu->knotsv == nullptr) {
1333  return;
1334  }
1335  if (nu->orderu > nu->pntsu) {
1336  return;
1337  }
1338  if (nu->orderv > nu->pntsv) {
1339  return;
1340  }
1341  if (coord_array == nullptr) {
1342  return;
1343  }
1344 
1345  /* allocate and initialize */
1346  len = totu * totv;
1347  if (len == 0) {
1348  return;
1349  }
1350 
1351  sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbfaces1");
1352 
1353  bp = nu->bp;
1354  i = nu->pntsu * nu->pntsv;
1355  ratcomp = 0;
1356  while (i--) {
1357  if (bp->vec[3] != 1.0f) {
1358  ratcomp = 1;
1359  break;
1360  }
1361  bp++;
1362  }
1363 
1364  fp = nu->knotsu;
1365  ustart = fp[nu->orderu - 1];
1366  if (nu->flagu & CU_NURB_CYCLIC) {
1367  uend = fp[nu->pntsu + nu->orderu - 1];
1368  }
1369  else {
1370  uend = fp[nu->pntsu];
1371  }
1372  ustep = (uend - ustart) / ((nu->flagu & CU_NURB_CYCLIC) ? totu : totu - 1);
1373 
1374  basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbfaces3");
1375 
1376  fp = nu->knotsv;
1377  vstart = fp[nu->orderv - 1];
1378 
1379  if (nu->flagv & CU_NURB_CYCLIC) {
1380  vend = fp[nu->pntsv + nu->orderv - 1];
1381  }
1382  else {
1383  vend = fp[nu->pntsv];
1384  }
1385  vstep = (vend - vstart) / ((nu->flagv & CU_NURB_CYCLIC) ? totv : totv - 1);
1386 
1387  len = KNOTSV(nu);
1388  basisv = (float *)MEM_malloc_arrayN(len * totv, sizeof(float), "makeNurbfaces3");
1389  jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4");
1390  jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5");
1391 
1392  /* Pre-calculation of `basisv` and `jstart`, `jend`. */
1393  if (nu->flagv & CU_NURB_CYCLIC) {
1394  cycl = nu->orderv - 1;
1395  }
1396  else {
1397  cycl = 0;
1398  }
1399  v = vstart;
1400  basis = basisv;
1401  curv = totv;
1402  while (curv--) {
1403  basisNurb(v, nu->orderv, nu->pntsv + cycl, nu->knotsv, basis, jstart + curv, jend + curv);
1404  basis += KNOTSV(nu);
1405  v += vstep;
1406  }
1407 
1408  if (nu->flagu & CU_NURB_CYCLIC) {
1409  cycl = nu->orderu - 1;
1410  }
1411  else {
1412  cycl = 0;
1413  }
1414  in = coord_array;
1415  u = ustart;
1416  curu = totu;
1417  while (curu--) {
1418  basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend);
1419 
1420  basis = basisv;
1421  curv = totv;
1422  while (curv--) {
1423  jsta = jstart[curv];
1424  jen = jend[curv];
1425 
1426  /* calculate sum */
1427  sumdiv = 0.0;
1428  fp = sum;
1429 
1430  for (j = jsta; j <= jen; j++) {
1431 
1432  if (j >= nu->pntsv) {
1433  jofs = (j - nu->pntsv);
1434  }
1435  else {
1436  jofs = j;
1437  }
1438  bp = nu->bp + nu->pntsu * jofs + istart - 1;
1439 
1440  for (i = istart; i <= iend; i++, fp++) {
1441  if (i >= nu->pntsu) {
1442  iofs = i - nu->pntsu;
1443  bp = nu->bp + nu->pntsu * jofs + iofs;
1444  }
1445  else {
1446  bp++;
1447  }
1448 
1449  if (ratcomp) {
1450  *fp = basisu[i] * basis[j] * bp->vec[3];
1451  sumdiv += *fp;
1452  }
1453  else {
1454  *fp = basisu[i] * basis[j];
1455  }
1456  }
1457  }
1458 
1459  if (ratcomp) {
1460  fp = sum;
1461  for (j = jsta; j <= jen; j++) {
1462  for (i = istart; i <= iend; i++, fp++) {
1463  *fp /= sumdiv;
1464  }
1465  }
1466  }
1467 
1468  zero_v3(in);
1469 
1470  /* one! (1.0) real point now */
1471  fp = sum;
1472  for (j = jsta; j <= jen; j++) {
1473 
1474  if (j >= nu->pntsv) {
1475  jofs = (j - nu->pntsv);
1476  }
1477  else {
1478  jofs = j;
1479  }
1480  bp = nu->bp + nu->pntsu * jofs + istart - 1;
1481 
1482  for (i = istart; i <= iend; i++, fp++) {
1483  if (i >= nu->pntsu) {
1484  iofs = i - nu->pntsu;
1485  bp = nu->bp + nu->pntsu * jofs + iofs;
1486  }
1487  else {
1488  bp++;
1489  }
1490 
1491  if (*fp != 0.0f) {
1492  madd_v3_v3fl(in, bp->vec, *fp);
1493  }
1494  }
1495  }
1496 
1497  in += 3;
1498  basis += KNOTSV(nu);
1499  }
1500  u += ustep;
1501  if (rowstride != 0) {
1502  in = (float *)(((unsigned char *)in) + (rowstride - 3 * totv * sizeof(*in)));
1503  }
1504  }
1505 
1506  /* free */
1507  MEM_freeN(sum);
1508  MEM_freeN(basisu);
1509  MEM_freeN(basisv);
1510  MEM_freeN(jstart);
1511  MEM_freeN(jend);
1512 }
1513 
1514 void BKE_nurb_makeCurve(const Nurb *nu,
1515  float *coord_array,
1516  float *tilt_array,
1517  float *radius_array,
1518  float *weight_array,
1519  int resolu,
1520  int stride)
1521 {
1522  const float eps = 1e-6f;
1523  BPoint *bp;
1524  float u, ustart, uend, ustep, sumdiv;
1525  float *basisu, *sum, *fp;
1526  float *coord_fp = coord_array, *tilt_fp = tilt_array, *radius_fp = radius_array,
1527  *weight_fp = weight_array;
1528  int i, len, istart, iend, cycl;
1529 
1530  if (nu->knotsu == nullptr) {
1531  return;
1532  }
1533  if (nu->orderu > nu->pntsu) {
1534  return;
1535  }
1536  if (coord_array == nullptr) {
1537  return;
1538  }
1539 
1540  /* allocate and initialize */
1541  len = nu->pntsu;
1542  if (len == 0) {
1543  return;
1544  }
1545  sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbcurve1");
1546 
1547  resolu = (resolu * SEGMENTSU(nu));
1548 
1549  if (resolu == 0) {
1550  MEM_freeN(sum);
1551  return;
1552  }
1553 
1554  fp = nu->knotsu;
1555  ustart = fp[nu->orderu - 1];
1556  if (nu->flagu & CU_NURB_CYCLIC) {
1557  uend = fp[nu->pntsu + nu->orderu - 1];
1558  }
1559  else {
1560  uend = fp[nu->pntsu];
1561  }
1562  ustep = (uend - ustart) / (resolu - ((nu->flagu & CU_NURB_CYCLIC) ? 0 : 1));
1563 
1564  basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbcurve3");
1565 
1566  if (nu->flagu & CU_NURB_CYCLIC) {
1567  cycl = nu->orderu - 1;
1568  }
1569  else {
1570  cycl = 0;
1571  }
1572 
1573  u = ustart;
1574  while (resolu--) {
1575  basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend);
1576 
1577  /* calc sum */
1578  sumdiv = 0.0;
1579  fp = sum;
1580  bp = nu->bp + istart - 1;
1581  for (i = istart; i <= iend; i++, fp++) {
1582  if (i >= nu->pntsu) {
1583  bp = nu->bp + (i - nu->pntsu);
1584  }
1585  else {
1586  bp++;
1587  }
1588 
1589  *fp = basisu[i] * bp->vec[3];
1590  sumdiv += *fp;
1591  }
1592  if ((sumdiv != 0.0f) && (sumdiv < 1.0f - eps || sumdiv > 1.0f + eps)) {
1593  /* is normalizing needed? */
1594  fp = sum;
1595  for (i = istart; i <= iend; i++, fp++) {
1596  *fp /= sumdiv;
1597  }
1598  }
1599 
1600  zero_v3(coord_fp);
1601 
1602  /* one! (1.0) real point */
1603  fp = sum;
1604  bp = nu->bp + istart - 1;
1605  for (i = istart; i <= iend; i++, fp++) {
1606  if (i >= nu->pntsu) {
1607  bp = nu->bp + (i - nu->pntsu);
1608  }
1609  else {
1610  bp++;
1611  }
1612 
1613  if (*fp != 0.0f) {
1614  madd_v3_v3fl(coord_fp, bp->vec, *fp);
1615 
1616  if (tilt_fp) {
1617  (*tilt_fp) += (*fp) * bp->tilt;
1618  }
1619 
1620  if (radius_fp) {
1621  (*radius_fp) += (*fp) * bp->radius;
1622  }
1623 
1624  if (weight_fp) {
1625  (*weight_fp) += (*fp) * bp->weight;
1626  }
1627  }
1628  }
1629 
1630  coord_fp = (float *)POINTER_OFFSET(coord_fp, stride);
1631 
1632  if (tilt_fp) {
1633  tilt_fp = (float *)POINTER_OFFSET(tilt_fp, stride);
1634  }
1635  if (radius_fp) {
1636  radius_fp = (float *)POINTER_OFFSET(radius_fp, stride);
1637  }
1638  if (weight_fp) {
1639  weight_fp = (float *)POINTER_OFFSET(weight_fp, stride);
1640  }
1641 
1642  u += ustep;
1643  }
1644 
1645  /* free */
1646  MEM_freeN(sum);
1647  MEM_freeN(basisu);
1648 }
1649 
1650 unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
1651  const unsigned int resolu,
1652  const bool is_cyclic,
1653  const bool use_cyclic_duplicate_endpoint)
1654 {
1655  const unsigned int segments = bezt_array_len - (is_cyclic ? 0 : 1);
1656  const unsigned int points_len = (segments * resolu) +
1657  (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1);
1658  return points_len;
1659 }
1660 
1661 void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
1662  const unsigned int bezt_array_len,
1663  const unsigned int resolu,
1664  const bool is_cyclic,
1665  const bool use_cyclic_duplicate_endpoint,
1666  /* array params */
1667  const unsigned int axis,
1668  const unsigned int stride,
1669  float *r_points)
1670 {
1671  const unsigned int points_len = BKE_curve_calc_coords_axis_len(
1672  bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint);
1673  float *r_points_offset = r_points;
1674 
1675  const unsigned int resolu_stride = resolu * stride;
1676  const unsigned int bezt_array_last = bezt_array_len - 1;
1677 
1678  for (unsigned int i = 0; i < bezt_array_last; i++) {
1679  const BezTriple *bezt_curr = &bezt_array[i];
1680  const BezTriple *bezt_next = &bezt_array[i + 1];
1681  BKE_curve_forward_diff_bezier(bezt_curr->vec[1][axis],
1682  bezt_curr->vec[2][axis],
1683  bezt_next->vec[0][axis],
1684  bezt_next->vec[1][axis],
1685  r_points_offset,
1686  (int)resolu,
1687  stride);
1688  r_points_offset = (float *)POINTER_OFFSET(r_points_offset, resolu_stride);
1689  }
1690 
1691  if (is_cyclic) {
1692  const BezTriple *bezt_curr = &bezt_array[bezt_array_last];
1693  const BezTriple *bezt_next = &bezt_array[0];
1694  BKE_curve_forward_diff_bezier(bezt_curr->vec[1][axis],
1695  bezt_curr->vec[2][axis],
1696  bezt_next->vec[0][axis],
1697  bezt_next->vec[1][axis],
1698  r_points_offset,
1699  (int)resolu,
1700  stride);
1701  r_points_offset = (float *)POINTER_OFFSET(r_points_offset, resolu_stride);
1702  if (use_cyclic_duplicate_endpoint) {
1703  *r_points_offset = *r_points;
1704  r_points_offset = (float *)POINTER_OFFSET(r_points_offset, stride);
1705  }
1706  }
1707  else {
1708  float *r_points_last = (float *)POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
1709  *r_points_last = bezt_array[bezt_array_last].vec[1][axis];
1710  r_points_offset = (float *)POINTER_OFFSET(r_points_offset, stride);
1711  }
1712 
1713  BLI_assert((float *)POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
1714  UNUSED_VARS_NDEBUG(points_len);
1715 }
1716 
1718  float q0, float q1, float q2, float q3, float *p, int it, int stride)
1719 {
1720  float rt0, rt1, rt2, rt3, f;
1721  int a;
1722 
1723  f = (float)it;
1724  rt0 = q0;
1725  rt1 = 3.0f * (q1 - q0) / f;
1726  f *= f;
1727  rt2 = 3.0f * (q0 - 2.0f * q1 + q2) / f;
1728  f *= it;
1729  rt3 = (q3 - q0 + 3.0f * (q1 - q2)) / f;
1730 
1731  q0 = rt0;
1732  q1 = rt1 + rt2 + rt3;
1733  q2 = 2 * rt2 + 6 * rt3;
1734  q3 = 6 * rt3;
1735 
1736  for (a = 0; a <= it; a++) {
1737  *p = q0;
1738  p = (float *)POINTER_OFFSET(p, stride);
1739  q0 += q1;
1740  q1 += q2;
1741  q2 += q3;
1742  }
1743 }
1744 
1746  float q0, float q1, float q2, float q3, float *p, int it, int stride)
1747 {
1748  float rt0, rt1, rt2, f;
1749  int a;
1750 
1751  f = 1.0f / (float)it;
1752 
1753  rt0 = 3.0f * (q1 - q0);
1754  rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2));
1755  rt2 = 6.0f * (q0 + q2) - 12.0f * q1;
1756 
1757  q0 = rt0;
1758  q1 = f * (rt1 + rt2);
1759  q2 = 2.0f * f * rt1;
1760 
1761  for (a = 0; a <= it; a++) {
1762  *p = q0;
1763  p = (float *)POINTER_OFFSET(p, stride);
1764  q0 += q1;
1765  q1 += q2;
1766  }
1767 }
1768 
1769 static void forward_diff_bezier_cotangent(const float p0[3],
1770  const float p1[3],
1771  const float p2[3],
1772  const float p3[3],
1773  float p[3],
1774  int it,
1775  int stride)
1776 {
1777  /* note that these are not perpendicular to the curve
1778  * they need to be rotated for this,
1779  *
1780  * This could also be optimized like BKE_curve_forward_diff_bezier */
1781  for (int a = 0; a <= it; a++) {
1782  float t = (float)a / (float)it;
1783 
1784  for (int i = 0; i < 3; i++) {
1785  p[i] = (-6.0f * t + 6.0f) * p0[i] + (18.0f * t - 12.0f) * p1[i] +
1786  (-18.0f * t + 6.0f) * p2[i] + (6.0f * t) * p3[i];
1787  }
1788  normalize_v3(p);
1789  p = (float *)POINTER_OFFSET(p, stride);
1790  }
1791 }
1792 
1793 static int cu_isectLL(const float v1[3],
1794  const float v2[3],
1795  const float v3[3],
1796  const float v4[3],
1797  short cox,
1798  short coy,
1799  float *lambda,
1800  float *mu,
1801  float vec[3])
1802 {
1803  /* return:
1804  * -1: collinear
1805  * 0: no intersection of segments
1806  * 1: exact intersection of segments
1807  * 2: cross-intersection of segments
1808  */
1809  float deler;
1810 
1811  deler = (v1[cox] - v2[cox]) * (v3[coy] - v4[coy]) - (v3[cox] - v4[cox]) * (v1[coy] - v2[coy]);
1812  if (deler == 0.0f) {
1813  return -1;
1814  }
1815 
1816  *lambda = (v1[coy] - v3[coy]) * (v3[cox] - v4[cox]) - (v1[cox] - v3[cox]) * (v3[coy] - v4[coy]);
1817  *lambda = -(*lambda / deler);
1818 
1819  deler = v3[coy] - v4[coy];
1820  if (deler == 0) {
1821  deler = v3[cox] - v4[cox];
1822  *mu = -(*lambda * (v2[cox] - v1[cox]) + v1[cox] - v3[cox]) / deler;
1823  }
1824  else {
1825  *mu = -(*lambda * (v2[coy] - v1[coy]) + v1[coy] - v3[coy]) / deler;
1826  }
1827  vec[cox] = *lambda * (v2[cox] - v1[cox]) + v1[cox];
1828  vec[coy] = *lambda * (v2[coy] - v1[coy]) + v1[coy];
1829 
1830  if (*lambda >= 0.0f && *lambda <= 1.0f && *mu >= 0.0f && *mu <= 1.0f) {
1831  if (*lambda == 0.0f || *lambda == 1.0f || *mu == 0.0f || *mu == 1.0f) {
1832  return 1;
1833  }
1834  return 2;
1835  }
1836  return 0;
1837 }
1838 
1839 static bool bevelinside(const BevList *bl1, const BevList *bl2)
1840 {
1841  /* is bl2 INSIDE bl1 ? with left-right method and "lambda's" */
1842  /* returns '1' if correct hole. */
1843  BevPoint *bevp, *prevbevp;
1844  float min, max, vec[3], hvec1[3], hvec2[3], lab, mu;
1845  int nr, links = 0, rechts = 0, mode;
1846 
1847  /* take first vertex of possible hole */
1848 
1849  bevp = bl2->bevpoints;
1850  hvec1[0] = bevp->vec[0];
1851  hvec1[1] = bevp->vec[1];
1852  hvec1[2] = 0.0;
1853  copy_v3_v3(hvec2, hvec1);
1854  hvec2[0] += 1000;
1855 
1856  /* test it with all edges of potential surrounding poly */
1857  /* count number of transitions left-right. */
1858 
1859  bevp = bl1->bevpoints;
1860  nr = bl1->nr;
1861  prevbevp = bevp + (nr - 1);
1862 
1863  while (nr--) {
1864  min = prevbevp->vec[1];
1865  max = bevp->vec[1];
1866  if (max < min) {
1867  min = max;
1868  max = prevbevp->vec[1];
1869  }
1870  if (min != max) {
1871  if (min <= hvec1[1] && max >= hvec1[1]) {
1872  /* there's a transition, calc intersection point */
1873  mode = cu_isectLL(prevbevp->vec, bevp->vec, hvec1, hvec2, 0, 1, &lab, &mu, vec);
1874  /* if lab==0.0 or lab==1.0 then the edge intersects exactly a transition
1875  * only allow for one situation: we choose lab= 1.0
1876  */
1877  if (mode >= 0 && lab != 0.0f) {
1878  if (vec[0] < hvec1[0]) {
1879  links++;
1880  }
1881  else {
1882  rechts++;
1883  }
1884  }
1885  }
1886  }
1887  prevbevp = bevp;
1888  bevp++;
1889  }
1890 
1891  return (links & 1) && (rechts & 1);
1892 }
1893 
1894 struct BevelSort {
1896  float left;
1897  int dir;
1898 };
1899 
1900 static int vergxcobev(const void *a1, const void *a2)
1901 {
1902  const struct BevelSort *x1 = (BevelSort *)a1, *x2 = (BevelSort *)a2;
1903 
1904  if (x1->left > x2->left) {
1905  return 1;
1906  }
1907  if (x1->left < x2->left) {
1908  return -1;
1909  }
1910  return 0;
1911 }
1912 
1913 /* this function cannot be replaced with atan2, but why? */
1914 
1916  float x1, float y1, float x2, float y2, float *r_sina, float *r_cosa)
1917 {
1918  float t01, t02, x3, y3;
1919 
1920  t01 = sqrtf(x1 * x1 + y1 * y1);
1921  t02 = sqrtf(x2 * x2 + y2 * y2);
1922  if (t01 == 0.0f) {
1923  t01 = 1.0f;
1924  }
1925  if (t02 == 0.0f) {
1926  t02 = 1.0f;
1927  }
1928 
1929  x1 /= t01;
1930  y1 /= t01;
1931  x2 /= t02;
1932  y2 /= t02;
1933 
1934  t02 = x1 * x2 + y1 * y2;
1935  if (fabsf(t02) >= 1.0f) {
1936  t02 = M_PI_2;
1937  }
1938  else {
1939  t02 = (saacos(t02)) / 2.0f;
1940  }
1941 
1942  t02 = sinf(t02);
1943  if (t02 == 0.0f) {
1944  t02 = 1.0f;
1945  }
1946 
1947  x3 = x1 - x2;
1948  y3 = y1 - y2;
1949  if (x3 == 0 && y3 == 0) {
1950  x3 = y1;
1951  y3 = -x1;
1952  }
1953  else {
1954  t01 = sqrtf(x3 * x3 + y3 * y3);
1955  x3 /= t01;
1956  y3 /= t01;
1957  }
1958 
1959  *r_sina = -y3 / t02;
1960  *r_cosa = x3 / t02;
1961 }
1962 
1963 static void tilt_bezpart(const BezTriple *prevbezt,
1964  const BezTriple *bezt,
1965  const Nurb *nu,
1966  float *tilt_array,
1967  float *radius_array,
1968  float *weight_array,
1969  int resolu,
1970  int stride)
1971 {
1972  const BezTriple *pprev, *next, *last;
1973  float fac, dfac, t[4];
1974  int a;
1975 
1976  if (tilt_array == nullptr && radius_array == nullptr) {
1977  return;
1978  }
1979 
1980  last = nu->bezt + (nu->pntsu - 1);
1981 
1982  /* returns a point */
1983  if (prevbezt == nu->bezt) {
1984  if (nu->flagu & CU_NURB_CYCLIC) {
1985  pprev = last;
1986  }
1987  else {
1988  pprev = prevbezt;
1989  }
1990  }
1991  else {
1992  pprev = prevbezt - 1;
1993  }
1994 
1995  /* next point */
1996  if (bezt == last) {
1997  if (nu->flagu & CU_NURB_CYCLIC) {
1998  next = nu->bezt;
1999  }
2000  else {
2001  next = bezt;
2002  }
2003  }
2004  else {
2005  next = bezt + 1;
2006  }
2007 
2008  fac = 0.0;
2009  dfac = 1.0f / (float)resolu;
2010 
2011  for (a = 0; a < resolu; a++, fac += dfac) {
2012  if (tilt_array) {
2013  if (nu->tilt_interp == KEY_CU_EASE) {
2014  /* May as well support for tilt also 2.47 ease interp. */
2015  *tilt_array = prevbezt->tilt +
2016  (bezt->tilt - prevbezt->tilt) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
2017  }
2018  else {
2020  *tilt_array = t[0] * pprev->tilt + t[1] * prevbezt->tilt + t[2] * bezt->tilt +
2021  t[3] * next->tilt;
2022  }
2023 
2024  tilt_array = (float *)POINTER_OFFSET(tilt_array, stride);
2025  }
2026 
2027  if (radius_array) {
2028  if (nu->radius_interp == KEY_CU_EASE) {
2029  /* Support 2.47 ease interp
2030  * NOTE: this only takes the 2 points into account,
2031  * giving much more localized results to changes in radius, sometimes you want that. */
2032  *radius_array = prevbezt->radius + (bezt->radius - prevbezt->radius) *
2033  (3.0f * fac * fac - 2.0f * fac * fac * fac);
2034  }
2035  else {
2036 
2037  /* reuse interpolation from tilt if we can */
2038  if (tilt_array == nullptr || nu->tilt_interp != nu->radius_interp) {
2040  }
2041  *radius_array = t[0] * pprev->radius + t[1] * prevbezt->radius + t[2] * bezt->radius +
2042  t[3] * next->radius;
2043  }
2044 
2045  radius_array = (float *)POINTER_OFFSET(radius_array, stride);
2046  }
2047 
2048  if (weight_array) {
2049  /* Basic interpolation for now, could copy tilt interp too. */
2050  *weight_array = prevbezt->weight + (bezt->weight - prevbezt->weight) *
2051  (3.0f * fac * fac - 2.0f * fac * fac * fac);
2052 
2053  weight_array = (float *)POINTER_OFFSET(weight_array, stride);
2054  }
2055  }
2056 }
2057 
2058 /* `make_bevel_list_3D_*` functions, at a minimum these must
2059  * fill in the #BevPoint.quat and #BevPoint.dir values. */
2060 
2063 {
2064  BevPoint *bevp2, *bevp1, *bevp0;
2065  int nr;
2066  bool is_cyclic = bl->poly != -1;
2067 
2068  if (is_cyclic) {
2069  bevp2 = bl->bevpoints;
2070  bevp1 = bevp2 + (bl->nr - 1);
2071  bevp0 = bevp1 - 1;
2072  nr = bl->nr;
2073  }
2074  else {
2075  /* If spline is not cyclic, direction of first and
2076  * last bevel points matches direction of CV handle.
2077  *
2078  * This is getting calculated earlier when we know
2079  * CV's handles and here we might simply skip evaluation
2080  * of direction for this guys.
2081  */
2082 
2083  bevp0 = bl->bevpoints;
2084  bevp1 = bevp0 + 1;
2085  bevp2 = bevp1 + 1;
2086 
2087  nr = bl->nr - 2;
2088  }
2089 
2090  while (nr--) {
2091  /* totally simple */
2092  bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec);
2093 
2094  bevp0 = bevp1;
2095  bevp1 = bevp2;
2096  bevp2++;
2097  }
2098 
2099  /* In the unlikely situation that handles define a zeroed direction,
2100  * calculate it from the adjacent points, see T80742.
2101  *
2102  * Only do this as a fallback since we typically want the end-point directions
2103  * to be exactly aligned with the handles at the end-point, see T83117. */
2104  if (is_cyclic == false) {
2105  bevp0 = &bl->bevpoints[0];
2106  bevp1 = &bl->bevpoints[1];
2107  if (UNLIKELY(is_zero_v3(bevp0->dir))) {
2108  sub_v3_v3v3(bevp0->dir, bevp1->vec, bevp0->vec);
2109  if (normalize_v3(bevp0->dir) == 0.0f) {
2110  copy_v3_v3(bevp0->dir, bevp1->dir);
2111  }
2112  }
2113 
2114  bevp0 = &bl->bevpoints[bl->nr - 2];
2115  bevp1 = &bl->bevpoints[bl->nr - 1];
2116  if (UNLIKELY(is_zero_v3(bevp1->dir))) {
2117  sub_v3_v3v3(bevp1->dir, bevp1->vec, bevp0->vec);
2118  if (normalize_v3(bevp1->dir) == 0.0f) {
2119  copy_v3_v3(bevp1->dir, bevp0->dir);
2120  }
2121  }
2122  }
2123 }
2125 {
2126  BevPoint *bevp2, *bevp1, *bevp0;
2127  int nr;
2128 
2129  bevp2 = bl->bevpoints;
2130  bevp1 = bevp2 + (bl->nr - 1);
2131  bevp0 = bevp1 - 1;
2132 
2133  nr = bl->nr;
2134  while (nr--) {
2135  if (angle_normalized_v3v3(bevp0->tan, bevp1->tan) > DEG2RADF(90.0f)) {
2136  negate_v3(bevp1->tan);
2137  }
2138 
2139  bevp0 = bevp1;
2140  bevp1 = bevp2;
2141  bevp2++;
2142  }
2143 }
2144 /* apply user tilt */
2146 {
2147  BevPoint *bevp2, *bevp1;
2148  int nr;
2149  float q[4];
2150 
2151  bevp2 = bl->bevpoints;
2152  bevp1 = bevp2 + (bl->nr - 1);
2153 
2154  nr = bl->nr;
2155  while (nr--) {
2156  axis_angle_to_quat(q, bevp1->dir, bevp1->tilt);
2157  mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
2158  normalize_qt(bevp1->quat);
2159 
2160  bevp1 = bevp2;
2161  bevp2++;
2162  }
2163 }
2164 /* smooth quats, this function should be optimized, it can get slow with many iterations. */
2166 {
2167  BevPoint *bevp2, *bevp1, *bevp0;
2168  int nr;
2169 
2170  float q[4];
2171  float bevp0_quat[4];
2172  int a;
2173 
2174  for (a = 0; a < smooth_iter; a++) {
2175  bevp2 = bl->bevpoints;
2176  bevp1 = bevp2 + (bl->nr - 1);
2177  bevp0 = bevp1 - 1;
2178 
2179  nr = bl->nr;
2180 
2181  if (bl->poly == -1) { /* check its not cyclic */
2182  /* skip the first point */
2183  /* bevp0 = bevp1; */
2184  bevp1 = bevp2;
2185  bevp2++;
2186  nr--;
2187 
2188  bevp0 = bevp1;
2189  bevp1 = bevp2;
2190  bevp2++;
2191  nr--;
2192  }
2193 
2194  copy_qt_qt(bevp0_quat, bevp0->quat);
2195 
2196  while (nr--) {
2197  /* interpolate quats */
2198  float zaxis[3] = {0, 0, 1}, cross[3], q2[4];
2199  interp_qt_qtqt(q, bevp0_quat, bevp2->quat, 0.5);
2200  normalize_qt(q);
2201 
2202  mul_qt_v3(q, zaxis);
2203  cross_v3_v3v3(cross, zaxis, bevp1->dir);
2204  axis_angle_to_quat(q2, cross, angle_normalized_v3v3(zaxis, bevp1->dir));
2205  normalize_qt(q2);
2206 
2207  copy_qt_qt(bevp0_quat, bevp1->quat);
2208  mul_qt_qtqt(q, q2, q);
2209  interp_qt_qtqt(bevp1->quat, bevp1->quat, q, 0.5);
2210  normalize_qt(bevp1->quat);
2211 
2212  /* bevp0 = bevp1; */ /* UNUSED */
2213  bevp1 = bevp2;
2214  bevp2++;
2215  }
2216  }
2217 }
2218 
2220 {
2221  BevPoint *bevp = bl->bevpoints;
2222  int nr = bl->nr;
2223 
2225 
2226  while (nr--) {
2227  vec_to_quat(bevp->quat, bevp->dir, 5, 1);
2228  bevp++;
2229  }
2230 }
2231 
2232 static void minimum_twist_between_two_points(BevPoint *current_point, BevPoint *previous_point)
2233 {
2234  float angle = angle_normalized_v3v3(previous_point->dir, current_point->dir);
2235  float q[4];
2236 
2237  if (angle > 0.0f) { /* otherwise we can keep as is */
2238  float cross_tmp[3];
2239  cross_v3_v3v3(cross_tmp, previous_point->dir, current_point->dir);
2240  axis_angle_to_quat(q, cross_tmp, angle);
2241  mul_qt_qtqt(current_point->quat, q, previous_point->quat);
2242  }
2243  else {
2244  copy_qt_qt(current_point->quat, previous_point->quat);
2245  }
2246 }
2247 
2249 {
2250  BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
2251  int nr;
2252  float q[4];
2253 
2255 
2256  bevp2 = bl->bevpoints;
2257  bevp1 = bevp2 + (bl->nr - 1);
2258  bevp0 = bevp1 - 1;
2259 
2260  /* The ordinal of the point being adjusted (bevp2). First point is 1. */
2261 
2262  /* First point is the reference, don't adjust.
2263  * Skip this point in the following loop. */
2264  if (bl->nr > 0) {
2265  vec_to_quat(bevp2->quat, bevp2->dir, 5, 1);
2266 
2267  bevp0 = bevp1; /* bevp0 is unused */
2268  bevp1 = bevp2;
2269  bevp2++;
2270  }
2271  for (nr = 1; nr < bl->nr; nr++) {
2272  minimum_twist_between_two_points(bevp2, bevp1);
2273 
2274  bevp0 = bevp1; /* bevp0 is unused */
2275  bevp1 = bevp2;
2276  bevp2++;
2277  }
2278 
2279  if (bl->poly != -1) { /* check for cyclic */
2280 
2281  /* Need to correct for the start/end points not matching
2282  * do this by calculating the tilt angle difference, then apply
2283  * the rotation gradually over the entire curve.
2284  *
2285  * Note that the split is between last and second last, rather than first/last as you'd expect.
2286  *
2287  * real order is like this
2288  * 0,1,2,3,4 --> 1,2,3,4,0
2289  *
2290  * This is why we compare last with second last.
2291  */
2292  float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3];
2293 
2294  BevPoint *bevp_first;
2295  BevPoint *bevp_last;
2296 
2297  bevp_first = bl->bevpoints;
2298  bevp_first += bl->nr - 1;
2299  bevp_last = bevp_first;
2300  bevp_last--;
2301 
2302  /* quats and vec's are normalized, should not need to re-normalize */
2303  mul_qt_v3(bevp_first->quat, vec_1);
2304  mul_qt_v3(bevp_last->quat, vec_2);
2305  normalize_v3(vec_1);
2306  normalize_v3(vec_2);
2307 
2308  /* align the vector, can avoid this and it looks 98% OK but
2309  * better to align the angle quat roll's before comparing */
2310  {
2311  cross_v3_v3v3(cross_tmp, bevp_last->dir, bevp_first->dir);
2312  angle = angle_normalized_v3v3(bevp_first->dir, bevp_last->dir);
2313  axis_angle_to_quat(q, cross_tmp, angle);
2314  mul_qt_v3(q, vec_2);
2315  }
2316 
2317  angle = angle_normalized_v3v3(vec_1, vec_2);
2318 
2319  /* flip rotation if needs be */
2320  cross_v3_v3v3(cross_tmp, vec_1, vec_2);
2321  normalize_v3(cross_tmp);
2322  if (angle_normalized_v3v3(bevp_first->dir, cross_tmp) < DEG2RADF(90.0f)) {
2323  angle = -angle;
2324  }
2325 
2326  bevp2 = bl->bevpoints;
2327  bevp1 = bevp2 + (bl->nr - 1);
2328  bevp0 = bevp1 - 1;
2329 
2330  nr = bl->nr;
2331  while (nr--) {
2332  ang_fac = angle * (1.0f - ((float)nr / bl->nr)); /* also works */
2333 
2334  axis_angle_to_quat(q, bevp1->dir, ang_fac);
2335  mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
2336 
2337  bevp0 = bevp1;
2338  bevp1 = bevp2;
2339  bevp2++;
2340  }
2341  }
2342  else {
2343  /* Need to correct quat for the first/last point,
2344  * this is so because previously it was only calculated
2345  * using its own direction, which might not correspond
2346  * the twist of neighbor point.
2347  */
2348  bevp1 = bl->bevpoints;
2349  bevp0 = bevp1 + 1;
2350  minimum_twist_between_two_points(bevp1, bevp0);
2351 
2352  bevp2 = bl->bevpoints;
2353  bevp1 = bevp2 + (bl->nr - 1);
2354  bevp0 = bevp1 - 1;
2355  minimum_twist_between_two_points(bevp1, bevp0);
2356  }
2357 }
2358 
2360 {
2361  BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
2362  int nr;
2363 
2364  float bevp0_tan[3];
2365 
2368 
2369  /* correct the tangents */
2370  bevp2 = bl->bevpoints;
2371  bevp1 = bevp2 + (bl->nr - 1);
2372  bevp0 = bevp1 - 1;
2373 
2374  nr = bl->nr;
2375  while (nr--) {
2376  float cross_tmp[3];
2377  cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir);
2378  cross_v3_v3v3(bevp1->tan, cross_tmp, bevp1->dir);
2379  normalize_v3(bevp1->tan);
2380 
2381  bevp0 = bevp1;
2382  bevp1 = bevp2;
2383  bevp2++;
2384  }
2385 
2386  /* now for the real twist calc */
2387  bevp2 = bl->bevpoints;
2388  bevp1 = bevp2 + (bl->nr - 1);
2389  bevp0 = bevp1 - 1;
2390 
2391  copy_v3_v3(bevp0_tan, bevp0->tan);
2392 
2393  nr = bl->nr;
2394  while (nr--) {
2395  /* make perpendicular, modify tan in place, is ok */
2396  float cross_tmp[3];
2397  const float zero[3] = {0, 0, 0};
2398 
2399  cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir);
2400  normalize_v3(cross_tmp);
2401  tri_to_quat(bevp1->quat, zero, cross_tmp, bevp1->tan); /* XXX: could be faster. */
2402 
2403  /* bevp0 = bevp1; */ /* UNUSED */
2404  bevp1 = bevp2;
2405  bevp2++;
2406  }
2407 }
2408 
2409 static void make_bevel_list_3D(BevList *bl, int smooth_iter, int twist_mode)
2410 {
2411  switch (twist_mode) {
2412  case CU_TWIST_TANGENT:
2414  break;
2415  case CU_TWIST_MINIMUM:
2417  break;
2418  default: /* CU_TWIST_Z_UP default, pre 2.49c */
2420  break;
2421  }
2422 
2423  if (smooth_iter) {
2425  }
2426 
2428 }
2429 
2430 /* only for 2 points */
2432 {
2433  float q[4];
2434 
2435  BevPoint *bevp2 = bl->bevpoints;
2436  BevPoint *bevp1 = bevp2 + 1;
2437 
2438  /* simple quat/dir */
2439  sub_v3_v3v3(bevp1->dir, bevp1->vec, bevp2->vec);
2440  normalize_v3(bevp1->dir);
2441 
2442  vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
2443  axis_angle_to_quat(q, bevp1->dir, bevp1->tilt);
2444  mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
2445  normalize_qt(bevp1->quat);
2446 
2447  copy_v3_v3(bevp2->dir, bevp1->dir);
2448  vec_to_quat(bevp2->quat, bevp2->dir, 5, 1);
2449  axis_angle_to_quat(q, bevp2->dir, bevp2->tilt);
2450  mul_qt_qtqt(bevp2->quat, q, bevp2->quat);
2451  normalize_qt(bevp2->quat);
2452 }
2453 
2454 /* only for 2 points */
2456 {
2457  BevPoint *bevp2 = bl->bevpoints;
2458  BevPoint *bevp1 = bevp2 + 1;
2459 
2460  const float x1 = bevp1->vec[0] - bevp2->vec[0];
2461  const float y1 = bevp1->vec[1] - bevp2->vec[1];
2462 
2463  calc_bevel_sin_cos(x1, y1, -x1, -y1, &(bevp1->sina), &(bevp1->cosa));
2464  bevp2->sina = bevp1->sina;
2465  bevp2->cosa = bevp1->cosa;
2466 
2467  /* fill in dir & quat */
2469 }
2470 
2472 {
2473  /* NOTE(campbell): `bevp->dir` and `bevp->quat` are not needed for beveling but are
2474  * used when making a path from a 2D curve, therefore they need to be set. */
2475 
2476  BevPoint *bevp0, *bevp1, *bevp2;
2477  int nr;
2478 
2479  if (bl->poly != -1) {
2480  bevp2 = bl->bevpoints;
2481  bevp1 = bevp2 + (bl->nr - 1);
2482  bevp0 = bevp1 - 1;
2483  nr = bl->nr;
2484  }
2485  else {
2486  bevp0 = bl->bevpoints;
2487  bevp1 = bevp0 + 1;
2488  bevp2 = bevp1 + 1;
2489 
2490  nr = bl->nr - 2;
2491  }
2492 
2493  while (nr--) {
2494  const float x1 = bevp1->vec[0] - bevp0->vec[0];
2495  const float x2 = bevp1->vec[0] - bevp2->vec[0];
2496  const float y1 = bevp1->vec[1] - bevp0->vec[1];
2497  const float y2 = bevp1->vec[1] - bevp2->vec[1];
2498 
2499  calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
2500 
2501  /* from: make_bevel_list_3D_zup, could call but avoid a second loop.
2502  * no need for tricky tilt calculation as with 3D curves */
2503  bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec);
2504  vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
2505  /* done with inline make_bevel_list_3D_zup */
2506 
2507  bevp0 = bevp1;
2508  bevp1 = bevp2;
2509  bevp2++;
2510  }
2511 
2512  /* correct non-cyclic cases */
2513  if (bl->poly == -1) {
2514  BevPoint *bevp;
2515  float angle;
2516 
2517  /* first */
2518  bevp = bl->bevpoints;
2519  angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2;
2520  bevp->sina = sinf(angle);
2521  bevp->cosa = cosf(angle);
2522  vec_to_quat(bevp->quat, bevp->dir, 5, 1);
2523 
2524  /* last */
2525  bevp = bl->bevpoints;
2526  bevp += (bl->nr - 1);
2527  angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2;
2528  bevp->sina = sinf(angle);
2529  bevp->cosa = cosf(angle);
2530  vec_to_quat(bevp->quat, bevp->dir, 5, 1);
2531  }
2532 }
2533 
2535 {
2536  if (nu->pntsu > 1) {
2537  BPoint *first_bp = nu->bp, *last_bp = nu->bp + (nu->pntsu - 1);
2538  BevPoint *first_bevp, *last_bevp;
2539 
2540  first_bevp = bl->bevpoints;
2541  last_bevp = first_bevp + (bl->nr - 1);
2542 
2543  sub_v3_v3v3(first_bevp->dir, (first_bp + 1)->vec, first_bp->vec);
2544  normalize_v3(first_bevp->dir);
2545 
2546  sub_v3_v3v3(last_bevp->dir, last_bp->vec, (last_bp - 1)->vec);
2547  normalize_v3(last_bevp->dir);
2548  }
2549 }
2550 
2552 {
2553  LISTBASE_FOREACH_MUTABLE (BevList *, bl, bev) {
2554  if (bl->seglen != nullptr) {
2555  MEM_freeN(bl->seglen);
2556  }
2557  if (bl->segbevcount != nullptr) {
2559  }
2560  if (bl->bevpoints != nullptr) {
2562  }
2563  MEM_freeN(bl);
2564  }
2565 
2566  BLI_listbase_clear(bev);
2567 }
2568 
2569 void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_render)
2570 {
2571  /* - Convert all curves to polys, with indication of resolution and flags for double-vertices.
2572  * - Possibly; do a smart vertex removal (in case #Nurb).
2573  * - Separate in individual blocks with #BoundBox.
2574  * - Auto-hole detection.
2575  */
2576 
2577  /* This function needs an object, because of `tflag` and `upflag`. */
2578  Curve *cu = (Curve *)ob->data;
2579  BezTriple *bezt, *prevbezt;
2580  BPoint *bp;
2581  BevList *blnew;
2582  BevPoint *bevp2, *bevp1 = nullptr, *bevp0;
2583  const float threshold = 0.00001f;
2584  float min, inp;
2585  float *seglen = nullptr;
2586  struct BevelSort *sortdata, *sd, *sd1;
2587  int a, b, nr, poly, resolu = 0, len = 0, segcount;
2588  int *segbevcount;
2589  bool do_tilt, do_radius, do_weight;
2590  bool is_editmode = false;
2591  ListBase *bev;
2592 
2593  /* segbevcount also requires seglen. */
2594  const bool need_seglen = ELEM(
2597 
2598  bev = &ob->runtime.curve_cache->bev;
2599 
2600 #if 0
2601  /* do we need to calculate the radius for each point? */
2602  do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 :
2603  1;
2604 #endif
2605 
2606  /* STEP 1: MAKE POLYS */
2607 
2609  if (cu->editnurb && ob->type != OB_FONT) {
2610  is_editmode = true;
2611  }
2612 
2613  LISTBASE_FOREACH (const Nurb *, nu, nurbs) {
2614  if (nu->hide && is_editmode) {
2615  continue;
2616  }
2617 
2618  /* check we are a single point? also check we are not a surface and that the orderu is sane,
2619  * enforced in the UI but can go wrong possibly */
2620  if (!BKE_nurb_check_valid_u(nu)) {
2621  BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), "makeBevelList1");
2622  bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
2623  BLI_addtail(bev, bl);
2624  bl->nr = 0;
2625  bl->charidx = nu->charidx;
2626  continue;
2627  }
2628 
2629  /* Tilt, as the rotation angle of curve control points, is only calculated for 3D curves,
2630  * (since this transformation affects the 3D space). */
2631  do_tilt = (cu->flag & CU_3D) != 0;
2632 
2633  /* Normal display uses the radius, better just to calculate them. */
2634  do_radius = CU_DO_RADIUS(cu, nu);
2635 
2636  do_weight = true;
2637 
2638  BevPoint *bevp;
2639 
2640  if (for_render && cu->resolu_ren != 0) {
2641  resolu = cu->resolu_ren;
2642  }
2643  else {
2644  resolu = nu->resolu;
2645  }
2646 
2647  segcount = SEGMENTSU(nu);
2648 
2649  if (nu->type == CU_POLY) {
2650  len = nu->pntsu;
2651  BevList *bl = MEM_cnew<BevList>(__func__);
2652  bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
2653  if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
2654  bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
2655  bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
2656  }
2657  BLI_addtail(bev, bl);
2658 
2659  bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
2660  bl->nr = len;
2661  bl->dupe_nr = 0;
2662  bl->charidx = nu->charidx;
2663  bevp = bl->bevpoints;
2664  bevp->offset = 0;
2665  bp = nu->bp;
2666  seglen = bl->seglen;
2667  segbevcount = bl->segbevcount;
2668 
2669  while (len--) {
2670  copy_v3_v3(bevp->vec, bp->vec);
2671  bevp->tilt = bp->tilt;
2672  bevp->radius = bp->radius;
2673  bevp->weight = bp->weight;
2674  bp++;
2675  if (seglen != nullptr && len != 0) {
2676  *seglen = len_v3v3(bevp->vec, bp->vec);
2677  bevp++;
2678  bevp->offset = *seglen;
2679  if (*seglen > threshold) {
2680  *segbevcount = 1;
2681  }
2682  else {
2683  *segbevcount = 0;
2684  }
2685  seglen++;
2686  segbevcount++;
2687  }
2688  else {
2689  bevp++;
2690  }
2691  }
2692 
2693  if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
2695  }
2696  }
2697  else if (nu->type == CU_BEZIER) {
2698  /* in case last point is not cyclic */
2699  len = segcount * resolu + 1;
2700 
2701  BevList *bl = MEM_cnew<BevList>(__func__);
2702  bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
2703  if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
2704  bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
2705  bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
2706  }
2707  BLI_addtail(bev, bl);
2708 
2709  bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
2710  bl->charidx = nu->charidx;
2711 
2712  bevp = bl->bevpoints;
2713  seglen = bl->seglen;
2714  segbevcount = bl->segbevcount;
2715 
2716  bevp->offset = 0;
2717  if (seglen != nullptr) {
2718  *seglen = 0;
2719  *segbevcount = 0;
2720  }
2721 
2722  a = nu->pntsu - 1;
2723  bezt = nu->bezt;
2724  if (nu->flagu & CU_NURB_CYCLIC) {
2725  a++;
2726  prevbezt = nu->bezt + (nu->pntsu - 1);
2727  }
2728  else {
2729  prevbezt = bezt;
2730  bezt++;
2731  }
2732 
2733  sub_v3_v3v3(bevp->dir, prevbezt->vec[2], prevbezt->vec[1]);
2734  normalize_v3(bevp->dir);
2735 
2736  BLI_assert(segcount >= a);
2737 
2738  while (a--) {
2739  if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
2740 
2741  copy_v3_v3(bevp->vec, prevbezt->vec[1]);
2742  bevp->tilt = prevbezt->tilt;
2743  bevp->radius = prevbezt->radius;
2744  bevp->weight = prevbezt->weight;
2745  bevp->dupe_tag = false;
2746  bevp++;
2747  bl->nr++;
2748  bl->dupe_nr = 1;
2749  if (seglen != nullptr) {
2750  *seglen = len_v3v3(prevbezt->vec[1], bezt->vec[1]);
2751  bevp->offset = *seglen;
2752  seglen++;
2753  /* match segbevcount to the cleaned up bevel lists (see STEP 2) */
2754  if (bevp->offset > threshold) {
2755  *segbevcount = 1;
2756  }
2757  segbevcount++;
2758  }
2759  }
2760  else {
2761  /* Always do all three, to prevent data hanging around. */
2762  int j;
2763 
2764  /* #BevPoint must stay aligned to 4 so `sizeof(BevPoint) / sizeof(float)` works. */
2765  for (j = 0; j < 3; j++) {
2766  BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
2767  prevbezt->vec[2][j],
2768  bezt->vec[0][j],
2769  bezt->vec[1][j],
2770  &(bevp->vec[j]),
2771  resolu,
2772  sizeof(BevPoint));
2773  }
2774 
2775  /* If both arrays are `nullptr` do nothing. */
2776  tilt_bezpart(prevbezt,
2777  bezt,
2778  nu,
2779  do_tilt ? &bevp->tilt : nullptr,
2780  do_radius ? &bevp->radius : nullptr,
2781  do_weight ? &bevp->weight : nullptr,
2782  resolu,
2783  sizeof(BevPoint));
2784 
2785  if (cu->twist_mode == CU_TWIST_TANGENT) {
2786  forward_diff_bezier_cotangent(prevbezt->vec[1],
2787  prevbezt->vec[2],
2788  bezt->vec[0],
2789  bezt->vec[1],
2790  bevp->tan,
2791  resolu,
2792  sizeof(BevPoint));
2793  }
2794 
2795  /* `seglen`. */
2796  if (seglen != nullptr) {
2797  *seglen = 0;
2798  *segbevcount = 0;
2799  for (j = 0; j < resolu; j++) {
2800  bevp0 = bevp;
2801  bevp++;
2802  bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
2803  /* Match `seglen` and `segbevcount` to the cleaned up bevel lists (see STEP 2). */
2804  if (bevp->offset > threshold) {
2805  *seglen += bevp->offset;
2806  *segbevcount += 1;
2807  }
2808  }
2809  seglen++;
2810  segbevcount++;
2811  }
2812  else {
2813  bevp += resolu;
2814  }
2815  bl->nr += resolu;
2816  }
2817  prevbezt = bezt;
2818  bezt++;
2819  }
2820 
2821  if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic: endpoint */
2822  copy_v3_v3(bevp->vec, prevbezt->vec[1]);
2823  bevp->tilt = prevbezt->tilt;
2824  bevp->radius = prevbezt->radius;
2825  bevp->weight = prevbezt->weight;
2826 
2827  sub_v3_v3v3(bevp->dir, prevbezt->vec[1], prevbezt->vec[0]);
2828  normalize_v3(bevp->dir);
2829 
2830  bl->nr++;
2831  }
2832  }
2833  else if (nu->type == CU_NURBS) {
2834  if (nu->pntsv == 1) {
2835  len = (resolu * segcount);
2836 
2837  BevList *bl = MEM_cnew<BevList>(__func__);
2838  bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
2839  if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
2840  bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
2841  bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
2842  }
2843  BLI_addtail(bev, bl);
2844  bl->nr = len;
2845  bl->dupe_nr = 0;
2846  bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
2847  bl->charidx = nu->charidx;
2848 
2849  bevp = bl->bevpoints;
2850  seglen = bl->seglen;
2851  segbevcount = bl->segbevcount;
2852 
2853  BKE_nurb_makeCurve(nu,
2854  &bevp->vec[0],
2855  do_tilt ? &bevp->tilt : nullptr,
2856  do_radius ? &bevp->radius : nullptr,
2857  do_weight ? &bevp->weight : nullptr,
2858  resolu,
2859  sizeof(BevPoint));
2860 
2861  /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
2862  if (seglen != nullptr) {
2863  nr = segcount;
2864  bevp0 = bevp;
2865  bevp++;
2866  while (nr) {
2867  int j;
2868  *seglen = 0;
2869  *segbevcount = 0;
2870  /* We keep last bevel segment zero-length. */
2871  for (j = 0; j < ((nr == 1) ? (resolu - 1) : resolu); j++) {
2872  bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
2873  if (bevp->offset > threshold) {
2874  *seglen += bevp->offset;
2875  *segbevcount += 1;
2876  }
2877  bevp0 = bevp;
2878  bevp++;
2879  }
2880  seglen++;
2881  segbevcount++;
2882  nr--;
2883  }
2884  }
2885 
2886  if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
2888  }
2889  }
2890  }
2891  }
2892 
2893  /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */
2894  LISTBASE_FOREACH (BevList *, bl, bev) {
2895  if (bl->nr == 0) { /* null bevel items come from single points */
2896  continue;
2897  }
2898 
2899  /* Scale the threshold so high resolution shapes don't get over reduced, see: T49850. */
2900  const float threshold_resolu = 0.00001f / resolu;
2901  bool is_cyclic = bl->poly != -1;
2902  nr = bl->nr;
2903  if (is_cyclic) {
2904  bevp1 = bl->bevpoints;
2905  bevp0 = bevp1 + (nr - 1);
2906  }
2907  else {
2908  bevp0 = bl->bevpoints;
2909  bevp0->offset = 0;
2910  bevp1 = bevp0 + 1;
2911  }
2912  nr--;
2913  while (nr--) {
2914  if (seglen != nullptr) {
2915  if (fabsf(bevp1->offset) < threshold) {
2916  bevp0->dupe_tag = true;
2917  bl->dupe_nr++;
2918  }
2919  }
2920  else {
2921  if (compare_v3v3(bevp0->vec, bevp1->vec, threshold_resolu)) {
2922  bevp0->dupe_tag = true;
2923  bl->dupe_nr++;
2924  }
2925  }
2926  bevp0 = bevp1;
2927  bevp1++;
2928  }
2929  }
2930 
2931  LISTBASE_FOREACH_MUTABLE (BevList *, bl, bev) {
2932  if (bl->nr == 0 || bl->dupe_nr == 0) {
2933  continue;
2934  }
2935 
2936  nr = bl->nr - bl->dupe_nr + 1; /* +1 because vector-bezier sets flag too. */
2937  blnew = (BevList *)MEM_mallocN(sizeof(BevList), "makeBevelList4");
2938  memcpy(blnew, bl, sizeof(BevList));
2939  blnew->bevpoints = (BevPoint *)MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
2940  if (!blnew->bevpoints) {
2941  MEM_freeN(blnew);
2942  break;
2943  }
2944  blnew->segbevcount = bl->segbevcount;
2945  blnew->seglen = bl->seglen;
2946  blnew->nr = 0;
2947  BLI_remlink(bev, bl);
2948  BLI_insertlinkbefore(bev, bl->next, blnew); /* Ensure `bevlist` is tuned with `nurblist`. */
2949  bevp0 = bl->bevpoints;
2950  bevp1 = blnew->bevpoints;
2951  nr = bl->nr;
2952  while (nr--) {
2953  if (bevp0->dupe_tag == 0) {
2954  memcpy(bevp1, bevp0, sizeof(BevPoint));
2955  bevp1++;
2956  blnew->nr++;
2957  }
2958  bevp0++;
2959  }
2960  if (bl->bevpoints != nullptr) {
2962  }
2963  MEM_freeN(bl);
2964  blnew->dupe_nr = 0;
2965  }
2966 
2967  /* STEP 3: POLYS COUNT AND AUTOHOLE */
2968  poly = 0;
2969  LISTBASE_FOREACH (BevList *, bl, bev) {
2970  if (bl->nr && bl->poly >= 0) {
2971  poly++;
2972  bl->poly = poly;
2973  bl->hole = 0;
2974  }
2975  }
2976 
2977  /* find extreme left points, also test (turning) direction */
2978  if (poly > 0) {
2979  sd = sortdata = (BevelSort *)MEM_malloc_arrayN(poly, sizeof(struct BevelSort), __func__);
2980  LISTBASE_FOREACH (BevList *, bl, bev) {
2981  if (bl->poly > 0) {
2982  BevPoint *bevp;
2983 
2984  bevp = bl->bevpoints;
2985  bevp1 = bl->bevpoints;
2986  min = bevp1->vec[0];
2987  nr = bl->nr;
2988  while (nr--) {
2989  if (min > bevp->vec[0]) {
2990  min = bevp->vec[0];
2991  bevp1 = bevp;
2992  }
2993  bevp++;
2994  }
2995  sd->bl = bl;
2996  sd->left = min;
2997 
2998  bevp = bl->bevpoints;
2999  if (bevp1 == bevp) {
3000  bevp0 = bevp + (bl->nr - 1);
3001  }
3002  else {
3003  bevp0 = bevp1 - 1;
3004  }
3005  bevp = bevp + (bl->nr - 1);
3006  if (bevp1 == bevp) {
3007  bevp2 = bl->bevpoints;
3008  }
3009  else {
3010  bevp2 = bevp1 + 1;
3011  }
3012 
3013  inp = ((bevp1->vec[0] - bevp0->vec[0]) * (bevp0->vec[1] - bevp2->vec[1]) +
3014  (bevp0->vec[1] - bevp1->vec[1]) * (bevp0->vec[0] - bevp2->vec[0]));
3015 
3016  if (inp > 0.0f) {
3017  sd->dir = 1;
3018  }
3019  else {
3020  sd->dir = 0;
3021  }
3022 
3023  sd++;
3024  }
3025  }
3026  qsort(sortdata, poly, sizeof(struct BevelSort), vergxcobev);
3027 
3028  sd = sortdata + 1;
3029  for (a = 1; a < poly; a++, sd++) {
3030  BevList *bl = sd->bl; /* is bl a hole? */
3031  sd1 = sortdata + (a - 1);
3032  for (b = a - 1; b >= 0; b--, sd1--) { /* all polys to the left */
3033  if (sd1->bl->charidx == bl->charidx) { /* for text, only check matching char */
3034  if (bevelinside(sd1->bl, bl)) {
3035  bl->hole = 1 - sd1->bl->hole;
3036  break;
3037  }
3038  }
3039  }
3040  }
3041 
3042  /* turning direction */
3043  if (CU_IS_2D(cu)) {
3044  sd = sortdata;
3045  for (a = 0; a < poly; a++, sd++) {
3046  if (sd->bl->hole == sd->dir) {
3047  BevList *bl = sd->bl;
3048  bevp1 = bl->bevpoints;
3049  bevp2 = bevp1 + (bl->nr - 1);
3050  nr = bl->nr / 2;
3051  while (nr--) {
3052  SWAP(BevPoint, *bevp1, *bevp2);
3053  bevp1++;
3054  bevp2--;
3055  }
3056  }
3057  }
3058  }
3059  MEM_freeN(sortdata);
3060  }
3061 
3062  /* STEP 4: 2D-COSINES or 3D ORIENTATION */
3063  if (CU_IS_2D(cu)) {
3064  /* 2D Curves */
3065  LISTBASE_FOREACH (BevList *, bl, bev) {
3066  if (bl->nr < 2) {
3067  BevPoint *bevp = bl->bevpoints;
3068  unit_qt(bevp->quat);
3069  }
3070  else if (bl->nr == 2) { /* 2 points, treat separately. */
3072  }
3073  else {
3075  }
3076  }
3077  }
3078  else {
3079  /* 3D Curves */
3080  LISTBASE_FOREACH (BevList *, bl, bev) {
3081  if (bl->nr < 2) {
3082  BevPoint *bevp = bl->bevpoints;
3083  unit_qt(bevp->quat);
3084  }
3085  else if (bl->nr == 2) { /* 2 points, treat separately. */
3087  }
3088  else {
3089  make_bevel_list_3D(bl, (int)(resolu * cu->twist_smooth), cu->twist_mode);
3090  }
3091  }
3092  }
3093 }
3094 
3095 /* ****************** HANDLES ************** */
3096 
3098  const BezTriple *prev,
3099  const BezTriple *next,
3100  eBezTriple_Flag handle_sel_flag,
3101  bool is_fcurve,
3102  bool skip_align,
3103  char fcurve_smoothing)
3104 {
3105  /* defines to avoid confusion */
3106 #define p2_h1 ((p2)-3)
3107 #define p2_h2 ((p2) + 3)
3108 
3109  const float *p1, *p3;
3110  float *p2;
3111  float pt[3];
3112  float dvec_a[3], dvec_b[3];
3113  float len, len_a, len_b;
3114  const float eps = 1e-5;
3115 
3116  /* assume normal handle until we check */
3118 
3119  if (bezt->h1 == 0 && bezt->h2 == 0) {
3120  return;
3121  }
3122 
3123  p2 = bezt->vec[1];
3124 
3125  if (prev == nullptr) {
3126  p3 = next->vec[1];
3127  pt[0] = 2.0f * p2[0] - p3[0];
3128  pt[1] = 2.0f * p2[1] - p3[1];
3129  pt[2] = 2.0f * p2[2] - p3[2];
3130  p1 = pt;
3131  }
3132  else {
3133  p1 = prev->vec[1];
3134  }
3135 
3136  if (next == nullptr) {
3137  pt[0] = 2.0f * p2[0] - p1[0];
3138  pt[1] = 2.0f * p2[1] - p1[1];
3139  pt[2] = 2.0f * p2[2] - p1[2];
3140  p3 = pt;
3141  }
3142  else {
3143  p3 = next->vec[1];
3144  }
3145 
3146  sub_v3_v3v3(dvec_a, p2, p1);
3147  sub_v3_v3v3(dvec_b, p3, p2);
3148 
3149  if (is_fcurve) {
3150  len_a = dvec_a[0];
3151  len_b = dvec_b[0];
3152  }
3153  else {
3154  len_a = len_v3(dvec_a);
3155  len_b = len_v3(dvec_b);
3156  }
3157 
3158  if (len_a == 0.0f) {
3159  len_a = 1.0f;
3160  }
3161  if (len_b == 0.0f) {
3162  len_b = 1.0f;
3163  }
3164 
3165  if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */
3166  float tvec[3];
3167  tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
3168  tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
3169  tvec[2] = dvec_b[2] / len_b + dvec_a[2] / len_a;
3170 
3171  if (is_fcurve) {
3172  if (fcurve_smoothing != FCURVE_SMOOTH_NONE) {
3173  /* force the horizontal handle size to be 1/3 of the key interval so that
3174  * the X component of the parametric bezier curve is a linear spline */
3175  len = 6.0f / 2.5614f;
3176  }
3177  else {
3178  len = tvec[0];
3179  }
3180  }
3181  else {
3182  len = len_v3(tvec);
3183  }
3184  len *= 2.5614f;
3185 
3186  if (len != 0.0f) {
3187  /* Only for F-Curves. */
3188  bool leftviolate = false, rightviolate = false;
3189 
3190  if (!is_fcurve || fcurve_smoothing == FCURVE_SMOOTH_NONE) {
3191  if (len_a > 5.0f * len_b) {
3192  len_a = 5.0f * len_b;
3193  }
3194  if (len_b > 5.0f * len_a) {
3195  len_b = 5.0f * len_a;
3196  }
3197  }
3198 
3199  if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
3200  len_a /= len;
3201  madd_v3_v3v3fl(p2_h1, p2, tvec, -len_a);
3202 
3203  if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
3204  float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
3205  float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
3206  if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
3207  bezt->vec[0][1] = bezt->vec[1][1];
3209  }
3210  else { /* handles should not be beyond y coord of two others */
3211  if (ydiff1 <= 0.0f) {
3212  if (prev->vec[1][1] > bezt->vec[0][1]) {
3213  bezt->vec[0][1] = prev->vec[1][1];
3214  leftviolate = true;
3215  }
3216  }
3217  else {
3218  if (prev->vec[1][1] < bezt->vec[0][1]) {
3219  bezt->vec[0][1] = prev->vec[1][1];
3220  leftviolate = true;
3221  }
3222  }
3223  }
3224  }
3225  }
3226  if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
3227  len_b /= len;
3228  madd_v3_v3v3fl(p2_h2, p2, tvec, len_b);
3229 
3230  if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
3231  float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
3232  float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
3233  if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
3234  bezt->vec[2][1] = bezt->vec[1][1];
3236  }
3237  else { /* handles should not be beyond y coord of two others */
3238  if (ydiff1 <= 0.0f) {
3239  if (next->vec[1][1] < bezt->vec[2][1]) {
3240  bezt->vec[2][1] = next->vec[1][1];
3241  rightviolate = true;
3242  }
3243  }
3244  else {
3245  if (next->vec[1][1] > bezt->vec[2][1]) {
3246  bezt->vec[2][1] = next->vec[1][1];
3247  rightviolate = true;
3248  }
3249  }
3250  }
3251  }
3252  }
3253  if (leftviolate || rightviolate) { /* align left handle */
3254  BLI_assert(is_fcurve);
3255  /* simple 2d calculation */
3256  float h1_x = p2_h1[0] - p2[0];
3257  float h2_x = p2[0] - p2_h2[0];
3258 
3259  if (leftviolate) {
3260  p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x;
3261  }
3262  else {
3263  p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x;
3264  }
3265  }
3266  }
3267  }
3268 
3269  if (bezt->h1 == HD_VECT) { /* vector */
3270  madd_v3_v3v3fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
3271  }
3272  if (bezt->h2 == HD_VECT) {
3273  madd_v3_v3v3fl(p2_h2, p2, dvec_b, 1.0f / 3.0f);
3274  }
3275 
3276  if (skip_align ||
3277  /* When one handle is free, aligning makes no sense, see: T35952 */
3278  ELEM(HD_FREE, bezt->h1, bezt->h2) ||
3279  /* Also when no handles are aligned, skip this step. */
3280  (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) {
3281  /* Handles need to be updated during animation and applying stuff like hooks,
3282  * but in such situations it's quite difficult to distinguish in which order
3283  * align handles should be aligned so skip them for now. */
3284  return;
3285  }
3286 
3287  len_a = len_v3v3(p2, p2_h1);
3288  len_b = len_v3v3(p2, p2_h2);
3289 
3290  if (len_a == 0.0f) {
3291  len_a = 1.0f;
3292  }
3293  if (len_b == 0.0f) {
3294  len_b = 1.0f;
3295  }
3296 
3297  const float len_ratio = len_a / len_b;
3298 
3299  if (bezt->f1 & handle_sel_flag) { /* order of calculation */
3300  if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */
3301  if (len_a > eps) {
3302  len = 1.0f / len_ratio;
3303  p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]);
3304  p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]);
3305  p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]);
3306  }
3307  }
3308  if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
3309  if (len_b > eps) {
3310  len = len_ratio;
3311  p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]);
3312  p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]);
3313  p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]);
3314  }
3315  }
3316  }
3317  else {
3318  if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
3319  if (len_b > eps) {
3320  len = len_ratio;
3321  p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]);
3322  p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]);
3323  p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]);
3324  }
3325  }
3326  if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */
3327  if (len_a > eps) {
3328  len = 1.0f / len_ratio;
3329  p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]);
3330  p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]);
3331  p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]);
3332  }
3333  }
3334  }
3335 
3336 #undef p2_h1
3337 #undef p2_h2
3338 }
3339 
3340 static void calchandlesNurb_intern(Nurb *nu, eBezTriple_Flag handle_sel_flag, bool skip_align)
3341 {
3342  BezTriple *bezt, *prev, *next;
3343  int a;
3344 
3345  if (nu->type != CU_BEZIER) {
3346  return;
3347  }
3348  if (nu->pntsu < 2) {
3349  return;
3350  }
3351 
3352  a = nu->pntsu;
3353  bezt = nu->bezt;
3354  if (nu->flagu & CU_NURB_CYCLIC) {
3355  prev = bezt + (a - 1);
3356  }
3357  else {
3358  prev = nullptr;
3359  }
3360  next = bezt + 1;
3361 
3362  while (a--) {
3363  calchandleNurb_intern(bezt, prev, next, handle_sel_flag, false, skip_align, 0);
3364  prev = bezt;
3365  if (a == 1) {
3366  if (nu->flagu & CU_NURB_CYCLIC) {
3367  next = nu->bezt;
3368  }
3369  else {
3370  next = nullptr;
3371  }
3372  }
3373  else {
3374  next++;
3375  }
3376 
3377  bezt++;
3378  }
3379 }
3380 
3391 static void *allocate_arrays(int count, float ***floats, char ***chars, const char *name)
3392 {
3393  size_t num_floats = 0, num_chars = 0;
3394 
3395  while (floats && floats[num_floats]) {
3396  num_floats++;
3397  }
3398 
3399  while (chars && chars[num_chars]) {
3400  num_chars++;
3401  }
3402 
3403  void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name);
3404 
3405  if (!buffer) {
3406  return nullptr;
3407  }
3408 
3409  float *fptr = (float *)buffer;
3410 
3411  for (int i = 0; i < num_floats; i++, fptr += count) {
3412  *floats[i] = fptr;
3413  }
3414 
3415  char *cptr = (char *)fptr;
3416 
3417  for (int i = 0; i < num_chars; i++, cptr += count) {
3418  *chars[i] = cptr;
3419  }
3420 
3421  return buffer;
3422 }
3423 
3424 static void free_arrays(void *buffer)
3425 {
3426  MEM_freeN(buffer);
3427 }
3428 
3429 /* computes in which direction to change h[i] to satisfy conditions better */
3430 static float bezier_relax_direction(const float *a,
3431  const float *b,
3432  const float *c,
3433  const float *d,
3434  const float *h,
3435  int i,
3436  int count)
3437 {
3438  /* current deviation between sides of the equation */
3439  float state = a[i] * h[(i + count - 1) % count] + b[i] * h[i] + c[i] * h[(i + 1) % count] - d[i];
3440 
3441  /* only the sign is meaningful */
3442  return -state * b[i];
3443 }
3444 
3445 static void bezier_lock_unknown(float *a, float *b, float *c, float *d, int i, float value)
3446 {
3447  a[i] = c[i] = 0.0f;
3448  b[i] = 1.0f;
3449  d[i] = value;
3450 }
3451 
3452 static void bezier_restore_equation(float *a,
3453  float *b,
3454  float *c,
3455  float *d,
3456  const float *a0,
3457  const float *b0,
3458  const float *c0,
3459  const float *d0,
3460  int i)
3461 {
3462  a[i] = a0[i];
3463  b[i] = b0[i];
3464  c[i] = c0[i];
3465  d[i] = d0[i];
3466 }
3467 
3469  float *b,
3470  float *c,
3471  float *d,
3472  float *h,
3473  const float *hmin,
3474  const float *hmax,
3475  int solve_count)
3476 {
3477  float *a0, *b0, *c0, *d0;
3478  float **arrays[] = {&a0, &b0, &c0, &d0, nullptr};
3479  char *is_locked, *num_unlocks;
3480  char **flagarrays[] = {&is_locked, &num_unlocks, nullptr};
3481 
3482  void *tmps = allocate_arrays(solve_count, arrays, flagarrays, "tridiagonal_solve_with_limits");
3483  if (!tmps) {
3484  return false;
3485  }
3486 
3487  memcpy(a0, a, sizeof(float) * solve_count);
3488  memcpy(b0, b, sizeof(float) * solve_count);
3489  memcpy(c0, c, sizeof(float) * solve_count);
3490  memcpy(d0, d, sizeof(float) * solve_count);
3491 
3492  memset(is_locked, 0, solve_count);
3493  memset(num_unlocks, 0, solve_count);
3494 
3495  bool overshoot, unlocked;
3496 
3497  do {
3498  if (!BLI_tridiagonal_solve_cyclic(a, b, c, d, h, solve_count)) {
3499  free_arrays(tmps);
3500  return false;
3501  }
3502 
3503  /* first check if any handles overshoot the limits, and lock them */
3504  bool all = false, locked = false;
3505 
3506  overshoot = unlocked = false;
3507 
3508  do {
3509  for (int i = 0; i < solve_count; i++) {
3510  if (h[i] >= hmin[i] && h[i] <= hmax[i]) {
3511  continue;
3512  }
3513 
3514  overshoot = true;
3515 
3516  float target = h[i] > hmax[i] ? hmax[i] : hmin[i];
3517 
3518  /* heuristically only lock handles that go in the right direction if there are such ones */
3519  if (target != 0.0f || all) {
3520  /* mark item locked */
3521  is_locked[i] = 1;
3522 
3523  bezier_lock_unknown(a, b, c, d, i, target);
3524  locked = true;
3525  }
3526  }
3527 
3528  all = true;
3529  } while (overshoot && !locked);
3530 
3531  /* If no handles overshot and were locked,
3532  * see if it may be a good idea to unlock some handles. */
3533  if (!locked) {
3534  for (int i = 0; i < solve_count; i++) {
3535  /* to definitely avoid infinite loops limit this to 2 times */
3536  if (!is_locked[i] || num_unlocks[i] >= 2) {
3537  continue;
3538  }
3539 
3540  /* if the handle wants to move in allowable direction, release it */
3541  float relax = bezier_relax_direction(a0, b0, c0, d0, h, i, solve_count);
3542 
3543  if ((relax > 0 && h[i] < hmax[i]) || (relax < 0 && h[i] > hmin[i])) {
3544  bezier_restore_equation(a, b, c, d, a0, b0, c0, d0, i);
3545 
3546  is_locked[i] = 0;
3547  num_unlocks[i]++;
3548  unlocked = true;
3549  }
3550  }
3551  }
3552  } while (overshoot || unlocked);
3553 
3554  free_arrays(tmps);
3555  return true;
3556 }
3557 
3558 /* Keep ascii art. */
3559 /* clang-format off */
3560 /*
3561  * This function computes the handles of a series of auto bezier points
3562  * on the basis of 'no acceleration discontinuities' at the points.
3563  * The first and last bezier points are considered 'fixed' (their handles are not touched)
3564  * The result is the smoothest possible trajectory going through intermediate points.
3565  * The difficulty is that the handles depends on their neighbors.
3566  *
3567  * The exact solution is found by solving a tridiagonal matrix equation formed
3568  * by the continuity and boundary conditions. Although theoretically handle position
3569  * is affected by all other points of the curve segment, in practice the influence
3570  * decreases exponentially with distance.
3571  *
3572  * NOTE: this algorithm assumes that the handle horizontal size is always 1/3 of the
3573  * of the interval to the next point. This rule ensures linear interpolation of time.
3574  *
3575  * ^ height (co 1)
3576  * | yN
3577  * | yN-1 |
3578  * | y2 | |
3579  * | y1 | | |
3580  * | y0 | | | |
3581  * | | | | | |
3582  * | | | | | |
3583  * | | | | | |
3584  * |------dx1--------dx2--------- ~ -------dxN-------------------> time (co 0)
3585  *
3586  * Notation:
3587  *
3588  * x[i], y[i] - keyframe coordinates
3589  * h[i] - right handle y offset from y[i]
3590  *
3591  * dx[i] = x[i] - x[i-1]
3592  * dy[i] = y[i] - y[i-1]
3593  *
3594  * Mathematical basis:
3595  *
3596  * 1. Handle lengths on either side of each point are connected by a factor
3597  * ensuring continuity of the first derivative:
3598  *
3599  * l[i] = dx[i+1]/dx[i]
3600  *
3601  * 2. The tridiagonal system is formed by the following equation, which is derived
3602  * by differentiating the bezier curve and specifies second derivative continuity
3603  * at every point:
3604  *
3605  * l[i]^2 * h[i-1] + (2*l[i]+2) * h[i] + 1/l[i+1] * h[i+1] = dy[i]*l[i]^2 + dy[i+1]
3606  *
3607  * 3. If this point is adjacent to a manually set handle with X size not equal to 1/3
3608  * of the horizontal interval, this equation becomes slightly more complex:
3609  *
3610  * l[i]^2 * h[i-1] + (3*(1-R[i-1])*l[i] + 3*(1-L[i+1])) * h[i] + 1/l[i+1] * h[i+1] = dy[i]*l[i]^2 + dy[i+1]
3611  *
3612  * The difference between equations amounts to this, and it's obvious that when R[i-1]
3613  * and L[i+1] are both 1/3, it becomes zero:
3614  *
3615  * ( (1-3*R[i-1])*l[i] + (1-3*L[i+1]) ) * h[i]
3616  *
3617  * 4. The equations for zero acceleration border conditions are basically the above
3618  * equation with parts omitted, so the handle size correction also applies.
3619  *
3620  * 5. The fully cyclic curve case is handled by eliminating one of the end points,
3621  * and instead of border conditions connecting the curve via a set of equations:
3622  *
3623  * l[0] = l[N] = dx[1] / dx[N]
3624  * dy[0] = dy[N]
3625  * Continuity equation (item 2) for i = 0.
3626  * Substitute h[0] for h[N] and h[N-1] for h[-1]
3627  */
3628 /* clang-format on */
3629 
3631  float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
3632 {
3633  a[i] = l[i] * l[i];
3634  b[i] = 2.0f * (l[i] + 1);
3635  c[i] = 1.0f / l[i + 1];
3636  d[i] = dy[i] * l[i] * l[i] + dy[i + 1];
3637 }
3638 
3640  float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
3641 {
3642  a[i] = 0.0f;
3643  b[i] = 2.0f;
3644  c[i] = 1.0f / l[i + 1];
3645  d[i] = dy[i + 1];
3646 }
3647 
3649  float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
3650 {
3651  a[i] = l[i] * l[i];
3652  b[i] = 2.0f * l[i];
3653  c[i] = 0.0f;
3654  d[i] = dy[i] * l[i] * l[i];
3655 }
3656 
3657 /* auto clamp prevents its own point going the wrong way, and adjacent handles overshooting */
3658 static void bezier_clamp(
3659  float *hmax, float *hmin, int i, float dy, bool no_reverse, bool no_overshoot)
3660 {
3661  if (dy > 0) {
3662  if (no_overshoot) {
3663  hmax[i] = min_ff(hmax[i], dy);
3664  }
3665  if (no_reverse) {
3666  hmin[i] = 0.0f;
3667  }
3668  }
3669  else if (dy < 0) {
3670  if (no_reverse) {
3671  hmax[i] = 0.0f;
3672  }
3673  if (no_overshoot) {
3674  hmin[i] = max_ff(hmin[i], dy);
3675  }
3676  }
3677  else if (no_reverse || no_overshoot) {
3678  hmax[i] = hmin[i] = 0.0f;
3679  }
3680 }
3681 
3682 /* write changes to a bezier handle */
3684  bool right,
3685  const float newval[3],
3686  bool endpoint)
3687 {
3688  float tmp[3];
3689 
3690  int idx = right ? 2 : 0;
3691  char hr = right ? bezt->h2 : bezt->h1;
3692  char hm = right ? bezt->h1 : bezt->h2;
3693 
3694  /* only assign Auto/Vector handles */
3695  if (!ELEM(hr, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
3696  return;
3697  }
3698 
3699  copy_v3_v3(bezt->vec[idx], newval);
3700 
3701  /* fix up the Align handle if any */
3702  if (ELEM(hm, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
3703  float hlen = len_v3v3(bezt->vec[1], bezt->vec[2 - idx]);
3704  float h2len = len_v3v3(bezt->vec[1], bezt->vec[idx]);
3705 
3706  sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]);
3707  madd_v3_v3v3fl(bezt->vec[2 - idx], bezt->vec[1], tmp, hlen / h2len);
3708  }
3709  /* at end points of the curve, mirror handle to the other side */
3710  else if (endpoint && ELEM(hm, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
3711  sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]);
3712  add_v3_v3v3(bezt->vec[2 - idx], bezt->vec[1], tmp);
3713  }
3714 }
3715 
3716 static void bezier_output_handle(BezTriple *bezt, bool right, float dy, bool endpoint)
3717 {
3718  float tmp[3];
3719 
3720  copy_v3_v3(tmp, bezt->vec[right ? 2 : 0]);
3721 
3722  tmp[1] = bezt->vec[1][1] + dy;
3723 
3724  bezier_output_handle_inner(bezt, right, tmp, endpoint);
3725 }
3726 
3727 static bool bezier_check_solve_end_handle(BezTriple *bezt, char htype, bool end)
3728 {
3729  return (htype == HD_VECT) || (end && ELEM(htype, HD_AUTO, HD_AUTO_ANIM) &&
3731 }
3732 
3733 static float bezier_calc_handle_adj(float hsize[2], float dx)
3734 {
3735  /* if handles intersect in x direction, they are scaled to fit */
3736  float fac = dx / (hsize[0] + dx / 3.0f);
3737  if (fac < 1.0f) {
3738  mul_v2_fl(hsize, fac);
3739  }
3740  return 1.0f - 3.0f * hsize[0] / dx;
3741 }
3742 
3744  BezTriple *bezt, int total, int start, int count, bool cycle)
3745 {
3746  float *dx, *dy, *l, *a, *b, *c, *d, *h, *hmax, *hmin;
3747  float **arrays[] = {&dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, nullptr};
3748 
3749  int solve_count = count;
3750 
3751  /* verify index ranges */
3752 
3753  if (count < 2) {
3754  return;
3755  }
3756 
3757  BLI_assert(start < total - 1 && count <= total);
3758  BLI_assert(start + count <= total || cycle);
3759 
3760  bool full_cycle = (start == 0 && count == total && cycle);
3761 
3762  BezTriple *bezt_first = &bezt[start];
3763  BezTriple *bezt_last =
3764  &bezt[(start + count > total) ? start + count - total : start + count - 1];
3765 
3766  bool solve_first = bezier_check_solve_end_handle(bezt_first, bezt_first->h2, start == 0);
3767  bool solve_last = bezier_check_solve_end_handle(
3768  bezt_last, bezt_last->h1, start + count == total);
3769 
3770  if (count == 2 && !full_cycle && solve_first == solve_last) {
3771  return;
3772  }
3773 
3774  /* allocate all */
3775 
3776  void *tmp_buffer = allocate_arrays(count, arrays, nullptr, "bezier_calc_smooth_tmp");
3777  if (!tmp_buffer) {
3778  return;
3779  }
3780 
3781  /* point locations */
3782 
3783  dx[0] = dy[0] = NAN_FLT;
3784 
3785  for (int i = 1, j = start + 1; i < count; i++, j++) {
3786  dx[i] = bezt[j].vec[1][0] - bezt[j - 1].vec[1][0];
3787  dy[i] = bezt[j].vec[1][1] - bezt[j - 1].vec[1][1];
3788 
3789  /* when cyclic, jump from last point to first */
3790  if (cycle && j == total - 1) {
3791  j = 0;
3792  }
3793  }
3794 
3795  /* ratio of x intervals */
3796 
3797  if (full_cycle) {
3798  dx[0] = dx[count - 1];
3799  dy[0] = dy[count - 1];
3800 
3801  l[0] = l[count - 1] = dx[1] / dx[0];
3802  }
3803  else {
3804  l[0] = l[count - 1] = 1.0f;
3805  }
3806 
3807  for (int i = 1; i < count - 1; i++) {
3808  l[i] = dx[i + 1] / dx[i];
3809  }
3810 
3811  /* compute handle clamp ranges */
3812 
3813  bool clamped_prev = false, clamped_cur = ELEM(HD_AUTO_ANIM, bezt_first->h1, bezt_first->h2);
3814 
3815  for (int i = 0; i < count; i++) {
3816  hmax[i] = FLT_MAX;
3817  hmin[i] = -FLT_MAX;
3818  }
3819 
3820  for (int i = 1, j = start + 1; i < count; i++, j++) {
3821  clamped_prev = clamped_cur;
3822  clamped_cur = ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2);
3823 
3824  if (cycle && j == total - 1) {
3825  j = 0;
3826  clamped_cur = clamped_cur || ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2);
3827  }
3828 
3829  bezier_clamp(hmax, hmin, i - 1, dy[i], clamped_prev, clamped_prev);
3830  bezier_clamp(hmax, hmin, i, dy[i] * l[i], clamped_cur, clamped_cur);
3831  }
3832 
3833  /* full cycle merges first and last points into continuous loop */
3834 
3835  float first_handle_adj = 0.0f, last_handle_adj = 0.0f;
3836 
3837  if (full_cycle) {
3838  /* reduce the number of unknowns by one */
3839  int i = solve_count = count - 1;
3840 
3841  hmin[0] = max_ff(hmin[0], hmin[i]);
3842  hmax[0] = min_ff(hmax[0], hmax[i]);
3843 
3844  solve_first = solve_last = true;
3845 
3846  bezier_eq_continuous(a, b, c, d, dy, l, 0);
3847  }
3848  else {
3849  float tmp[2];
3850 
3851  /* boundary condition: fixed handles or zero curvature */
3852  if (!solve_first) {
3853  sub_v2_v2v2(tmp, bezt_first->vec[2], bezt_first->vec[1]);
3854  first_handle_adj = bezier_calc_handle_adj(tmp, dx[1]);
3855 
3856  bezier_lock_unknown(a, b, c, d, 0, tmp[1]);
3857  }
3858  else {
3859  bezier_eq_noaccel_right(a, b, c, d, dy, l, 0);
3860  }
3861 
3862  if (!solve_last) {
3863  sub_v2_v2v2(tmp, bezt_last->vec[1], bezt_last->vec[0]);
3864  last_handle_adj = bezier_calc_handle_adj(tmp, dx[count - 1]);
3865 
3866  bezier_lock_unknown(a, b, c, d, count - 1, tmp[1]);
3867  }
3868  else {
3869  bezier_eq_noaccel_left(a, b, c, d, dy, l, count - 1);
3870  }
3871  }
3872 
3873  /* main tridiagonal system of equations */
3874 
3875  for (int i = 1; i < count - 1; i++) {
3876  bezier_eq_continuous(a, b, c, d, dy, l, i);
3877  }
3878 
3879  /* apply correction for user-defined handles with nonstandard x positions */
3880 
3881  if (!full_cycle) {
3882  if (count > 2 || solve_last) {
3883  b[1] += l[1] * first_handle_adj;
3884  }
3885 
3886  if (count > 2 || solve_first) {
3887  b[count - 2] += last_handle_adj;
3888  }
3889  }
3890 
3891  /* solve and output results */
3892 
3893  if (tridiagonal_solve_with_limits(a, b, c, d, h, hmin, hmax, solve_count)) {
3894  if (full_cycle) {
3895  h[count - 1] = h[0];
3896  }
3897 
3898  for (int i = 1, j = start + 1; i < count - 1; i++, j++) {
3899  bool end = (j == total - 1);
3900 
3901  bezier_output_handle(&bezt[j], false, -h[i] / l[i], end);
3902 
3903  if (end) {
3904  j = 0;
3905  }
3906 
3907  bezier_output_handle(&bezt[j], true, h[i], end);
3908  }
3909 
3910  if (solve_first) {
3911  bezier_output_handle(bezt_first, true, h[0], start == 0);
3912  }
3913 
3914  if (solve_last) {
3915  bezier_output_handle(bezt_last, false, -h[count - 1] / l[count - 1], start + count == total);
3916  }
3917  }
3918 
3919  /* free all */
3920 
3921  free_arrays(tmp_buffer);
3922 }
3923 
3924 static bool is_free_auto_point(BezTriple *bezt)
3925 {
3926  return BEZT_IS_AUTOH(bezt) && bezt->auto_handle_type == HD_AUTOTYPE_NORMAL;
3927 }
3928 
3929 void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
3930 {
3931  /* ignore cyclic extrapolation if end points are locked */
3932  cyclic = cyclic && is_free_auto_point(&bezt[0]) && is_free_auto_point(&bezt[total - 1]);
3933 
3934  /* if cyclic, try to find a sequence break point */
3935  int search_base = 0;
3936 
3937  if (cyclic) {
3938  for (int i = 1; i < total - 1; i++) {
3939  if (!is_free_auto_point(&bezt[i])) {
3940  search_base = i;
3941  break;
3942  }
3943  }
3944 
3945  /* all points of the curve are freely changeable auto handles - solve as full cycle */
3946  if (search_base == 0) {
3947  bezier_handle_calc_smooth_fcurve(bezt, total, 0, total, cyclic);
3948  return;
3949  }
3950  }
3951 
3952  /* Find continuous sub-sequences of free auto handles and smooth them, starting at search_base.
3953  * In cyclic mode these sub-sequences can span the cycle boundary. */
3954  int start = search_base, count = 1;
3955 
3956  for (int i = 1, j = start + 1; i < total; i++, j++) {
3957  /* in cyclic mode: jump from last to first point when necessary */
3958  if (j == total - 1 && cyclic) {
3959  j = 0;
3960  }
3961 
3962  /* non auto handle closes the list (we come here at least for the last handle, see above) */
3963  if (!is_free_auto_point(&bezt[j])) {
3964  bezier_handle_calc_smooth_fcurve(bezt, total, start, count + 1, cyclic);
3965  start = j;
3966  count = 1;
3967  }
3968  else {
3969  count++;
3970  }
3971  }
3972 
3973  if (count > 1) {
3974  bezier_handle_calc_smooth_fcurve(bezt, total, start, count, cyclic);
3975  }
3976 }
3977 
3979  BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing)
3980 {
3981  calchandleNurb_intern(bezt, prev, next, (eBezTriple_Flag)SELECT, is_fcurve, false, smoothing);
3982 }
3983 
3985  BezTriple *prev,
3986  BezTriple *next,
3987  const eBezTriple_Flag__Alias handle_sel_flag,
3988  const bool is_fcurve,
3989  const char smoothing)
3990 {
3992  bezt, prev, next, (eBezTriple_Flag)handle_sel_flag, is_fcurve, false, smoothing);
3993 }
3994 
3995 void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */
3996 {
3998 }
3999 
4005 {
4006  BezTriple *bezt;
4007  int i;
4008 
4009  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
4010  if ((bezt->f1 & SELECT) != (bezt->f3 & SELECT)) {
4011  bezt->f1 ^= SELECT;
4012  bezt->f3 ^= SELECT;
4013  }
4014  }
4015 }
4016 
4017 /* internal use only (weak) */
4019 {
4023 }
4024 
4026 {
4027  if (nu->pntsu > 1) {
4028  BezTriple *prev = BKE_nurb_bezt_get_prev(nu, bezt);
4029  BezTriple *next = BKE_nurb_bezt_get_next(nu, bezt);
4030  BKE_nurb_handle_calc(bezt, prev, next, false, 0);
4031  }
4032 }
4033 
4035 {
4036  if (nu->pntsu > 1) {
4037  const char h1_back = bezt->h1, h2_back = bezt->h2;
4038 
4039  bezt->h1 = bezt->h2 = HD_AUTO;
4040 
4041  /* Override handle types to HD_AUTO and recalculate */
4042  BKE_nurb_handle_calc_simple(nu, bezt);
4043 
4044  bezt->h1 = h1_back;
4045  bezt->h2 = h2_back;
4046  }
4047 }
4048 
4050  const eBezTriple_Flag__Alias sel_flag,
4051  const bool use_handle,
4052  const bool use_around_local)
4053 {
4054  short flag = 0;
4055 
4056 #define SEL_F1 (1 << 0)
4057 #define SEL_F2 (1 << 1)
4058 #define SEL_F3 (1 << 2)
4059 
4060  if (use_handle) {
4061  if (bezt->f1 & sel_flag) {
4062  flag |= SEL_F1;
4063  }
4064  if (bezt->f2 & sel_flag) {
4065  flag |= SEL_F2;
4066  }
4067  if (bezt->f3 & sel_flag) {
4068  flag |= SEL_F3;
4069  }
4070  }
4071  else {
4072  flag = (bezt->f2 & sel_flag) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
4073  }
4074 
4075  if (use_around_local) {
4076  flag &= ~SEL_F2;
4077  }
4078 
4079  /* check for partial selection */
4080  if (!ELEM(flag, 0, SEL_F1 | SEL_F2 | SEL_F3)) {
4081  if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
4082  bezt->h1 = HD_ALIGN;
4083  }
4084  if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
4085  bezt->h2 = HD_ALIGN;
4086  }
4087 
4088  if (bezt->h1 == HD_VECT) {
4089  if ((!(flag & SEL_F1)) != (!(flag & SEL_F2))) {
4090  bezt->h1 = HD_FREE;
4091  }
4092  }
4093  if (bezt->h2 == HD_VECT) {
4094  if ((!(flag & SEL_F3)) != (!(flag & SEL_F2))) {
4095  bezt->h2 = HD_FREE;
4096  }
4097  }
4098  }
4099 
4100 #undef SEL_F1
4101 #undef SEL_F2
4102 #undef SEL_F3
4103 }
4104 
4105 void BKE_nurb_handles_test(Nurb *nu, const bool use_handle, const bool use_around_local)
4106 {
4107  BezTriple *bezt;
4108  int a;
4109 
4110  if (nu->type != CU_BEZIER) {
4111  return;
4112  }
4113 
4114  bezt = nu->bezt;
4115  a = nu->pntsu;
4116  while (a--) {
4117  BKE_nurb_bezt_handle_test(bezt, SELECT, use_handle, use_around_local);
4118  bezt++;
4119  }
4120 
4122 }
4123 
4125 {
4126  /* checks handle coordinates and calculates type */
4127  const float eps = 0.0001f;
4128  const float eps_sq = eps * eps;
4129 
4130  if (nu == nullptr || nu->bezt == nullptr) {
4131  return;
4132  }
4133 
4134  BezTriple *bezt2 = nu->bezt;
4135  BezTriple *bezt1 = bezt2 + (nu->pntsu - 1);
4136  BezTriple *bezt0 = bezt1 - 1;
4137  int i = nu->pntsu;
4138 
4139  while (i--) {
4140  bool align = false, leftsmall = false, rightsmall = false;
4141 
4142  /* left handle: */
4143  if (flag == 0 || (bezt1->f1 & flag)) {
4144  bezt1->h1 = HD_FREE;
4145  /* Distance too short: vector-handle. */
4146  if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
4147  bezt1->h1 = HD_VECT;
4148  leftsmall = true;
4149  }
4150  else {
4151  /* Aligned handle? */
4152  if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) {
4153  align = true;
4154  bezt1->h1 = HD_ALIGN;
4155  }
4156  /* or vector handle? */
4157  if (dist_squared_to_line_v3(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
4158  bezt1->h1 = HD_VECT;
4159  }
4160  }
4161  }
4162  /* right handle: */
4163  if (flag == 0 || (bezt1->f3 & flag)) {
4164  bezt1->h2 = HD_FREE;
4165  /* Distance too short: vector-handle. */
4166  if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
4167  bezt1->h2 = HD_VECT;
4168  rightsmall = true;
4169  }
4170  else {
4171  /* Aligned handle? */
4172  if (align) {
4173  bezt1->h2 = HD_ALIGN;
4174  }
4175 
4176  /* or vector handle? */
4177  if (dist_squared_to_line_v3(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
4178  bezt1->h2 = HD_VECT;
4179  }
4180  }
4181  }
4182  if (leftsmall && bezt1->h2 == HD_ALIGN) {
4183  bezt1->h2 = HD_FREE;
4184  }
4185  if (rightsmall && bezt1->h1 == HD_ALIGN) {
4186  bezt1->h1 = HD_FREE;
4187  }
4188 
4189  /* undesired combination: */
4190  if (bezt1->h1 == HD_ALIGN && bezt1->h2 == HD_VECT) {
4191  bezt1->h1 = HD_FREE;
4192  }
4193  if (bezt1->h2 == HD_ALIGN && bezt1->h1 == HD_VECT) {
4194  bezt1->h2 = HD_FREE;
4195  }
4196 
4197  bezt0 = bezt1;
4198  bezt1 = bezt2;
4199  bezt2++;
4200  }
4201 
4203 }
4204 
4206 {
4207  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4208  BKE_nurb_handles_autocalc(nu, flag);
4209  }
4210 }
4211 
4212 void BKE_nurbList_handles_set(ListBase *editnurb, const char code)
4213 {
4214  BezTriple *bezt;
4215  int a;
4216 
4217  if (ELEM(code, HD_AUTO, HD_VECT)) {
4218  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4219  if (nu->type == CU_BEZIER) {
4220  bezt = nu->bezt;
4221  a = nu->pntsu;
4222  while (a--) {
4223  if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
4224  if (bezt->f1 & SELECT) {
4225  bezt->h1 = code;
4226  }
4227  if (bezt->f3 & SELECT) {
4228  bezt->h2 = code;
4229  }
4230  if (bezt->h1 != bezt->h2) {
4231  if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO)) {
4232  bezt->h1 = HD_FREE;
4233  }
4234  if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO)) {
4235  bezt->h2 = HD_FREE;
4236  }
4237  }
4238  }
4239  bezt++;
4240  }
4241 
4242  /* like BKE_nurb_handles_calc but moves selected */
4244  }
4245  }
4246  }
4247  else {
4248  char h_new = HD_FREE;
4249 
4250  /* There is 1 handle not FREE: FREE it all, else make ALIGNED. */
4251  if (code == 5) {
4252  h_new = HD_ALIGN;
4253  }
4254  else if (code == 6) {
4255  h_new = HD_FREE;
4256  }
4257  else {
4258  /* Toggle */
4259  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4260  if (nu->type == CU_BEZIER) {
4261  bezt = nu->bezt;
4262  a = nu->pntsu;
4263  while (a--) {
4264  if (((bezt->f1 & SELECT) && bezt->h1 != HD_FREE) ||
4265  ((bezt->f3 & SELECT) && bezt->h2 != HD_FREE)) {
4266  h_new = HD_AUTO;
4267  break;
4268  }
4269  bezt++;
4270  }
4271  }
4272  }
4273  h_new = (h_new == HD_FREE) ? HD_ALIGN : HD_FREE;
4274  }
4275  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4276  if (nu->type == CU_BEZIER) {
4277  bezt = nu->bezt;
4278  a = nu->pntsu;
4279  while (a--) {
4280  if (bezt->f1 & SELECT) {
4281  bezt->h1 = h_new;
4282  }
4283  if (bezt->f3 & SELECT) {
4284  bezt->h2 = h_new;
4285  }
4286 
4287  bezt++;
4288  }
4289 
4290  /* like BKE_nurb_handles_calc but moves selected */
4292  }
4293  }
4294  }
4295 }
4296 
4298  const bool calc_length,
4299  const uint8_t flag)
4300 {
4301  BezTriple *bezt;
4302  int a;
4303 
4304  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4305  if (nu->type != CU_BEZIER) {
4306  continue;
4307  }
4308 
4309  bool changed = false;
4310 
4311  for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) {
4312 
4313  const bool h1_select = (bezt->f1 & flag) == flag;
4314  const bool h2_select = (bezt->f3 & flag) == flag;
4315 
4316  if (h1_select || h2_select) {
4317 
4318  float co1_back[3], co2_back[3];
4319 
4320  copy_v3_v3(co1_back, bezt->vec[0]);
4321  copy_v3_v3(co2_back, bezt->vec[2]);
4322 
4324 
4325  if (h1_select) {
4326  if (!calc_length) {
4327  dist_ensure_v3_v3fl(bezt->vec[0], bezt->vec[1], len_v3v3(co1_back, bezt->vec[1]));
4328  }
4329  }
4330  else {
4331  copy_v3_v3(bezt->vec[0], co1_back);
4332  }
4333 
4334  if (h2_select) {
4335  if (!calc_length) {
4336  dist_ensure_v3_v3fl(bezt->vec[2], bezt->vec[1], len_v3v3(co2_back, bezt->vec[1]));
4337  }
4338  }
4339  else {
4340  copy_v3_v3(bezt->vec[2], co2_back);
4341  }
4342 
4343  changed = true;
4344  }
4345  }
4346 
4347  if (changed) {
4348  /* Recalculate the whole curve */
4350  }
4351  }
4352 }
4353 
4354 void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
4355 {
4356  BezTriple *bezt;
4357  BPoint *bp;
4358  int a;
4359 
4360  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4361  if (nu->type == CU_BEZIER) {
4362  a = nu->pntsu;
4363  bezt = nu->bezt;
4364  while (a--) {
4365  if (set) {
4366  bezt->f1 |= flag;
4367  bezt->f2 |= flag;
4368  bezt->f3 |= flag;
4369  }
4370  else {
4371  bezt->f1 &= ~flag;
4372  bezt->f2 &= ~flag;
4373  bezt->f3 &= ~flag;
4374  }
4375  bezt++;
4376  }
4377  }
4378  else {
4379  a = nu->pntsu * nu->pntsv;
4380  bp = nu->bp;
4381  while (a--) {
4382  SET_FLAG_FROM_TEST(bp->f1, set, flag);
4383  bp++;
4384  }
4385  }
4386  }
4387 }
4388 
4390 {
4391  bool changed = false;
4392 
4393  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4394  if (nu->type == CU_BEZIER) {
4395  for (int i = 0; i < nu->pntsu; i++) {
4396  BezTriple *bezt = &nu->bezt[i];
4397  uint8_t old_f1 = bezt->f1, old_f2 = bezt->f2, old_f3 = bezt->f3;
4398 
4399  SET_FLAG_FROM_TEST(bezt->f1, bezt->f1 & from_flag, flag);
4400  SET_FLAG_FROM_TEST(bezt->f2, bezt->f2 & from_flag, flag);
4401  SET_FLAG_FROM_TEST(bezt->f3, bezt->f3 & from_flag, flag);
4402 
4403  changed |= (old_f1 != bezt->f1) || (old_f2 != bezt->f2) || (old_f3 != bezt->f3);
4404  }
4405  }
4406  else {
4407  for (int i = 0; i < nu->pntsu * nu->pntsv; i++) {
4408  BPoint *bp = &nu->bp[i];
4409  uint8_t old_f1 = bp->f1;
4410 
4411  SET_FLAG_FROM_TEST(bp->f1, bp->f1 & from_flag, flag);
4412  changed |= (old_f1 != bp->f1);
4413  }
4414  }
4415  }
4416 
4417  return changed;
4418 }
4419 
4421 {
4422  BezTriple *bezt1, *bezt2;
4423  BPoint *bp1, *bp2;
4424  float *fp1, *fp2, *tempf;
4425  int a, b;
4426 
4427  if (nu->pntsu == 1 && nu->pntsv == 1) {
4428  return;
4429  }
4430 
4431  if (nu->type == CU_BEZIER) {
4432  a = nu->pntsu;
4433  bezt1 = nu->bezt;
4434  bezt2 = bezt1 + (a - 1);
4435  if (a & 1) {
4436  a += 1; /* if odd, also swap middle content */
4437  }
4438  a /= 2;
4439  while (a > 0) {
4440  if (bezt1 != bezt2) {
4441  SWAP(BezTriple, *bezt1, *bezt2);
4442  }
4443 
4444  swap_v3_v3(bezt1->vec[0], bezt1->vec[2]);
4445 
4446  if (bezt1 != bezt2) {
4447  swap_v3_v3(bezt2->vec[0], bezt2->vec[2]);
4448  }
4449 
4450  SWAP(uint8_t, bezt1->h1, bezt1->h2);
4451  SWAP(uint8_t, bezt1->f1, bezt1->f3);
4452 
4453  if (bezt1 != bezt2) {
4454  SWAP(uint8_t, bezt2->h1, bezt2->h2);
4455  SWAP(uint8_t, bezt2->f1, bezt2->f3);
4456  bezt1->tilt = -bezt1->tilt;
4457  bezt2->tilt = -bezt2->tilt;
4458  }
4459  else {
4460  bezt1->tilt = -bezt1->tilt;
4461  }
4462  a--;
4463  bezt1++;
4464  bezt2--;
4465  }
4466  }
4467  else if (nu->pntsv == 1) {
4468  a = nu->pntsu;
4469  bp1 = nu->bp;
4470  bp2 = bp1 + (a - 1);
4471  a /= 2;
4472  while (bp1 != bp2 && a > 0) {
4473  SWAP(BPoint, *bp1, *bp2);
4474  a--;
4475  bp1->tilt = -bp1->tilt;
4476  bp2->tilt = -bp2->tilt;
4477  bp1++;
4478  bp2--;
4479  }
4480  /* If there are odd number of points no need to touch coord of middle one,
4481  * but still need to change its tilt.
4482  */
4483  if (nu->pntsu & 1) {
4484  bp1->tilt = -bp1->tilt;
4485  }
4486  if (nu->type == CU_NURBS) {
4487  /* no knots for too short paths */
4488  if (nu->knotsu) {
4489  /* inverse knots */
4490  a = KNOTSU(nu);
4491  fp1 = nu->knotsu;
4492  fp2 = fp1 + (a - 1);
4493  a /= 2;
4494  while (fp1 != fp2 && a > 0) {
4495  SWAP(float, *fp1, *fp2);
4496  a--;
4497  fp1++;
4498  fp2--;
4499  }
4500  /* and make in increasing order again */
4501  a = KNOTSU(nu);
4502  fp1 = nu->knotsu;
4503  fp2 = tempf = (float *)MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
4504  a--;
4505  fp2[a] = fp1[a];
4506  while (a--) {
4507  fp2[0] = fabsf(fp1[1] - fp1[0]);
4508  fp1++;
4509  fp2++;
4510  }
4511 
4512  a = KNOTSU(nu) - 1;
4513  fp1 = nu->knotsu;
4514  fp2 = tempf;
4515  fp1[0] = 0.0;
4516  fp1++;
4517  while (a--) {
4518  fp1[0] = fp1[-1] + fp2[0];
4519  fp1++;
4520  fp2++;
4521  }
4522  MEM_freeN(tempf);
4523  }
4524  }
4525  }
4526  else {
4527  for (b = 0; b < nu->pntsv; b++) {
4528  bp1 = nu->bp + b * nu->pntsu;
4529  a = nu->pntsu;
4530  bp2 = bp1 + (a - 1);
4531  a /= 2;
4532 
4533  while (bp1 != bp2 && a > 0) {
4534  SWAP(BPoint, *bp1, *bp2);
4535  a--;
4536  bp1++;
4537  bp2--;
4538  }
4539  }
4540  }
4541 }
4542 
4543 void BKE_curve_nurbs_vert_coords_get(const ListBase *lb, float (*vert_coords)[3], int vert_len)
4544 {
4545  float *co = vert_coords[0];
4546  LISTBASE_FOREACH (const Nurb *, nu, lb) {
4547  if (nu->type == CU_BEZIER) {
4548  const BezTriple *bezt = nu->bezt;
4549  for (int i = 0; i < nu->pntsu; i++, bezt++) {
4550  copy_v3_v3(co, bezt->vec[0]);
4551  co += 3;
4552  copy_v3_v3(co, bezt->vec[1]);
4553  co += 3;
4554  copy_v3_v3(co, bezt->vec[2]);
4555  co += 3;
4556  }
4557  }
4558  else {
4559  const BPoint *bp = nu->bp;
4560  for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
4561  copy_v3_v3(co, bp->vec);
4562  co += 3;
4563  }
4564  }
4565  }
4566  BLI_assert(co == vert_coords[vert_len]);
4567  UNUSED_VARS_NDEBUG(vert_len);
4568 }
4569 
4570 float (*BKE_curve_nurbs_vert_coords_alloc(const ListBase *lb, int *r_vert_len))[3]
4571 {
4572  const int vert_len = BKE_nurbList_verts_count(lb);
4573  float(*vert_coords)[3] = (float(*)[3])MEM_malloc_arrayN(
4574  vert_len, sizeof(*vert_coords), __func__);
4575  BKE_curve_nurbs_vert_coords_get(lb, vert_coords, vert_len);
4576  *r_vert_len = vert_len;
4577  return vert_coords;
4578 }
4579 
4581  const float (*vert_coords)[3],
4582  const float mat[4][4],
4583  const bool constrain_2d)
4584 {
4585  const float *co = vert_coords[0];
4586 
4587  LISTBASE_FOREACH (Nurb *, nu, lb) {
4588  if (nu->type == CU_BEZIER) {
4589  BezTriple *bezt = nu->bezt;
4590 
4591  for (int i = 0; i < nu->pntsu; i++, bezt++) {
4592  mul_v3_m4v3(bezt->vec[0], mat, co);
4593  co += 3;
4594  mul_v3_m4v3(bezt->vec[1], mat, co);
4595  co += 3;
4596  mul_v3_m4v3(bezt->vec[2], mat, co);
4597  co += 3;
4598  }
4599  }
4600  else {
4601  BPoint *bp = nu->bp;
4602 
4603  for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
4604  mul_v3_m4v3(bp->vec, mat, co);
4605  co += 3;
4606  }
4607  }
4608 
4609  if (constrain_2d) {
4610  BKE_nurb_project_2d(nu);
4611  }
4612 
4614  }
4615 }
4616 
4618  const float (*vert_coords)[3],
4619  const bool constrain_2d)
4620 {
4621  const float *co = vert_coords[0];
4622 
4623  LISTBASE_FOREACH (Nurb *, nu, lb) {
4624  if (nu->type == CU_BEZIER) {
4625  BezTriple *bezt = nu->bezt;
4626 
4627  for (int i = 0; i < nu->pntsu; i++, bezt++) {
4628  copy_v3_v3(bezt->vec[0], co);
4629  co += 3;
4630  copy_v3_v3(bezt->vec[1], co);
4631  co += 3;
4632  copy_v3_v3(bezt->vec[2], co);
4633  co += 3;
4634  }
4635  }
4636  else {
4637  BPoint *bp = nu->bp;
4638 
4639  for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
4640  copy_v3_v3(bp->vec, co);
4641  co += 3;
4642  }
4643  }
4644 
4645  if (constrain_2d) {
4646  BKE_nurb_project_2d(nu);
4647  }
4648 
4650  }
4651 }
4652 
4653 float (*BKE_curve_nurbs_key_vert_coords_alloc(const ListBase *lb, float *key, int *r_vert_len))[3]
4654 {
4655  int vert_len = BKE_nurbList_verts_count(lb);
4656  float(*cos)[3] = (float(*)[3])MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
4657 
4658  float *co = cos[0];
4659  LISTBASE_FOREACH (const Nurb *, nu, lb) {
4660  if (nu->type == CU_BEZIER) {
4661  const BezTriple *bezt = nu->bezt;
4662 
4663  for (int i = 0; i < nu->pntsu; i++, bezt++) {
4664  copy_v3_v3(co, &key[0]);
4665  co += 3;
4666  copy_v3_v3(co, &key[3]);
4667  co += 3;
4668  copy_v3_v3(co, &key[6]);
4669  co += 3;
4671  }
4672  }
4673  else {
4674  const BPoint *bp = nu->bp;
4675 
4676  for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
4677  copy_v3_v3(co, key);
4678  co += 3;
4679  key += KEYELEM_FLOAT_LEN_BPOINT;
4680  }
4681  }
4682  }
4683  *r_vert_len = vert_len;
4684  return cos;
4685 }
4686 
4688 {
4689  LISTBASE_FOREACH (Nurb *, nu, lb) {
4690  if (nu->type == CU_BEZIER) {
4691  BezTriple *bezt = nu->bezt;
4692 
4693  for (int i = 0; i < nu->pntsu; i++, bezt++) {
4694  bezt->tilt = key[9];
4695  bezt->radius = key[10];
4697  }
4698  }
4699  else {
4700  BPoint *bp = nu->bp;
4701 
4702  for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
4703  bp->tilt = key[3];
4704  bp->radius = key[4];
4705  key += KEYELEM_FLOAT_LEN_BPOINT;
4706  }
4707  }
4708  }
4709 }
4710 
4712  const short order,
4713  const short flag,
4714  const short type,
4715  const bool is_surf,
4716  int *r_points_needed)
4717 {
4718  if (pnts <= 1) {
4720  }
4721  if (type == CU_NURBS) {
4722  if (pnts < order) {
4724  }
4725  if (flag & CU_NURB_BEZIER) {
4726  int points_needed = 0;
4727  if (flag & CU_NURB_CYCLIC) {
4728  const int remainder = pnts % (order - 1);
4729  points_needed = remainder > 0 ? order - 1 - remainder : 0;
4730  }
4731  else if (((flag & CU_NURB_ENDPOINT) == 0) && pnts <= order) {
4732  points_needed = order + 1 - pnts;
4733  }
4734  if (points_needed) {
4735  *r_points_needed = points_needed;
4738  }
4739  }
4740  }
4742 }
4743 
4744 bool BKE_nurb_valid_message(const int pnts,
4745  const short order,
4746  const short flag,
4747  const short type,
4748  const bool is_surf,
4749  const int dir,
4750  char *message_dst,
4751  const size_t maxncpy)
4752 {
4753  int points_needed;
4755  pnts, order, flag, type, is_surf, &points_needed);
4756 
4757  const char *msg_template = nullptr;
4758  switch (status) {
4760  message_dst[0] = 0;
4761  return false;
4763  if (dir == 1) {
4764  /* Exception made for curves as their pntsv == 1. */
4765  message_dst[0] = 0;
4766  return false;
4767  }
4768  msg_template = TIP_("At least two points required");
4769  break;
4771  msg_template = TIP_("Must have more control points than Order");
4772  break;
4774  msg_template = TIP_("%d more %s row(s) needed for Bezier");
4775  break;
4777  msg_template = TIP_("%d more point(s) needed for Bezier");
4778  break;
4779  }
4780 
4781  BLI_snprintf(message_dst, maxncpy, msg_template, points_needed, dir == 0 ? "U" : "V");
4782  return true;
4783 }
4784 
4786 {
4787  int points_needed;
4790  nu->pntsu, nu->orderu, nu->flagu, nu->type, nu->pntsv > 1, &points_needed);
4791 }
4792 
4794 {
4795  int points_needed;
4798  nu->pntsv, nu->orderv, nu->flagv, nu->type, nu->pntsv > 1, &points_needed);
4799 }
4800 
4802 {
4803  if (!BKE_nurb_check_valid_u(nu)) {
4804  return false;
4805  }
4806  if ((nu->pntsv > 1) && !BKE_nurb_check_valid_v(nu)) {
4807  return false;
4808  }
4809 
4810  return true;
4811 }
4812 
4814 {
4815  bool changed = false;
4816  if (nu->pntsu < nu->orderu) {
4817  nu->orderu = max_ii(2, nu->pntsu);
4818  changed = true;
4819  }
4820  return changed;
4821 }
4822 
4824 {
4825  bool changed = false;
4826  if (nu->pntsv < nu->orderv) {
4827  nu->orderv = max_ii(2, nu->pntsv);
4828  changed = true;
4829  }
4830  return changed;
4831 }
4832 
4834  const short type,
4835  const bool use_handles,
4836  const char **r_err_msg)
4837 {
4838  BezTriple *bezt;
4839  BPoint *bp;
4840  int a, c, nr;
4841 
4842  if (nu->type == CU_POLY) {
4843  if (type == CU_BEZIER) { /* To Bezier with vector-handles. */
4844  nr = nu->pntsu;
4845  bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
4846  nu->bezt = bezt;
4847  a = nr;
4848  bp = nu->bp;
4849  while (a--) {
4850  copy_v3_v3(bezt->vec[1], bp->vec);
4851  bezt->f1 = bezt->f2 = bezt->f3 = bp->f1;
4852  bezt->h1 = bezt->h2 = HD_VECT;
4853  bezt->weight = bp->weight;
4854  bezt->radius = bp->radius;
4855  bp++;
4856  bezt++;
4857  }
4858  MEM_freeN(nu->bp);
4859  nu->bp = nullptr;
4860  nu->pntsu = nr;
4861  nu->pntsv = 0;
4862  nu->type = CU_BEZIER;
4864  }
4865  else if (type == CU_NURBS) {
4866  nu->type = CU_NURBS;
4867  nu->orderu = 4;
4868  nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
4870  a = nu->pntsu * nu->pntsv;
4871  bp = nu->bp;
4872  while (a--) {
4873  bp->vec[3] = 1.0;
4874  bp++;
4875  }
4876  }
4877  }
4878  else if (nu->type == CU_BEZIER) { /* Bezier */
4879  if (ELEM(type, CU_POLY, CU_NURBS)) {
4880  nr = use_handles ? (3 * nu->pntsu) : nu->pntsu;
4881  nu->bp = (BPoint *)MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
4882  a = nu->pntsu;
4883  bezt = nu->bezt;
4884  bp = nu->bp;
4885  while (a--) {
4886  if ((type == CU_POLY && bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) ||
4887  (use_handles == false)) {
4888  /* vector handle becomes one poly vertex */
4889  copy_v3_v3(bp->vec, bezt->vec[1]);
4890  bp->vec[3] = 1.0;
4891  bp->f1 = bezt->f2;
4892  if (use_handles) {
4893  nr -= 2;
4894  }
4895  bp->radius = bezt->radius;
4896  bp->weight = bezt->weight;
4897  bp++;
4898  }
4899  else {
4900  const uint8_t *f = &bezt->f1;
4901  for (c = 0; c < 3; c++, f++) {
4902  copy_v3_v3(bp->vec, bezt->vec[c]);
4903  bp->vec[3] = 1.0;
4904  bp->f1 = *f;
4905  bp->radius = bezt->radius;
4906  bp->weight = bezt->weight;
4907  bp++;
4908  }
4909  }
4910  bezt++;
4911  }
4912  MEM_freeN(nu->bezt);
4913  nu->bezt = nullptr;
4914  nu->pntsu = nr;
4915  nu->pntsv = 1;
4916  nu->orderu = 4;
4917  nu->orderv = 1;
4918  nu->type = type;
4919 
4920  if (type == CU_NURBS) {
4921  nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
4922  nu->flagu |= CU_NURB_BEZIER;
4924  }
4925  }
4926  }
4927  else if (nu->type == CU_NURBS) {
4928  if (type == CU_POLY) {
4929  nu->type = CU_POLY;
4930  if (nu->knotsu) {
4931  MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
4932  }
4933  nu->knotsu = nullptr;
4934  MEM_SAFE_FREE(nu->knotsv);
4935  }
4936  else if (type == CU_BEZIER) { /* to Bezier */
4937  nr = nu->pntsu / 3;
4938 
4939  if (nr < 2) {
4940  if (r_err_msg != nullptr) {
4941  *r_err_msg = "At least 6 points required for conversion";
4942  }
4943  return false; /* conversion impossible */
4944  }
4945 
4946  bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
4947  nu->bezt = bezt;
4948  a = nr;
4949  bp = nu->bp;
4950  while (a--) {
4951  copy_v3_v3(bezt->vec[0], bp->vec);
4952  bezt->f1 = bp->f1;
4953  bp++;
4954  copy_v3_v3(bezt->vec[1], bp->vec);
4955  bezt->f2 = bp->f1;
4956  bp++;
4957  copy_v3_v3(bezt->vec[2], bp->vec);
4958  bezt->f3 = bp->f1;
4959  bezt->radius = bp->radius;
4960  bezt->weight = bp->weight;
4961  bp++;
4962  bezt++;
4963  }
4964  MEM_freeN(nu->bp);
4965  nu->bp = nullptr;
4966  MEM_freeN(nu->knotsu);
4967  nu->knotsu = nullptr;
4968  nu->pntsu = nr;
4969  nu->type = CU_BEZIER;
4970  }
4971  }
4972 
4973  return true;
4974 }
4975 
4977 {
4978  if (cu->editnurb) {
4979  return BKE_curve_editNurbs_get(cu);
4980  }
4981 
4982  return &cu->nurb;
4983 }
4984 
4986 {
4987  if (cu->editnurb) {
4989  }
4990 
4991  return &cu->nurb;
4992 }
4993 
4995 {
4996  if (nu == nullptr) {
4997  cu->actnu = CU_ACT_NONE;
4998  }
4999  else {
5000  BLI_assert(!nu->hide);
5001  ListBase *nurbs = BKE_curve_editNurbs_get(cu);
5002  cu->actnu = BLI_findindex(nurbs, nu);
5003  }
5004 }
5005 
5007 {
5008  ListBase *nurbs = BKE_curve_editNurbs_get(cu);
5009  return (Nurb *)BLI_findlink(nurbs, cu->actnu);
5010 }
5011 
5013 {
5014  Nurb *nu = nullptr;
5015  void *vert = nullptr;
5016 
5017  BKE_curve_nurb_vert_active_get(cu, &nu, &vert);
5018  return vert;
5019 }
5020 
5021 int BKE_curve_nurb_vert_index_get(const Nurb *nu, const void *vert)
5022 {
5023  if (nu->type == CU_BEZIER) {
5024  BLI_assert(ARRAY_HAS_ITEM((BezTriple *)vert, nu->bezt, nu->pntsu));
5025  return (BezTriple *)vert - nu->bezt;
5026  }
5027 
5028  BLI_assert(ARRAY_HAS_ITEM((BPoint *)vert, nu->bp, nu->pntsu * nu->pntsv));
5029  return (BPoint *)vert - nu->bp;
5030 }
5031 
5032 void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
5033 {
5034  if (nu) {
5035  BKE_curve_nurb_active_set(cu, nu);
5036 
5037  if (vert) {
5038  cu->actvert = BKE_curve_nurb_vert_index_get(nu, vert);
5039  }
5040  else {
5041  cu->actvert = CU_ACT_NONE;
5042  }
5043  }
5044  else {
5045  cu->actnu = cu->actvert = CU_ACT_NONE;
5046  }
5047 }
5048 
5049 bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
5050 {
5051  Nurb *nu = nullptr;
5052  void *vert = nullptr;
5053 
5054  if (cu->actvert != CU_ACT_NONE) {
5055  ListBase *nurbs = BKE_curve_editNurbs_get(cu);
5056  nu = (Nurb *)BLI_findlink(nurbs, cu->actnu);
5057 
5058  if (nu) {
5059  if (nu->type == CU_BEZIER) {
5060  BLI_assert(nu->pntsu > cu->actvert);
5061  vert = &nu->bezt[cu->actvert];
5062  }
5063  else {
5064  BLI_assert((nu->pntsu * nu->pntsv) > cu->actvert);
5065  vert = &nu->bp[cu->actvert];
5066  }
5067  }
5068  }
5069 
5070  *r_nu = nu;
5071  *r_vert = vert;
5072 
5073  return (*r_vert != nullptr);
5074 }
5075 
5077 {
5078  Nurb *nu;
5079  void *vert;
5080 
5081  if (BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
5082  if (nu->type == CU_BEZIER) {
5083  BezTriple *bezt = (BezTriple *)vert;
5084  if (BEZT_ISSEL_ANY(bezt) == 0) {
5085  cu->actvert = CU_ACT_NONE;
5086  }
5087  }
5088  else {
5089  BPoint *bp = (BPoint *)vert;
5090  if ((bp->f1 & SELECT) == 0) {
5091  cu->actvert = CU_ACT_NONE;
5092  }
5093  }
5094 
5095  if (nu->hide) {
5096  cu->actnu = CU_ACT_NONE;
5097  }
5098  }
5099 }
5100 
5101 bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
5102 {
5103  ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
5104  ListBase temp_nurb_lb = {nullptr, nullptr};
5105  const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0);
5106  /* For font curves we generate temp list of splines.
5107  *
5108  * This is likely to be fine, this function is not supposed to be called
5109  * often, and it's the only way to get meaningful bounds for fonts.
5110  */
5111  if (is_font) {
5112  nurb_lb = &temp_nurb_lb;
5113  BKE_vfont_to_curve_ex(nullptr, cu, FO_EDIT, nurb_lb, nullptr, nullptr, nullptr, nullptr);
5114  use_radius = false;
5115  }
5116  /* Do bounding box based on splines. */
5117  LISTBASE_FOREACH (const Nurb *, nu, nurb_lb) {
5118  BKE_nurb_minmax(nu, use_radius, min, max);
5119  }
5120  const bool result = (BLI_listbase_is_empty(nurb_lb) == false);
5121  /* Cleanup if needed. */
5122  BKE_nurbList_free(&temp_nurb_lb);
5123  return result;
5124 }
5125 
5126 bool BKE_curve_center_median(Curve *cu, float cent[3])
5127 {
5128  ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
5129  int total = 0;
5130 
5131  zero_v3(cent);
5132 
5133  LISTBASE_FOREACH (Nurb *, nu, nurb_lb) {
5134  int i;
5135 
5136  if (nu->type == CU_BEZIER) {
5137  BezTriple *bezt;
5138  i = nu->pntsu;
5139  total += i * 3;
5140  for (bezt = nu->bezt; i--; bezt++) {
5141  add_v3_v3(cent, bezt->vec[0]);
5142  add_v3_v3(cent, bezt->vec[1]);
5143  add_v3_v3(cent, bezt->vec[2]);
5144  }
5145  }
5146  else {
5147  BPoint *bp;
5148  i = nu->pntsu * nu->pntsv;
5149  total += i;
5150  for (bp = nu->bp; i--; bp++) {
5151  add_v3_v3(cent, bp->vec);
5152  }
5153  }
5154  }
5155 
5156  if (total) {
5157  mul_v3_fl(cent, 1.0f / (float)total);
5158  }
5159 
5160  return (total != 0);
5161 }
5162 
5163 bool BKE_curve_center_bounds(Curve *cu, float cent[3])
5164 {
5165  float min[3], max[3];
5166  INIT_MINMAX(min, max);
5167  if (BKE_curve_minmax(cu, false, min, max)) {
5168  mid_v3_v3v3(cent, min, max);
5169  return true;
5170  }
5171 
5172  return false;
5173 }
5174 
5176  const float mat[4][4],
5177  const bool do_keys,
5178  const bool do_props,
5179  const float unit_scale)
5180 {
5181  BPoint *bp;
5182  BezTriple *bezt;
5183  int i;
5184 
5185  const bool is_uniform_scaled = is_uniform_scaled_m4(mat);
5186 
5187  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5188  if (nu->type == CU_BEZIER) {
5189  i = nu->pntsu;
5190  for (bezt = nu->bezt; i--; bezt++) {
5191  mul_m4_v3(mat, bezt->vec[0]);
5192  mul_m4_v3(mat, bezt->vec[1]);
5193  mul_m4_v3(mat, bezt->vec[2]);
5194  if (do_props) {
5195  bezt->radius *= unit_scale;
5196  }
5197  if (!is_uniform_scaled) {
5198  if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
5199  bezt->h1 = bezt->h2 = HD_ALIGN;
5200  }
5201  }
5202  }
5204  }
5205  else {
5206  i = nu->pntsu * nu->pntsv;
5207  for (bp = nu->bp; i--; bp++) {
5208  mul_m4_v3(mat, bp->vec);
5209  if (do_props) {
5210  bp->radius *= unit_scale;
5211  }
5212  }
5213  }
5214  }
5215 
5216  if (do_keys && cu->key) {
5217  LISTBASE_FOREACH (KeyBlock *, kb, &cu->key->block) {
5218  float *fp = (float *)kb->data;
5219  int n = kb->totelem;
5220 
5221  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5222  if (nu->type == CU_BEZIER) {
5223  for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
5224  mul_m4_v3(mat, &fp[0]);
5225  mul_m4_v3(mat, &fp[3]);
5226  mul_m4_v3(mat, &fp[6]);
5227  if (do_props) {
5228  fp[10] *= unit_scale; /* radius */
5229  }
5231  }
5232  }
5233  else {
5234  for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
5235  mul_m4_v3(mat, fp);
5236  if (do_props) {
5237  fp[4] *= unit_scale; /* radius */
5238  }
5240  }
5241  }
5242  }
5243  }
5244  }
5245 }
5246 
5247 void BKE_curve_transform(Curve *cu, const float mat[4][4], const bool do_keys, const bool do_props)
5248 {
5249  float unit_scale = mat4_to_scale(mat);
5250  BKE_curve_transform_ex(cu, mat, do_keys, do_props, unit_scale);
5251 }
5252 
5253 void BKE_curve_translate(Curve *cu, const float offset[3], const bool do_keys)
5254 {
5255  ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
5256 
5257  LISTBASE_FOREACH (Nurb *, nu, nurb_lb) {
5258  if (nu->type == CU_BEZIER) {
5259  int i = nu->pntsu;
5260  for (BezTriple *bezt = nu->bezt; i--; bezt++) {
5261  add_v3_v3(bezt->vec[0], offset);
5262  add_v3_v3(bezt->vec[1], offset);
5263  add_v3_v3(bezt->vec[2], offset);
5264  }
5265  }
5266  else {
5267  int i = nu->pntsu * nu->pntsv;
5268  for (BPoint *bp = nu->bp; i--; bp++) {
5269  add_v3_v3(bp->vec, offset);
5270  }
5271  }
5272  }
5273 
5274  if (do_keys && cu->key) {
5275  LISTBASE_FOREACH (KeyBlock *, kb, &cu->key->block) {
5276  float *fp = (float *)kb->data;
5277  int n = kb->totelem;
5278 
5279  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5280  if (nu->type == CU_BEZIER) {
5281  for (int i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
5282  add_v3_v3(&fp[0], offset);
5283  add_v3_v3(&fp[3], offset);
5284  add_v3_v3(&fp[6], offset);
5286  }
5287  }
5288  else {
5289  for (int i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
5290  add_v3_v3(fp, offset);
5292  }
5293  }
5294  }
5295  }
5296  }
5297 }
5298 
5300 {
5301  const int curvetype = BKE_curve_type_get(cu);
5302 
5303  if (curvetype == OB_FONT) {
5304  struct CharInfo *info = cu->strinfo;
5305  for (int i = cu->len_char32 - 1; i >= 0; i--, info++) {
5306  if (info->mat_nr && info->mat_nr >= index) {
5307  info->mat_nr--;
5308  }
5309  }
5310  }
5311  else {
5312  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5313  if (nu->mat_nr && nu->mat_nr >= index) {
5314  nu->mat_nr--;
5315  }
5316  }
5317  }
5318 }
5319 
5320 bool BKE_curve_material_index_used(const Curve *cu, int index)
5321 {
5322  const int curvetype = BKE_curve_type_get(cu);
5323 
5324  if (curvetype == OB_FONT) {
5325  const struct CharInfo *info = cu->strinfo;
5326  for (int i = cu->len_char32 - 1; i >= 0; i--, info++) {
5327  if (info->mat_nr == index) {
5328  return true;
5329  }
5330  }
5331  }
5332  else {
5333  LISTBASE_FOREACH (const Nurb *, nu, &cu->nurb) {
5334  if (nu->mat_nr == index) {
5335  return true;
5336  }
5337  }
5338  }
5339 
5340  return false;
5341 }
5342 
5344 {
5345  const int curvetype = BKE_curve_type_get(cu);
5346 
5347  if (curvetype == OB_FONT) {
5348  struct CharInfo *info = cu->strinfo;
5349  for (int i = cu->len_char32 - 1; i >= 0; i--, info++) {
5350  info->mat_nr = 0;
5351  }
5352  }
5353  else {
5354  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5355  nu->mat_nr = 0;
5356  }
5357  }
5358 }
5359 
5361 {
5362  const int curvetype = BKE_curve_type_get(cu);
5363  bool is_valid = true;
5364 
5365  if (curvetype == OB_FONT) {
5366  CharInfo *info = cu->strinfo;
5367  const int max_idx = max_ii(0, cu->totcol); /* OB_FONT use 1 as first mat index, not 0!!! */
5368  int i;
5369  for (i = cu->len_char32 - 1; i >= 0; i--, info++) {
5370  if (info->mat_nr > max_idx) {
5371  info->mat_nr = 0;
5372  is_valid = false;
5373  }
5374  }
5375  }
5376  else {
5377  const int max_idx = max_ii(0, cu->totcol - 1);
5378  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5379  if (nu->mat_nr > max_idx) {
5380  nu->mat_nr = 0;
5381  is_valid = false;
5382  }
5383  }
5384  }
5385 
5386  if (!is_valid) {
5388  return true;
5389  }
5390  return false;
5391 }
5392 
5393 void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int remap_len)
5394 {
5395  const int curvetype = BKE_curve_type_get(cu);
5396  const short remap_len_short = (short)remap_len;
5397 
5398 #define MAT_NR_REMAP(n) \
5399  if (n < remap_len_short) { \
5400  BLI_assert(n >= 0 && remap[n] < remap_len_short); \
5401  n = remap[n]; \
5402  } \
5403  ((void)0)
5404 
5405  if (curvetype == OB_FONT) {
5406  struct CharInfo *strinfo;
5407  int charinfo_len, i;
5408 
5409  if (cu->editfont) {
5410  EditFont *ef = cu->editfont;
5411  strinfo = ef->textbufinfo;
5412  charinfo_len = ef->len;
5413  }
5414  else {
5415  strinfo = cu->strinfo;
5416  charinfo_len = cu->len_char32;
5417  }
5418 
5419  for (i = 0; i <= charinfo_len; i++) {
5420  if (strinfo[i].mat_nr > 0) {
5421  strinfo[i].mat_nr -= 1;
5422  MAT_NR_REMAP(strinfo[i].mat_nr);
5423  strinfo[i].mat_nr += 1;
5424  }
5425  }
5426  }
5427  else {
5428  ListBase *nurbs = BKE_curve_editNurbs_get(cu);
5429 
5430  if (nurbs) {
5431  LISTBASE_FOREACH (Nurb *, nu, nurbs) {
5432  MAT_NR_REMAP(nu->mat_nr);
5433  }
5434  }
5435  }
5436 
5437 #undef MAT_NR_REMAP
5438 }
5439 
5440 void BKE_curve_smooth_flag_set(Curve *cu, const bool use_smooth)
5441 {
5442  if (use_smooth) {
5443  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5444  nu->flag |= CU_SMOOTH;
5445  }
5446  }
5447  else {
5448  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5449  nu->flag &= ~CU_SMOOTH;
5450  }
5451  }
5452 }
5453 
5454 void BKE_curve_rect_from_textbox(const struct Curve *cu,
5455  const struct TextBox *tb,
5456  struct rctf *r_rect)
5457 {
5458  r_rect->xmin = cu->xof + tb->x;
5459  r_rect->ymax = cu->yof + tb->y + cu->fsize;
5460 
5461  r_rect->xmax = r_rect->xmin + tb->w;
5462  r_rect->ymin = r_rect->ymax - tb->h;
5463 }
5464 
5465 void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
5466 {
5467  float h1[2], h2[2], len1, len2, len, fac;
5468 
5469  /* Calculate handle deltas. */
5470  h1[0] = v1[0] - v2[0];
5471  h1[1] = v1[1] - v2[1];
5472 
5473  h2[0] = v4[0] - v3[0];
5474  h2[1] = v4[1] - v3[1];
5475 
5476  /* Calculate distances:
5477  * - len = span of time between keyframes
5478  * - len1 = length of handle of start key
5479  * - len2 = length of handle of end key
5480  */
5481  len = v4[0] - v1[0];
5482  len1 = fabsf(h1[0]);
5483  len2 = fabsf(h2[0]);
5484 
5485  /* If the handles have no length, no need to do any corrections. */
5486  if ((len1 + len2) == 0.0f) {
5487  return;
5488  }
5489 
5490  /* the two handles cross over each other, so force them
5491  * apart using the proportion they overlap
5492  */
5493  if ((len1 + len2) > len) {
5494  fac = len / (len1 + len2);
5495 
5496  v2[0] = (v1[0] - fac * h1[0]);
5497  v2[1] = (v1[1] - fac * h1[1]);
5498 
5499  v3[0] = (v4[0] - fac * h2[0]);
5500  v3[1] = (v4[1] - fac * h2[1]);
5501  }
5502 }
5503 
5504 /* **** Depsgraph evaluation **** */
5505 
5507 {
5510  if (DEG_is_active(depsgraph)) {
5511  Curve *curve_orig = (Curve *)DEG_get_original_id(&curve->id);
5513  curve_orig->texflag |= CU_AUTOSPACE_EVALUATED;
5514  copy_v3_v3(curve_orig->loc, curve->loc);
5515  copy_v3_v3(curve_orig->size, curve->size);
5516  }
5517  }
5518 }
5519 
5520 /* Draw Engine */
5521 void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = nullptr;
5523 
5525 {
5526  if (cu->batch_cache) {
5528  }
5529 }
5531 {
5532  if (cu->batch_cache) {
5534  }
5535 }
typedef float(TangentPoint)[2]
void BKE_animdata_blend_read_data(struct BlendDataReader *reader, struct AnimData *adt)
Definition: anim_data.c:1443
void BKE_animdata_blend_write(struct BlendWriter *writer, struct AnimData *adt)
Definition: anim_data.c:1421
#define KNOTSU(nu)
Definition: BKE_curve.h:52
#define CU_DO_RADIUS(cu, nu)
Definition: BKE_curve.h:61
int eBezTriple_Flag__Alias
Definition: BKE_curve.h:28
#define CU_IS_2D(cu)
Definition: BKE_curve.h:67
#define KNOTSV(nu)
Definition: BKE_curve.h:54
#define SEGMENTSU(nu)
Definition: BKE_curve.h:58
void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile)
Definition: curveprofile.cc:88
struct CurveProfile * BKE_curveprofile_copy(const struct CurveProfile *profile)
void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct CurveProfile *profile)
Definition: curveprofile.cc:82
void BKE_curveprofile_free(struct CurveProfile *profile)
Definition: curveprofile.cc:50
display list (or rather multi purpose list) stuff.
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition: BKE_idtype.h:39
void key_curve_position_weights(float t, float data[4], int type)
Definition: key.c:336
@ LIB_ID_COPY_SHAPEKEY
Definition: BKE_lib_id.h:170
struct ID * BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, int flag)
void * BKE_libblock_alloc(struct Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition: lib_id.c:1050
void BKE_id_blend_write(struct BlendWriter *writer, struct ID *id)
Definition: lib_id.c:2008
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(_data, _id_super, _cb_flag)
@ IDWALK_CB_USER
Definition: BKE_lib_query.h:73
@ IDWALK_CB_NOP
Definition: BKE_lib_query.h:33
General operations, lookup, etc. for blender objects.
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3])
Definition: object.cc:3645
struct VFont * BKE_vfont_builtin_get(void)
Definition: vfont.c:413
bool BKE_vfont_to_curve_ex(struct Object *ob, struct Curve *cu, int mode, struct ListBase *r_nubase, const char32_t **r_text, int *r_text_len, bool *r_text_free, struct CharTrans **r_chartransdata)
Definition: vfont.c:1709
#define BLI_assert(a)
Definition: BLI_assert.h:46
void BLI_endian_switch_float_array(float *val, int size) ATTR_NONNULL(1)
Definition: endian_switch.c:51
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:790
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:340
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float saacos(float fac)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
#define M_PI_2
Definition: BLI_math_base.h:23
MINLINE int mod_i(int i, int n)
#define NAN_FLT
Definition: BLI_math_base.h:63
float dist_squared_to_line_v3(const float p[3], const float l1[3], const float l2[3])
Definition: math_geom.c:499
bool is_uniform_scaled_m4(const float m[4][4])
Definition: math_matrix.c:1867
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
float mat4_to_scale(const float M[4][4])
Definition: math_matrix.c:2185
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], float t)
float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3])
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
void vec_to_quat(float q[4], const float vec[3], short axis, short upflag)
float normalize_qt(float q[4])
#define DEG2RADF(_deg)
void mul_qt_v3(const float q[4], float r[3])
Definition: math_rotation.c:59
void unit_qt(float q[4])
Definition: math_rotation.c:27
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
Definition: math_rotation.c:46
void copy_qt_qt(float q[4], const float a[4])
Definition: math_rotation.c:33
bool BLI_tridiagonal_solve_cyclic(const float *a, const float *b, const float *c, const float *d, float *r_x, int count)
Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
Definition: math_solvers.c:86
MINLINE bool compare_v3v3(const float a[3], const float b[3], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:867
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:237
MINLINE void swap_v3_v3(float a[3], float b[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:445
MINLINE void add_v3_v3(float r[3], const float a[3])
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], float dist)
Definition: math_vector.c:917
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3])
Definition: math_vector.c:680
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define INIT_MINMAX(min, max)
#define SWAP(type, a, b)
#define ARRAY_HAS_ITEM(arr_item, arr_start, arr_len)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define UNLIKELY(x)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define POINTER_OFFSET(v, ofs)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define BLO_read_data_address(reader, ptr_p)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_list(BlendDataReader *reader, struct ListBase *list)
Definition: readfile.c:5172
void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
Definition: writefile.c:1581
#define BLO_read_id_address(reader, lib, id_ptr_p)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_expand(expander, id)
bool BLO_read_requires_endian_switch(BlendDataReader *reader)
Definition: readfile.c:5143
void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_ptr)
Definition: writefile.c:1489
void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p)
Definition: readfile.c:5245
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr)
Definition: writefile.c:1591
#define BLT_I18NCONTEXT_ID_CURVE_LEGACY
#define TIP_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
bool DEG_is_active(const struct Depsgraph *depsgraph)
Definition: depsgraph.cc:312
void DEG_debug_print_eval(struct Depsgraph *depsgraph, const char *function_name, const char *object_name, const void *object_address)
void DEG_id_tag_update(struct ID *id, int flag)
struct ID * DEG_get_original_id(struct ID *id)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
#define FILTER_ID_CU_LEGACY
Definition: DNA_ID.h:903
@ INDEX_ID_CU_LEGACY
Definition: DNA_ID.h:1027
@ ID_CU_LEGACY
Definition: DNA_ID_enums.h:49
@ FCURVE_SMOOTH_NONE
@ CU_BEZIER
@ CU_POLY
@ CU_NURBS
@ CU_AUTOSPACE
@ CU_AUTOSPACE_EVALUATED
#define MAXTEXTBOX
#define BEZT_IS_AUTOH(bezt)
struct Curve Curve
@ CU_SMOOTH
struct BPoint BPoint
#define BEZT_ISSEL_ANY(bezt)
@ CU_BEVFAC_MAP_SPLINE
@ CU_BEVFAC_MAP_SEGMENT
#define CU_ACT_NONE
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
@ CU_NURB_BEZIER
@ HD_AUTO_ANIM
@ HD_VECT
@ HD_FREE
@ HD_AUTO
@ HD_ALIGN_DOUBLESIDE
@ HD_ALIGN
#define KEY_CU_EASE
@ HD_AUTOTYPE_NORMAL
@ HD_AUTOTYPE_LOCKED_FINAL
struct BezTriple BezTriple
@ CU_TWIST_MINIMUM
@ CU_TWIST_TANGENT
eBezTriple_Flag
@ CU_3D
@ CU_FRONT
@ CU_BACK
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
#define KEYELEM_ELEM_LEN_BPOINT
#define KEYELEM_FLOAT_LEN_BEZTRIPLE
#define KEYELEM_FLOAT_LEN_BPOINT
#define KEYELEM_ELEM_LEN_BEZTRIPLE
Object is a sort of wrapper for general info.
@ OB_SURF
@ OB_FONT
@ OB_CURVES_LEGACY
@ BOUNDBOX_DIRTY
#define FO_EDIT
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble y1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble right
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint i1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei stride
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint order
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
static void smooth_iter(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float(*vertexCos)[3], uint verts_num, const float *smooth_weights, uint iterations)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
__forceinline bool all(const avxb &b)
Definition: avxb.h:201
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
#define sinf(x)
Definition: cuda/compat.h:102
#define cosf(x)
Definition: cuda/compat.h:101
void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
Definition: curve.cc:4124
static void bevel_list_flip_tangents(BevList *bl)
Definition: curve.cc:2124
static void makeknots(Nurb *nu, short uv)
Definition: curve.cc:1204
void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
Definition: curve.cc:4034
bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, uint8_t from_flag, uint8_t flag)
Definition: curve.cc:4389
static void basisNurb(float t, short order, int pnts, const float *knots, float *basis, int *start, int *end)
Definition: curve.cc:1244
void BKE_nurb_handle_calc_simple(Nurb *nu, BezTriple *bezt)
Definition: curve.cc:4025
void BKE_curve_batch_cache_dirty_tag(Curve *cu, int mode)
Definition: curve.cc:5524
void BKE_nurb_index_to_uv(Nurb *nu, int index, int *r_u, int *r_v)
Definition: curve.cc:964
void BKE_nurb_handles_calc(Nurb *nu)
Definition: curve.cc:3995
Nurb * BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
Definition: curve.cc:701
static void bezier_eq_noaccel_left(float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
Definition: curve.cc:3648
void BKE_curve_translate(Curve *cu, const float offset[3], const bool do_keys)
Definition: curve.cc:5253
static void nurbList_handles_swap_select(Nurb *nu)
Definition: curve.cc:4004
BPoint * BKE_nurb_bpoint_get_next(Nurb *nu, BPoint *bp)
Definition: curve.cc:994
void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect)
Definition: curve.cc:5454
static void make_bevel_list_segment_2D(BevList *bl)
Definition: curve.cc:2455
void BKE_curve_editNurb_free(Curve *cu)
Definition: curve.cc:378
static void * allocate_arrays(int count, float ***floats, char ***chars, const char *name)
Definition: curve.cc:3391
bool BKE_curve_center_median(Curve *cu, float cent[3])
Definition: curve.cc:5126
void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv)
Definition: curve.cc:1322
static void curve_editNurb_keyIndex_cv_free_cb(void *val)
Definition: curve.cc:356
void BKE_curve_smooth_flag_set(Curve *cu, const bool use_smooth)
Definition: curve.cc:5440
IDTypeInfo IDType_ID_CU_LEGACY
Definition: curve.cc:306
void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
Definition: curve.cc:5465
static bool bevelinside(const BevList *bl1, const BevList *bl2)
Definition: curve.cc:1839
void BKE_nurb_project_2d(Nurb *nu)
Definition: curve.cc:736
static void bevel_list_calc_bisect(BevList *bl)
Definition: curve.cc:2062
void BKE_curve_texspace_ensure(Curve *cu)
Definition: curve.cc:555
bool BKE_nurb_order_clamp_u(struct Nurb *nu)
Definition: curve.cc:4813
static void curve_init_data(ID *id)
Definition: curve.cc:72
static void free_arrays(void *buffer)
Definition: curve.cc:3424
void BKE_nurbList_handles_autocalc(ListBase *editnurb, uint8_t flag)
Definition: curve.cc:4205
void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int remap_len)
Definition: curve.cc:5393
static void make_bevel_list_3D_minimum_twist(BevList *bl)
Definition: curve.cc:2248
void BKE_nurb_minmax(const Nurb *nu, bool use_radius, float min[3], float max[3])
Definition: curve.cc:762
static void curve_blend_read_data(BlendDataReader *reader, ID *id)
Definition: curve.cc:206
static void curve_foreach_id(ID *id, LibraryForeachIDData *data)
Definition: curve.cc:130
void BKE_curve_transform_ex(Curve *cu, const float mat[4][4], const bool do_keys, const bool do_props, const float unit_scale)
Definition: curve.cc:5175
void BKE_nurb_handles_test(Nurb *nu, const bool use_handle, const bool use_around_local)
Definition: curve.cc:4105
static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
Definition: curve.cc:81
static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3], const float p2[3], const float p3[3], float p[3], int it, int stride)
Definition: curve.cc:1769
static void bevel_list_smooth(BevList *bl, int smooth_iter)
Definition: curve.cc:2165
void BKE_nurb_free(Nurb *nu)
Definition: curve.cc:622
void BKE_curve_nurbs_vert_coords_apply_with_mat4(ListBase *lb, const float(*vert_coords)[3], const float mat[4][4], const bool constrain_2d)
Definition: curve.cc:4580
void BKE_curve_init(Curve *cu, const short curve_type)
Definition: curve.cc:388
static void make_bevel_list_segment_3D(BevList *bl)
Definition: curve.cc:2431
Nurb * BKE_curve_nurb_active_get(Curve *cu)
Definition: curve.cc:5006
static void curve_blend_read_lib(BlendLibReader *reader, ID *id)
Definition: curve.cc:269
void BKE_curve_type_test(Object *ob)
Definition: curve.cc:482
static void make_bevel_list_3D_tangent(BevList *bl)
Definition: curve.cc:2359
void BKE_curve_bevelList_free(ListBase *bev)
Definition: curve.cc:2551
void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
Definition: curve.cc:4994
static int vergxcobev(const void *a1, const void *a2)
Definition: curve.cc:1900
void BKE_curve_texspace_calc(Curve *cu)
Definition: curve.cc:518
static void make_bevel_list_2D(BevList *bl)
Definition: curve.cc:2471
#define MAT_NR_REMAP(n)
static bool is_free_auto_point(BezTriple *bezt)
Definition: curve.cc:3924
void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3])
Definition: curve.cc:1134
Curve * BKE_curve_add(Main *bmain, const char *name, int type)
Definition: curve.cc:414
bool BKE_nurb_check_valid_uv(const Nurb *nu)
Definition: curve.cc:4801
void(* BKE_curve_batch_cache_free_cb)(Curve *cu)
Definition: curve.cc:5522
void BKE_curve_batch_cache_free(Curve *cu)
Definition: curve.cc:5530
void BKE_nurb_makeCurve(const Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride)
Definition: curve.cc:1514
float BKE_nurb_calc_length(const Nurb *nu, int resolution)
Definition: curve.cc:814
void BKE_curve_transform(Curve *cu, const float mat[4][4], const bool do_keys, const bool do_props)
Definition: curve.cc:5247
ListBase * BKE_curve_editNurbs_get(Curve *cu)
Definition: curve.cc:426
bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles, const char **r_err_msg)
Definition: curve.cc:4833
void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
Definition: curve.cc:369
bool BKE_curve_center_bounds(Curve *cu, float cent[3])
Definition: curve.cc:5163
static void make_bevel_list_3D_zup(BevList *bl)
Definition: curve.cc:2219
void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
Definition: curve.cc:5032
static void calchandlesNurb_intern(Nurb *nu, eBezTriple_Flag handle_sel_flag, bool skip_align)
Definition: curve.cc:3340
void BKE_nurb_knot_calc_u(Nurb *nu)
Definition: curve.cc:1234
void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
Definition: curve.cc:3929
unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len, const unsigned int resolu, const bool is_cyclic, const bool use_cyclic_duplicate_endpoint)
Definition: curve.cc:1650
static float bezier_calc_handle_adj(float hsize[2], float dx)
Definition: curve.cc:3733
static void bevel_list_apply_tilt(BevList *bl)
Definition: curve.cc:2145
void BKE_curve_nurbs_vert_coords_get(const ListBase *lb, float(*vert_coords)[3], int vert_len)
Definition: curve.cc:4543
void BKE_curve_dimension_update(Curve *cu)
Definition: curve.cc:465
void BKE_nurbList_handles_set(ListBase *editnurb, const char code)
Definition: curve.cc:4212
void BKE_curve_nurbs_key_vert_tilts_apply(ListBase *lb, const float *key)
Definition: curve.cc:4687
void BKE_nurbList_duplicate(ListBase *lb1, const ListBase *lb2)
Definition: curve.cc:726
bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
Definition: curve.cc:5101
static bool tridiagonal_solve_with_limits(float *a, float *b, float *c, float *d, float *h, const float *hmin, const float *hmax, int solve_count)
Definition: curve.cc:3468
void BKE_nurb_handle_calc(BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing)
Definition: curve.cc:3978
void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, BPoint *bp, float r_normal[3])
Definition: curve.cc:1111
static void calcknots(float *knots, const int pnts, const short order, const short flag)
Definition: curve.cc:1164
#define SEL_F1
static void bezier_lock_unknown(float *a, float *b, float *c, float *d, int i, float value)
Definition: curve.cc:3445
#define SEL_F2
static void bezier_handle_calc_smooth_fcurve(BezTriple *bezt, int total, int start, int count, bool cycle)
Definition: curve.cc:3743
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
Definition: curve.cc:1717
static void bezier_eq_noaccel_right(float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
Definition: curve.cc:3639
void BKE_nurbList_free(ListBase *lb)
Definition: curve.cc:649
static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_address)
Definition: curve.cc:146
void BKE_curve_editfont_free(Curve *cu)
Definition: curve.cc:336
#define p2_h1
bool BKE_nurb_check_valid_v(const Nurb *nu)
Definition: curve.cc:4793
static void calchandleNurb_intern(BezTriple *bezt, const BezTriple *prev, const BezTriple *next, eBezTriple_Flag handle_sel_flag, bool is_fcurve, bool skip_align, char fcurve_smoothing)
Definition: curve.cc:3097
int BKE_nurbList_verts_count(const ListBase *nurb)
Definition: curve.cc:588
void BKE_curve_nurbs_vert_coords_apply(ListBase *lb, const float(*vert_coords)[3], const bool constrain_2d)
Definition: curve.cc:4617
static void bevlist_firstlast_direction_calc_from_bpoint(const Nurb *nu, BevList *bl)
Definition: curve.cc:2534
void BKE_curve_material_index_remove(Curve *cu, int index)
Definition: curve.cc:5299
int BKE_nurb_index_from_uv(Nurb *nu, int u, int v)
Definition: curve.cc:942
void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_render)
Definition: curve.cc:2569
void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
Definition: curve.cc:1745
void BKE_curve_calc_coords_axis(const BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, const bool is_cyclic, const bool use_cyclic_duplicate_endpoint, const unsigned int axis, const unsigned int stride, float *r_points)
Definition: curve.cc:1661
static void nurb_handles_calc__align_selected(Nurb *nu)
Definition: curve.cc:4018
void BKE_nurb_knot_calc_v(Nurb *nu)
Definition: curve.cc:1239
static void make_bevel_list_3D(BevList *bl, int smooth_iter, int twist_mode)
Definition: curve.cc:2409
static bool bezier_check_solve_end_handle(BezTriple *bezt, char htype, bool end)
Definition: curve.cc:3727
short BKE_curve_type_get(const Curve *cu)
Definition: curve.cc:444
Nurb * BKE_nurb_duplicate(const Nurb *nu)
Definition: curve.cc:661
void BKE_nurb_bezt_handle_test(BezTriple *bezt, const eBezTriple_Flag__Alias sel_flag, const bool use_handle, const bool use_around_local)
Definition: curve.cc:4049
void(* BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode)
Definition: curve.cc:5521
bool BKE_curve_material_index_used(const Curve *cu, int index)
Definition: curve.cc:5320
BPoint * BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
Definition: curve.cc:1037
void BKE_nurb_direction_switch(Nurb *nu)
Definition: curve.cc:4420
static void curve_blend_read_expand(BlendExpander *expander, ID *id)
Definition: curve.cc:288
void BKE_curve_nurb_vert_active_validate(Curve *cu)
Definition: curve.cc:5076
#define SEL_F3
void BKE_curve_material_index_clear(Curve *cu)
Definition: curve.cc:5343
BoundBox * BKE_curve_boundbox_get(Object *ob)
Definition: curve.cc:494
void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve)
Definition: curve.cc:5506
const ListBase * BKE_curve_editNurbs_get_for_read(const Curve *cu)
Definition: curve.cc:435
bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
Definition: curve.cc:5049
bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
Definition: curve.cc:562
bool BKE_nurb_check_valid_u(const Nurb *nu)
Definition: curve.cc:4785
void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
Definition: curve.cc:928
static float bezier_relax_direction(const float *a, const float *b, const float *c, const float *d, const float *h, int i, int count)
Definition: curve.cc:3430
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
Definition: curve.cc:4354
static void bezier_output_handle_inner(BezTriple *bezt, bool right, const float newval[3], bool endpoint)
Definition: curve.cc:3683
static NURBSValidationStatus nurb_check_valid(const int pnts, const short order, const short flag, const short type, const bool is_surf, int *r_points_needed)
Definition: curve.cc:4711
static void curve_free_data(ID *id)
Definition: curve.cc:108
static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], const float v4[3], short cox, short coy, float *lambda, float *mu, float vec[3])
Definition: curve.cc:1793
static void bezier_restore_equation(float *a, float *b, float *c, float *d, const float *a0, const float *b0, const float *c0, const float *d0, int i)
Definition: curve.cc:3452
void * BKE_curve_vert_active_get(Curve *cu)
Definition: curve.cc:5012
#define p2_h2
bool BKE_nurb_valid_message(const int pnts, const short order, const short flag, const short type, const bool is_surf, const int dir, char *message_dst, const size_t maxncpy)
Definition: curve.cc:4744
static void minimum_twist_between_two_points(BevPoint *current_point, BevPoint *previous_point)
Definition: curve.cc:2232
void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
Definition: curve.cc:363
int BKE_nurbList_verts_count_without_handles(const ListBase *nurb)
Definition: curve.cc:604
BezTriple * BKE_nurb_bezt_get_prev(Nurb *nu, BezTriple *bezt)
Definition: curve.cc:1015
static void bezier_output_handle(BezTriple *bezt, bool right, float dy, bool endpoint)
Definition: curve.cc:3716
float(* BKE_curve_nurbs_key_vert_coords_alloc(const ListBase *lb, float *key, int *r_vert_len))[3]
Definition: curve.cc:4653
bool BKE_nurb_order_clamp_v(struct Nurb *nu)
Definition: curve.cc:4823
static void switch_endian_knots(Nurb *nu)
Definition: curve.cc:196
static void calc_bevel_sin_cos(float x1, float y1, float x2, float y2, float *r_sina, float *r_cosa)
Definition: curve.cc:1915
void BKE_nurb_bezt_calc_plane(struct Nurb *nu, BezTriple *bezt, float r_plane[3])
Definition: curve.cc:1074
int BKE_curve_nurb_vert_index_get(const Nurb *nu, const void *vert)
Definition: curve.cc:5021
static void bezier_eq_continuous(float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
Definition: curve.cc:3630
static void bezier_clamp(float *hmax, float *hmin, int i, float dy, bool no_reverse, bool no_overshoot)
Definition: curve.cc:3658
void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), BezTriple *bezt, float r_normal[3])
Definition: curve.cc:1059
static void tilt_bezpart(const BezTriple *prevbezt, const BezTriple *bezt, const Nurb *nu, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride)
Definition: curve.cc:1963
NURBSValidationStatus
Definition: curve.cc:64
float(* BKE_curve_nurbs_vert_coords_alloc(const ListBase *lb, int *r_vert_len))[3]
Definition: curve.cc:4570
const ListBase * BKE_curve_nurbs_get_for_read(const Curve *cu)
Definition: curve.cc:4985
void BKE_nurb_handle_calc_ex(BezTriple *bezt, BezTriple *prev, BezTriple *next, const eBezTriple_Flag__Alias handle_sel_flag, const bool is_fcurve, const char smoothing)
Definition: curve.cc:3984
void BKE_nurbList_handles_recalculate(ListBase *editnurb, const bool calc_length, const uint8_t flag)
Definition: curve.cc:4297
BezTriple * BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt)
Definition: curve.cc:973
bool BKE_curve_material_index_validate(Curve *cu)
Definition: curve.cc:5360
void BKE_nurb_points_add(Nurb *nu, int number)
Definition: curve.cc:915
ListBase * BKE_curve_nurbs_get(Curve *cu)
Definition: curve.cc:4976
#define SELECT
Curve curve
bool is_valid
const Depsgraph * depsgraph
SyclQueue void void * src
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
static bool is_cyclic(const Nurb *nu)
int count
ccl_global float * buffer
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
const int state
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static ulong * next
#define atan2f(x, y)
Definition: metal/compat.h:227
#define fabsf(x)
Definition: metal/compat.h:219
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
vec_base< T, 3 > cross(const vec_base< T, 3 > &a, const vec_base< T, 3 > &b)
T length(const vec_base< T, Size > &a)
SymEdge< T > * prev(const SymEdge< T > *se)
Definition: delaunay_2d.cc:105
vec_base< float, 3 > float3
static RawVector< RawArray< int64_t, 0 > > arrays
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
const btScalar eps
Definition: poly34.cpp:11
#define min(a, b)
Definition: sort.c:35
unsigned char uint8_t
Definition: stdint.h:78
float weight
uint8_t f1
float vec[4]
float radius
float tilt
struct BevList * next
float * seglen
BevPoint * bevpoints
int * segbevcount
short dupe_tag
float offset
float radius
float dir[3]
float tan[3]
float quat[4]
float weight
float vec[3]
int dir
Definition: curve.cc:1897
BevList * bl
Definition: curve.cc:1895
float left
Definition: curve.cc:1896
char auto_handle_type
uint8_t h1
uint8_t f3
float vec[3][3]
uint8_t f1
uint8_t f2
uint8_t h2
void * orig_cv
Definition: BKE_curve.h:47
ListBase bev
Definition: BKE_curve.h:34
struct Object * bevobj
char edit_data_from_original
float loc[3]
struct CurveProfile * bevel_profile
struct Material ** mat
struct VFont * vfont
short totcol
float xof
int len_char32
struct TextBox * tb
short resolv
void * batch_cache
struct AnimData * adt
struct EditFont * editfont
char bevfac2_mapping
short resolu
short twist_mode
float wordspace
struct Key * key
struct CharInfo * strinfo
struct VFont * vfontb
float linewidth
struct Object * textoncurve
char * str
char texflag
EditNurb * editnurb
struct VFont * vfonti
ListBase nurb
float fsize
float yof
struct VFont * vfontbi
char bevfac1_mapping
struct Object * taperobj
short resolu_ren
float size[3]
float twist_smooth
short type
EditFontSelBox * selboxes
Definition: BKE_vfont.h:37
int len
Definition: BKE_vfont.h:42
char32_t * textbuf
Definition: BKE_vfont.h:32
struct CharInfo * textbufinfo
Definition: BKE_vfont.h:33
struct GHash * keyindex
ListBase nurbs
Definition: DNA_ID.h:368
struct Library * lib
Definition: DNA_ID.h:372
int us
Definition: DNA_ID.h:388
char name[66]
Definition: DNA_ID.h:378
ID * from
Definition: DNA_key_types.h:88
ID id
Definition: DNA_key_types.h:63
ListBase block
Definition: DNA_key_types.h:84
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
short flagu
short orderu
short orderv
float * knotsu
short tilt_interp
short type
float * knotsv
BezTriple * bezt
BPoint * bp
short resolu
short radius_interp
short hide
short flagv
struct CurveCache * curve_cache
struct BoundBox * bb
Object_Runtime runtime
void * data
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
float max