diff options
author | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-01-06 02:24:05 +0400 |
---|---|---|
committer | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-01-06 02:24:05 +0400 |
commit | feccbaabbd39c18b2f552964ebd8dfab4eeaed89 (patch) | |
tree | 0069f654883a7a02dd320649ce61bd7933748111 /source | |
parent | a22096e8019c461128a0907e4026859996ec1b5c (diff) | |
parent | 37ba969c74840142682cf22f34610f3b65b86cf4 (diff) |
Merged changes in the trunk up to revision 53584.
Conflicts resolved:
release/scripts/startup/bl_ui/properties_render.py
source/blender/blenloader/intern/readfile.c
source/blender/editors/interface/interface_templates.c
source/blender/makesrna/RNA_enum_types.h
Also made additional code updates for:
r53355 UIList - Python-extendable list of UI items
r53460 Alpha premul pipeline cleanup
Diffstat (limited to 'source')
416 files changed, 14049 insertions, 5377 deletions
diff --git a/source/blender/avi/intern/avi_intern.h b/source/blender/avi/intern/avi_intern.h index c8d54fe99e9..5dc48657831 100644 --- a/source/blender/avi/intern/avi_intern.h +++ b/source/blender/avi/intern/avi_intern.h @@ -37,9 +37,27 @@ unsigned int GET_FCC (FILE *fp); unsigned int GET_TCC (FILE *fp); -#define PUT_FCC(ch4, fp) putc(ch4[0],fp); putc(ch4[1],fp); putc(ch4[2],fp); putc(ch4[3],fp) -#define PUT_FCCN(num, fp) putc((num>>0)&0377,fp); putc((num>>8)&0377,fp); putc((num>>16)&0377,fp); putc((num>>24)&0377,fp) -#define PUT_TCC(ch2, fp) putc(ch2[0],fp); putc(ch2[1],fp) +#define PUT_FCC(ch4, fp) \ +{ \ + putc(ch4[0], fp); \ + putc(ch4[1], fp); \ + putc(ch4[2], fp); \ + putc(ch4[3], fp); \ +} (void)0 + +#define PUT_FCCN(num, fp) \ +{ \ + putc((num >> 0) & 0377, fp); \ + putc((num >> 8) & 0377, fp); \ + putc((num >> 16) & 0377, fp); \ + putc((num >> 24) & 0377, fp); \ +} (void)0 + +#define PUT_TCC(ch2, fp) \ +{ \ + putc(ch2[0], fp); \ + putc(ch2[1], fp); \ +} (void)0 void *avi_format_convert (AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, int *size); diff --git a/source/blender/avi/intern/avi_mjpeg.c b/source/blender/avi/intern/avi_mjpeg.c index 396f1199cd9..91b8fa5a060 100644 --- a/source/blender/avi/intern/avi_mjpeg.c +++ b/source/blender/avi/intern/avi_mjpeg.c @@ -206,7 +206,7 @@ static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsign return 1; } -static void Compress_JPEG(int quality, unsigned char *outbuffer, unsigned char *inBuffer, int width, int height, int bufsize) +static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned char *inBuffer, int width, int height, int bufsize) { int i, rowstride; unsigned int y; @@ -316,7 +316,8 @@ static int check_and_decode_jpeg(unsigned char *inbuf, unsigned char *outbuf, in } } -static void check_and_compress_jpeg(int quality, unsigned char *outbuf, unsigned char *inbuf, int width, int height, int bufsize) +static void check_and_compress_jpeg(int quality, unsigned char *outbuf, const unsigned char *inbuf, + int width, int height, int bufsize) { /* JPEG's are always multiples of 16, extra is ignored in AVI's */ if ((width & 0xF) || (height & 0xF)) { @@ -379,7 +380,11 @@ void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 1"); if (!movie->interlace) { - check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, buf, buffer, movie->header->Width, movie->header->Height, bufsize); + check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, + buf, buffer, + movie->header->Width, + movie->header->Height, + bufsize); } else { deinterlace(movie->odd_fields, buf, buffer, movie->header->Width, movie->header->Height); @@ -388,10 +393,18 @@ void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, buffer = buf; buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 2"); - check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, buf, buffer, movie->header->Width, movie->header->Height / 2, bufsize / 2); + check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, + buf, buffer, + movie->header->Width, + movie->header->Height / 2, + bufsize / 2); *size += numbytes; numbytes = 0; - check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, buf + *size, buffer + (movie->header->Height / 2) * movie->header->Width * 3, movie->header->Width, movie->header->Height / 2, bufsize / 2); + check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, + buf + *size, buffer + (movie->header->Height / 2) * movie->header->Width * 3, + movie->header->Width, + movie->header->Height / 2, + bufsize / 2); } *size += numbytes; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 91ecded88be..9c7623f3757 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -383,7 +383,7 @@ int blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) if (gc->cur_tex == -1) { blf_glyph_cache_texture(font, gc); gc->x_offs = gc->pad; - gc->y_offs = gc->pad; + gc->y_offs = 0; } if (gc->x_offs > (gc->p2_width - gc->max_glyph_width)) { @@ -391,7 +391,7 @@ int blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) gc->y_offs += gc->max_glyph_height; if (gc->y_offs > (gc->p2_height - gc->max_glyph_height)) { - gc->y_offs = gc->pad; + gc->y_offs = 0; blf_glyph_cache_texture(font, gc); } } @@ -400,6 +400,19 @@ int blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) g->xoff = gc->x_offs; g->yoff = gc->y_offs; + /* prevent glTexSubImage2D from failing if the character + * asks for pixels out of bounds, this tends only to happen + * with very small sizes (5px high or less) */ + if (UNLIKELY((g->xoff + g->width) > gc->p2_width)) { + g->width -= (g->xoff + g->width) - gc->p2_width; + BLI_assert(g->width > 0); + } + if (UNLIKELY((g->yoff + g->height) > gc->p2_height)) { + g->height -= (g->yoff + g->height) - gc->p2_height; + BLI_assert(g->height > 0); + } + + glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c index 4d066ea8740..9086799f984 100644 --- a/source/blender/blenfont/intern/blf_lang.c +++ b/source/blender/blenfont/intern/blf_lang.c @@ -100,7 +100,7 @@ static void fill_locales(void) /* First loop to find highest locale ID */ while (line) { int t; - str = (char*) line->link; + str = (char *)line->link; if (str[0] == '#' || str[0] == '\0') { line = line->next; continue; /* Comment or void... */ @@ -118,12 +118,12 @@ static void fill_locales(void) line = lines; /* Do not allocate locales with zero-sized mem, as LOCALE macro uses NULL locales as invalid marker! */ if (num_locales > 0) { - locales = MEM_callocN(num_locales * sizeof(char*), __func__); + locales = MEM_callocN(num_locales * sizeof(char *), __func__); while (line) { int id; char *loc, *sep1, *sep2, *sep3; - str = (char*) line->link; + str = (char *)line->link; if (str[0] == '#' || str[0] == '\0') { line = line->next; continue; @@ -230,7 +230,7 @@ void BLF_lang_set(const char *str) bl_locale_set(short_locale_utf8); if (short_locale[0]) { - MEM_freeN((void*)short_locale_utf8); + MEM_freeN((void *)short_locale_utf8); } } diff --git a/source/blender/blenkernel/BKE_addon.h b/source/blender/blenkernel/BKE_addon.h new file mode 100644 index 00000000000..eafaec3e605 --- /dev/null +++ b/source/blender/blenkernel/BKE_addon.h @@ -0,0 +1,42 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_ADDON_H__ +#define __BKE_ADDON_H__ + +#include "RNA_types.h" + +typedef struct bAddonPrefType { + /* type info */ + char idname[64]; // best keep the same size as BKE_ST_MAXNAME + + /* RNA integration */ + ExtensionRNA ext; +} bAddonPrefType; + +bAddonPrefType *BKE_addon_pref_type_find(const char *idname, int quiet); +void BKE_addon_pref_type_add(bAddonPrefType *apt); +void BKE_addon_pref_type_remove(bAddonPrefType *apt); + +void BKE_addon_pref_type_init(void); +void BKE_addon_pref_type_free(void); + +#endif /* __BKE_ADDON_H__ */ diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 11759a82e60..10528f1b270 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 265 -#define BLENDER_SUBVERSION 3 +#define BLENDER_SUBVERSION 5 /* 262 was the last editmesh release but it has compatibility code for bmesh data */ #define BLENDER_MINVERSION 262 diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index cbffb6c0cea..248fe9c8968 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -99,6 +99,7 @@ float BKE_brush_unprojected_radius_get(const struct Scene *scene, struct Brush * void BKE_brush_unprojected_radius_set(struct Scene *scene, struct Brush *brush, float value); float BKE_brush_alpha_get(const struct Scene *scene, struct Brush *brush); +void BKE_brush_alpha_set(Scene *scene, struct Brush *brush, float alpha); float BKE_brush_weight_get(const Scene *scene, struct Brush *brush); void BKE_brush_weight_set(const Scene *scene, struct Brush *brush, float value); diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 79e75127763..c79dc62bb61 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -108,8 +108,8 @@ typedef struct bConstraintTypeInfo { } bConstraintTypeInfo; /* Function Prototypes for bConstraintTypeInfo's */ -bConstraintTypeInfo *constraint_get_typeinfo(struct bConstraint *con); -bConstraintTypeInfo *get_constraint_typeinfo(int type); +bConstraintTypeInfo *BKE_constraint_get_typeinfo(struct bConstraint *con); +bConstraintTypeInfo *BKE_get_constraint_typeinfo(int type); /* ---------------------------------------------------------------------------- */ /* Useful macros for testing various common flag combinations */ @@ -120,38 +120,38 @@ bConstraintTypeInfo *get_constraint_typeinfo(int type); /* ---------------------------------------------------------------------------- */ /* Constraint function prototypes */ -void unique_constraint_name(struct bConstraint *con, struct ListBase *list); +void BKE_unique_constraint_name(struct bConstraint *con, struct ListBase *list); -void free_constraints(struct ListBase *list); -void copy_constraints(struct ListBase *dst, const struct ListBase *src, int do_extern); -void relink_constraints(struct ListBase *list); -void id_loop_constraints(struct ListBase *list, ConstraintIDFunc func, void *userdata); -void free_constraint_data(struct bConstraint *con); +void BKE_free_constraints(struct ListBase *list); +void BKE_copy_constraints(struct ListBase *dst, const struct ListBase *src, int do_extern); +void BKE_relink_constraints(struct ListBase *list); +void BKE_id_loop_constraints(struct ListBase *list, ConstraintIDFunc func, void *userdata); +void BKE_free_constraint_data(struct bConstraint *con); /* Constraint API function prototypes */ -struct bConstraint *constraints_get_active(struct ListBase *list); -void constraints_set_active(ListBase *list, struct bConstraint *con); -struct bConstraint *constraints_findByName(struct ListBase *list, const char *name); - -struct bConstraint *add_ob_constraint(struct Object *ob, const char *name, short type); -struct bConstraint *add_pose_constraint(struct Object *ob, struct bPoseChannel *pchan, const char *name, short type); +struct bConstraint *BKE_constraints_get_active(struct ListBase *list); +void BKE_constraints_set_active(ListBase *list, struct bConstraint *con); +struct bConstraint *BKE_constraints_findByName(struct ListBase *list, const char *name); + +struct bConstraint *BKE_add_ob_constraint(struct Object *ob, const char *name, short type); +struct bConstraint *BKE_add_pose_constraint(struct Object *ob, struct bPoseChannel *pchan, const char *name, short type); -int remove_constraint(ListBase *list, struct bConstraint *con); -void remove_constraints_type(ListBase *list, short type, short last_only); +int BKE_remove_constraint(ListBase *list, struct bConstraint *con); +void BKE_remove_constraints_type(ListBase *list, short type, short last_only); /* Constraints + Proxies function prototypes */ -void extract_proxylocal_constraints(struct ListBase *dst, struct ListBase *src); -short proxylocked_constraints_owner(struct Object *ob, struct bPoseChannel *pchan); +void BKE_extract_proxylocal_constraints(struct ListBase *dst, struct ListBase *src); +short BKE_proxylocked_constraints_owner(struct Object *ob, struct bPoseChannel *pchan); /* Constraint Evaluation function prototypes */ -struct bConstraintOb *constraints_make_evalob(struct Scene *scene, struct Object *ob, void *subdata, short datatype); -void constraints_clear_evalob(struct bConstraintOb *cob); +struct bConstraintOb *BKE_constraints_make_evalob(struct Scene *scene, struct Object *ob, void *subdata, short datatype); +void BKE_constraints_clear_evalob(struct bConstraintOb *cob); -void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to); +void BKE_constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to); -void get_constraint_target_matrix(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime); -void get_constraint_targets_for_solving(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime); -void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime); +void BKE_get_constraint_target_matrix(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime); +void BKE_get_constraint_targets_for_solving(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime); +void BKE_solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index 8306da71432..ab27421b383 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -56,6 +56,9 @@ void defvert_remove_group(struct MDeformVert *dvert, struct void defvert_clear(struct MDeformVert *dvert); int defvert_find_shared(const struct MDeformVert *dvert_a, const struct MDeformVert *dvert_b); +void BKE_defvert_array_free(struct MDeformVert *dvert, int totvert); +void BKE_defvert_array_copy(struct MDeformVert *dst, const struct MDeformVert *src, int totvert); + float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup); float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup); diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 758a2a8a2e8..6b986cdceda 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -83,7 +83,7 @@ void BKE_displist_elem_free(DispList *dl); DispList *BKE_displist_find_or_create(struct ListBase *lb, int type); DispList *BKE_displist_find(struct ListBase *lb, int type); void BKE_displist_normals_add(struct ListBase *lb); -void BKE_displist_count(struct ListBase *lb, int *totvert, int *totface); +void BKE_displist_count(struct ListBase *lb, int *totvert, int *totface, int *tottri); void BKE_displist_free(struct ListBase *lb); int BKE_displist_has_faces(struct ListBase *lb); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index a9f6a61a655..ad3e4bb2251 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -315,6 +315,8 @@ __attribute__((nonnull)) * the actual struct IDProperty struct either.*/ void IDP_FreeProperty(struct IDProperty *prop); +void IDP_ClearProperty(IDProperty *prop); + /** Unlinks any struct IDProperty<->ID linkage that might be going on.*/ void IDP_UnlinkProperty(struct IDProperty *prop); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 1f9630d9fce..499609932d1 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -60,8 +60,10 @@ int BKE_imbuf_alpha_test(struct ImBuf *ibuf); int BKE_imbuf_write_stamp(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf); int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf); int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf, const short is_copy); -void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame, const char imtype, const short use_ext, const short use_frames); -int BKE_add_image_extension(char *string, const char imtype); +void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame, const struct ImageFormatData *im_format, const short use_ext, const short use_frames); +void BKE_makepicstring_from_type(char *string, const char *base, const char *relbase, int frame, const char imtype, const short use_ext, const short use_frames); +int BKE_add_image_extension(char *string, const struct ImageFormatData *im_format); +int BKE_add_image_extension_from_type(char *string, const char imtype); char BKE_ftype_to_imtype(const int ftype); int BKE_imtype_to_ftype(const char imtype); diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index d7d75b4c4c9..a159cbb13d4 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -59,7 +59,7 @@ void key_curve_position_weights(float t, float data[4], int type); void key_curve_tangent_weights(float t, float data[4], int type); void key_curve_normal_weights(float t, float data[4], int type); -float *do_ob_key(struct Scene *scene, struct Object *ob); +float *BKE_key_evaluate_object(struct Scene *scene, struct Object *ob, int *r_totelem); struct Key *BKE_key_from_object(struct Object *ob); struct KeyBlock *BKE_keyblock_from_object(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 320ced67a2f..db9f1228f76 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -162,8 +162,6 @@ void BKE_mesh_from_nurbs(struct Object *ob); void BKE_mesh_from_nurbs_displist(struct Object *ob, struct ListBase *dispbase, int **orco_index_ptr); void BKE_mesh_from_curve(struct Scene *scene, struct Object *ob); -void free_dverts(struct MDeformVert *dvert, int totvert); -void copy_dverts(struct MDeformVert *dst, const struct MDeformVert *src, int totvert); void BKE_mesh_delete_material_index(struct Mesh *me, short index); void BKE_mesh_smooth_flag_set(struct Object *meshOb, int enableSmooth); void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index b8f168cbdea..0a2f757b38e 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -557,6 +557,7 @@ struct ShadeResult; #define SH_NODE_BSDF_REFRACTION 173 #define SH_NODE_TANGENT 174 #define SH_NODE_NORMAL_MAP 175 +#define SH_NODE_HAIR_INFO 176 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h index 603cb1f22a6..9dcbb41c7dc 100644 --- a/source/blender/blenkernel/BKE_packedFile.h +++ b/source/blender/blenkernel/BKE_packedFile.h @@ -48,6 +48,7 @@ struct PackedFile *newPackedFile(struct ReportList *reports, const char *filenam struct PackedFile *newPackedFileMemory(void *mem, int memlen); void packAll(struct Main *bmain, struct ReportList *reports); +void packLibraries(struct Main *bmain, struct ReportList *reports); /* unpack */ char *unpackFile(struct ReportList *reports, const char *abs_name, const char *local_name, struct PackedFile *pf, int how); @@ -55,6 +56,7 @@ int unpackVFont(struct ReportList *reports, struct VFont *vfont, int how); int unpackSound(struct Main *bmain, struct ReportList *reports, struct bSound *sound, int how); int unpackImage(struct ReportList *reports, struct Image *ima, int how); void unpackAll(struct Main *bmain, struct ReportList *reports, int how); +int unpackLibraries(struct Main *bmain, struct ReportList *reports); int writePackedFile(struct ReportList *reports, const char *filename, struct PackedFile *pf, int guimode); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index c452c177143..0a4a7f75e25 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -33,6 +33,7 @@ */ struct bContext; +struct BMesh; struct Brush; struct MDisps; struct MeshElemMap; @@ -92,6 +93,12 @@ typedef struct SculptSession { /* Mesh connectivity */ const struct MeshElemMap *pmap; + /* BMesh for dynamic topology sculpting */ + struct BMesh *bm; + int bm_smooth_shading; + /* Undo/redo log for dynamic topology sculpting */ + struct BMLog *bm_log; + /* PBVH acceleration structure */ struct PBVH *pbvh; int show_diffuse_color; @@ -121,5 +128,6 @@ typedef struct SculptSession { void free_sculptsession(struct Object *ob); void free_sculptsession_deformMats(struct SculptSession *ss); +void sculptsession_bm_to_me(struct Object *ob, int reorder); #endif diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 302de593963..709db7e4570 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -18,8 +18,8 @@ * ***** END GPL LICENSE BLOCK ***** */ -#ifndef __BLI_PBVH_H__ -#define __BLI_PBVH_H__ +#ifndef __BKE_PBVH_H__ +#define __BKE_PBVH_H__ /** \file BKE_pbvh.h * \ingroup bke @@ -27,13 +27,18 @@ */ #include "BLI_bitmap.h" +#include "BLI_ghash.h" +#include "BLI_utildefines.h" + +/* Needed for BMesh functions used in the PBVH iterator macro */ +#include "bmesh.h" struct CCGElem; struct CCGKey; struct CustomData; struct DMFlagMat; struct DMGridAdjacency; -struct ListBase; +struct GHash; struct MFace; struct MVert; struct PBVH; @@ -49,32 +54,35 @@ typedef struct { /* Callbacks */ /* returns 1 if the search should continue from this node, 0 otherwise */ -typedef int (*BLI_pbvh_SearchCallback)(PBVHNode *node, void *data); +typedef int (*BKE_pbvh_SearchCallback)(PBVHNode *node, void *data); -typedef void (*BLI_pbvh_HitCallback)(PBVHNode *node, void *data); -typedef void (*BLI_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *tmin); +typedef void (*BKE_pbvh_HitCallback)(PBVHNode *node, void *data); +typedef void (*BKE_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *tmin); /* Building */ -PBVH *BLI_pbvh_new(void); -void BLI_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts, +PBVH *BKE_pbvh_new(void); +void BKE_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts, int totface, int totvert, struct CustomData *vdata); -void BLI_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems, +void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems, struct DMGridAdjacency *gridadj, int totgrid, struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden); -void BLI_pbvh_free(PBVH *bvh); +void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, int smooth_shading, + struct BMLog *log); + +void BKE_pbvh_free(PBVH *bvh); /* Hierarchical Search in the BVH, two methods: * - for each hit calling a callback * - gather nodes in an array (easy to multithread) */ -void BLI_pbvh_search_callback(PBVH *bvh, - BLI_pbvh_SearchCallback scb, void *search_data, - BLI_pbvh_HitCallback hcb, void *hit_data); +void BKE_pbvh_search_callback(PBVH *bvh, + BKE_pbvh_SearchCallback scb, void *search_data, + BKE_pbvh_HitCallback hcb, void *hit_data); -void BLI_pbvh_search_gather(PBVH *bvh, - BLI_pbvh_SearchCallback scb, void *search_data, +void BKE_pbvh_search_gather(PBVH *bvh, + BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot); /* Raycast @@ -82,33 +90,45 @@ void BLI_pbvh_search_gather(PBVH *bvh, * it's up to the callback to find the primitive within the leaves that is * hit first */ -void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data, +void BKE_pbvh_raycast(PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data, const float ray_start[3], const float ray_normal[3], int original); -int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], +int BKE_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco, const float ray_start[3], const float ray_normal[3], float *dist); /* Drawing */ -void BLI_pbvh_node_draw(PBVHNode *node, void *data); -void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], - int (*setMaterial)(int, void *attribs)); +void BKE_pbvh_node_draw(PBVHNode *node, void *data); +void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], + int (*setMaterial)(int, void *attribs), int wireframe); /* PBVH Access */ typedef enum { PBVH_FACES, PBVH_GRIDS, + PBVH_BMESH } PBVHType; -PBVHType BLI_pbvh_type(const PBVH *bvh); +PBVHType BKE_pbvh_type(const PBVH *bvh); /* multires hidden data, only valid for type == PBVH_GRIDS */ -unsigned int **BLI_pbvh_grid_hidden(const PBVH *bvh); +unsigned int **BKE_pbvh_grid_hidden(const PBVH *bvh); /* multires level, only valid for type == PBVH_GRIDS */ -void BLI_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key); +void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key); + +/* Only valid for type == PBVH_BMESH */ +BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); +void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size); + +typedef enum { + PBVH_Subdivide = 1, + PBVH_Collapse = 2, +} PBVHTopologyUpdateMode; +int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, + const float center[3], float radius); /* Node Access */ @@ -122,45 +142,60 @@ typedef enum { PBVH_UpdateRedraw = 32, PBVH_RebuildDrawBuffers = 64, - PBVH_FullyHidden = 128 + PBVH_FullyHidden = 128, + + PBVH_UpdateTopology = 256, } PBVHNodeFlags; -void BLI_pbvh_node_mark_update(PBVHNode *node); -void BLI_pbvh_node_mark_rebuild_draw(PBVHNode *node); -void BLI_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden); +void BKE_pbvh_node_mark_update(PBVHNode *node); +void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node); +void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden); +void BKE_pbvh_node_mark_topology_update(PBVHNode *node); -void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, +void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, struct CCGElem ***grid_elems, struct DMGridAdjacency **gridadj); -void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, +void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *totvert); -void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, +void BKE_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, int **vert_indices, struct MVert **verts); -void BLI_pbvh_node_get_BB(PBVHNode * node, float bb_min[3], float bb_max[3]); -void BLI_pbvh_node_get_original_BB(PBVHNode * node, float bb_min[3], float bb_max[3]); +void BKE_pbvh_node_get_BB(PBVHNode * node, float bb_min[3], float bb_max[3]); +void BKE_pbvh_node_get_original_BB(PBVHNode * node, float bb_min[3], float bb_max[3]); -float BLI_pbvh_node_get_tmin(PBVHNode *node); +float BKE_pbvh_node_get_tmin(PBVHNode *node); /* test if AABB is at least partially inside the planes' volume */ -int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data); +int BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data); /* test if AABB is at least partially outside the planes' volume */ -int BLI_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data); +int BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data); + +struct GHash *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node); +struct GHash *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node); +void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node); +void BKE_pbvh_bmesh_after_stroke(PBVH *bvh); /* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */ -void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]); -void BLI_pbvh_redraw_BB(PBVH * bvh, float bb_min[3], float bb_max[3]); -void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface); -void BLI_pbvh_grids_update(PBVH *bvh, struct CCGElem **grid_elems, +void BKE_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]); +void BKE_pbvh_redraw_BB(PBVH * bvh, float bb_min[3], float bb_max[3]); +void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface); +void BKE_pbvh_grids_update(PBVH *bvh, struct CCGElem **grid_elems, struct DMGridAdjacency *gridadj, void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden); -/* vertex deformer */ -float (*BLI_pbvh_get_vertCos(struct PBVH *pbvh))[3]; -void BLI_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]); -int BLI_pbvh_isDeformed(struct PBVH *pbvh); +/* Layer displacement */ + +/* Get the node's displacement layer, creating it if necessary */ +float *BKE_pbvh_node_layer_disp_get(PBVH *pbvh, PBVHNode *node); +/* If the node has a displacement layer, free it and set to null */ +void BKE_pbvh_node_layer_disp_free(PBVHNode *node); + +/* vertex deformer */ +float (*BKE_pbvh_get_vertCos(struct PBVH *pbvh))[3]; +void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]); +int BKE_pbvh_isDeformed(struct PBVH *pbvh); /* Vertex Iterator */ @@ -197,9 +232,15 @@ typedef struct PBVHVertexIter { int *vert_indices; float *vmask; + /* bmesh */ + struct GHashIterator bm_unique_verts; + struct GHashIterator bm_other_verts; + struct CustomData *bm_vdata; + /* result: these are all computed in the macro, but we assume * that compiler optimization's will skip the ones we don't use */ struct MVert *mvert; + struct BMVert *bm_vert; float *co; short *no; float *fno; @@ -213,7 +254,7 @@ typedef struct PBVHVertexIter { void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mode); -#define BLI_pbvh_vertex_iter_begin(bvh, node, vi, mode) \ +#define BKE_pbvh_vertex_iter_begin(bvh, node, vi, mode) \ pbvh_vertex_iter_init(bvh, node, &vi, mode); \ \ for (vi.i = 0, vi.g = 0; vi.g < vi.totgrid; vi.g++) { \ @@ -241,7 +282,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, continue; \ } \ } \ - else { \ + else if (vi.mverts) { \ vi.mvert = &vi.mverts[vi.vert_indices[vi.gx]]; \ if (mode == PBVH_ITER_UNIQUE && vi.mvert->flag & ME_HIDE) \ continue; \ @@ -250,21 +291,39 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, if (vi.vmask) \ vi.mask = &vi.vmask[vi.vert_indices[vi.gx]]; \ } \ - -#define BLI_pbvh_vertex_iter_end \ + else { \ + if (!BLI_ghashIterator_isDone(&vi.bm_unique_verts)) {\ + vi.bm_vert = BLI_ghashIterator_getKey(&vi.bm_unique_verts); \ + BLI_ghashIterator_step(&vi.bm_unique_verts); \ + } \ + else { \ + vi.bm_vert = BLI_ghashIterator_getKey(&vi.bm_other_verts); \ + BLI_ghashIterator_step(&vi.bm_other_verts); \ + } \ + if (mode == PBVH_ITER_UNIQUE && \ + BM_elem_flag_test(vi.bm_vert, BM_ELEM_HIDDEN)) \ + continue; \ + vi.co = vi.bm_vert->co; \ + vi.fno = vi.bm_vert->no; \ + vi.mask = CustomData_bmesh_get(vi.bm_vdata, \ + vi.bm_vert->head.data, \ + CD_PAINT_MASK); \ + } + +#define BKE_pbvh_vertex_iter_end \ } \ } \ } -void BLI_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count); -void BLI_pbvh_node_free_proxies(PBVHNode *node); -PBVHProxyNode *BLI_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node); -void BLI_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***nodes, int *totnode); +void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count); +void BKE_pbvh_node_free_proxies(PBVHNode *node); +PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node); +void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***nodes, int *totnode); -//void BLI_pbvh_node_BB_reset(PBVHNode *node); -//void BLI_pbvh_node_BB_expand(PBVHNode *node, float co[3]); +//void BKE_pbvh_node_BB_reset(PBVHNode *node); +//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]); void pbvh_show_diffuse_color_set(PBVH *bvh, int show_diffuse_color); -#endif /* __BLI_PBVH_H__ */ +#endif /* __BKE_PBVH_H__ */ diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 8aa08beec57..3c6f886b59a 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -46,6 +46,7 @@ struct bContext; struct bContextDataResult; struct bScreen; struct uiLayout; +struct uiList; struct uiMenuItem; struct wmKeyConfig; struct wmNotifier; @@ -181,6 +182,23 @@ typedef struct PanelType { ExtensionRNA ext; } PanelType; +/* uilist types */ + +/* draw an item in the uiList */ +typedef void (*uiListDrawItemFunc)(struct uiList *, struct bContext *, struct uiLayout *, struct PointerRNA *, + struct PointerRNA *, int, struct PointerRNA *, const char *, int); + +typedef struct uiListType { + struct uiListType *next, *prev; + + char idname[BKE_ST_MAXNAME]; /* unique name */ + + uiListDrawItemFunc draw_item; + + /* RNA integration */ + ExtensionRNA ext; +} uiListType; + /* header types */ typedef struct HeaderType { diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index d1332ba937e..61d82e6c604 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -121,7 +121,8 @@ typedef struct ShrinkwrapCalcData { } ShrinkwrapCalcData; -void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts); +void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, + float (*vertexCos)[3], int numVerts); /* * This function casts a ray in the given BVHTree.. but it takes into consideration the space_transform, that is: @@ -130,9 +131,12 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object * then the input (vert, dir, BVHTreeRayHit) must be defined in ob1 coordinates space * and the BVHTree must be built in ob2 coordinate space. * - * Thus it provides an easy way to cast the same ray across several trees (where each tree was built on its own coords space) + * Thus it provides an easy way to cast the same ray across several trees + * (where each tree was built on its own coords space) */ -int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); +int normal_projection_project_vertex(char options, const float vert[3], const float dir[3], + const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, + BVHTree_RayCastCallback callback, void *userdata); /* * NULL initializers to local data @@ -142,6 +146,4 @@ int normal_projection_project_vertex(char options, const float *vert, const floa #define NULL_BVHTreeRayHit {NULL, } #define NULL_BVHTreeNearest {0, } - -#endif - +#endif /* __BKE_SHRINKWRAP_H__ */ diff --git a/source/blender/blenkernel/BKE_suggestions.h b/source/blender/blenkernel/BKE_suggestions.h index 9b61d9141fb..c36a2d61968 100644 --- a/source/blender/blenkernel/BKE_suggestions.h +++ b/source/blender/blenkernel/BKE_suggestions.h @@ -75,7 +75,7 @@ short texttool_text_is_active(Text *text); /* Suggestions */ void texttool_suggest_add(const char *name, char type); -void texttool_suggest_prefix(const char *prefix); +void texttool_suggest_prefix(const char *prefix, const int prefix_len); void texttool_suggest_clear(void); SuggItem *texttool_suggest_first(void); SuggItem *texttool_suggest_last(void); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index accac8694a9..1e3dd426efa 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -106,6 +106,7 @@ int text_check_delim(const char ch); int text_check_digit(const char ch); int text_check_identifier(const char ch); int text_check_whitespace(const char ch); +int text_find_identifier_start(const char *str, int i); enum { TXT_MOVE_LINE_UP = -1, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 7a11bdb1f39..23f23acad6b 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -58,6 +58,7 @@ set(SRC intern/CCGSubSurf.c intern/DerivedMesh.c intern/action.c + intern/addon.c intern/anim.c intern/anim_sys.c intern/armature.c @@ -123,6 +124,7 @@ set(SRC intern/particle.c intern/particle_system.c intern/pbvh.c + intern/pbvh_bmesh.c intern/pointcache.c intern/property.c intern/report.c @@ -152,6 +154,7 @@ set(SRC BKE_DerivedMesh.h BKE_action.h + BKE_addon.h BKE_anim.h BKE_animsys.h BKE_armature.h @@ -242,6 +245,7 @@ set(SRC depsgraph_private.h nla_private.h intern/CCGSubSurf.h + intern/pbvh_intern.h ) add_definitions(-DGLEW_STATIC) @@ -255,7 +259,7 @@ endif() if(WITH_BULLET) list(APPEND INC_SYS - ../../../extern/bullet2/src + ${BULLET_INCLUDE_DIRS} ) add_definitions(-DUSE_BULLET) endif() diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 2dc01513149..ec8d37e1ae3 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1340,6 +1340,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); int has_multires = mmd != NULL, multires_applied = 0; int sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt; + int sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm); const int draw_flag = ((scene->toolsettings->multipaint ? CALC_WP_MULTIPAINT : 0) | (scene->toolsettings->auto_normalize ? CALC_WP_AUTO_NORMALIZE : 0)); @@ -1407,7 +1408,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos if (!modifier_isEnabled(scene, md, required_mode)) continue; if (useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) continue; - if (mti->type == eModifierTypeType_OnlyDeform) { + if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) { if (!deformedVerts) deformedVerts = mesh_getVertexCos(me, &numVerts); @@ -1465,9 +1466,14 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos modifier_setError(md, "Modifier requires original data, bad stack position"); continue; } - if (sculpt_mode && (!has_multires || multires_applied)) { + if (sculpt_mode && + (!has_multires || multires_applied || ob->sculpt->bm)) + { int unsupported = 0; + if (sculpt_dyntopo) + unsupported = TRUE; + if (scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM) unsupported |= mti->type != eModifierTypeType_OnlyDeform; @@ -2310,20 +2316,19 @@ DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em) static void make_vertexcosnos__mapFunc(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]) { - float *vec = userData; - - vec += 6 * index; + DMCoNo *co_no = &((DMCoNo *)userData)[index]; /* check if we've been here before (normal should not be 0) */ - if (vec[3] || vec[4] || vec[5]) return; + if (!is_zero_v3(co_no->no)) { + return; + } - copy_v3_v3(vec, co); - vec += 3; + copy_v3_v3(co_no->co, co); if (no_f) { - copy_v3_v3(vec, no_f); + copy_v3_v3(co_no->no, no_f); } else { - normal_short_to_float_v3(vec, no_s); + normal_short_to_float_v3(co_no->no, no_s); } } diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 83d1538ecbe..63e12dfb99d 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -543,7 +543,7 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, int copycon) for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) { /* TODO: rename this argument... */ if (copycon) { - copy_constraints(&listb, &pchan->constraints, TRUE); // copy_constraints NULLs listb + BKE_copy_constraints(&listb, &pchan->constraints, TRUE); // BKE_copy_constraints NULLs listb pchan->constraints = listb; pchan->mpath = NULL; /* motion paths should not get copied yet... */ } @@ -621,7 +621,7 @@ void BKE_pose_channel_free(bPoseChannel *pchan) pchan->mpath = NULL; } - free_constraints(&pchan->constraints); + BKE_free_constraints(&pchan->constraints); if (pchan->prop) { IDP_FreeProperty(pchan->prop); @@ -711,7 +711,7 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f pchan->iklinweight = pchan_from->iklinweight; /* constraints */ - copy_constraints(&pchan->constraints, &pchan_from->constraints, TRUE); + BKE_copy_constraints(&pchan->constraints, &pchan_from->constraints, TRUE); /* id-properties */ if (pchan->prop) { diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c new file mode 100644 index 00000000000..7f475cd4732 --- /dev/null +++ b/source/blender/blenkernel/intern/addon.c @@ -0,0 +1,85 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stddef.h> +#include <stdlib.h> + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_string.h" + +#include "BKE_addon.h" /* own include */ + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "BLF_translation.h" + +#include "MEM_guardedalloc.h" + +static GHash *global_addonpreftype_hash = NULL; + + +bAddonPrefType *BKE_addon_pref_type_find(const char *idname, int quiet) +{ + if (idname[0]) { + bAddonPrefType *apt; + + apt = BLI_ghash_lookup(global_addonpreftype_hash, idname); + if (apt) { + return apt; + } + + if (!quiet) { + printf("search for unknown addon-pref '%s'\n", idname); + } + } + else { + if (!quiet) { + printf("search for empty addon-pref"); + } + } + + return NULL; +} + +void BKE_addon_pref_type_add(bAddonPrefType *apt) +{ + BLI_ghash_insert(global_addonpreftype_hash, (void *)apt->idname, apt); +} + +void BKE_addon_pref_type_remove(bAddonPrefType *apt) +{ + BLI_ghash_remove(global_addonpreftype_hash, (void *)apt->idname, NULL, (GHashValFreeFP)MEM_freeN); +} + +void BKE_addon_pref_type_init(void) +{ + BLI_assert(global_addonpreftype_hash == NULL); + global_addonpreftype_hash = BLI_ghash_str_new(__func__); +} + +void BKE_addon_pref_type_free(void) +{ + BLI_ghash_free(global_addonpreftype_hash, NULL, (GHashValFreeFP)MEM_freeN); + global_addonpreftype_hash = NULL; +} diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 9155d67dc36..ad14dee168a 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1620,15 +1620,16 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected * 2. copy proxy-pchan's constraints on-to new * 3. add extracted local constraints back on top * - * Note for copy_constraints: when copying constraints, disable 'do_extern' otherwise - * we get the libs direct linked in this blend. */ - extract_proxylocal_constraints(&proxylocal_constraints, &pchan->constraints); - copy_constraints(&pchanw.constraints, &pchanp->constraints, FALSE); + * Note for BKE_copy_constraints: when copying constraints, disable 'do_extern' otherwise + * we get the libs direct linked in this blend. + */ + BKE_extract_proxylocal_constraints(&proxylocal_constraints, &pchan->constraints); + BKE_copy_constraints(&pchanw.constraints, &pchanp->constraints, FALSE); BLI_movelisttolist(&pchanw.constraints, &proxylocal_constraints); /* constraints - set target ob pointer to own object */ for (con = pchanw.constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -2426,15 +2427,15 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float /* prepare PoseChannel for Constraint solving * - makes a copy of matrix, and creates temporary struct to use */ - cob = constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE); + cob = BKE_constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE); /* Solve PoseChannel's Constraints */ - solve_constraints(&pchan->constraints, cob, ctime); /* ctime doesnt alter objects */ + BKE_solve_constraints(&pchan->constraints, cob, ctime); /* ctime doesnt alter objects */ /* cleanup after Constraint Solving * - applies matrix back to pchan, and frees temporary struct used */ - constraints_clear_evalob(cob); + BKE_constraints_clear_evalob(cob); /* prevent constraints breaking a chain */ if (pchan->bone->flag & BONE_CONNECTED) { diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 5c0856bc95b..11ae242023c 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -387,6 +387,7 @@ void BKE_userdef_free(void) wmKeyMap *km; wmKeyMapItem *kmi; wmKeyMapDiffItem *kmdi; + bAddon *addon, *addon_next; for (km = U.user_keymaps.first; km; km = km->next) { for (kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) { @@ -407,11 +408,19 @@ void BKE_userdef_free(void) BLI_freelistN(&km->items); } + for (addon = U.addons.first; addon; addon = addon_next) { + addon_next = addon->next; + if (addon->prop) { + IDP_FreeProperty(addon->prop); + MEM_freeN(addon->prop); + } + MEM_freeN(addon); + } + BLI_freelistN(&U.uistyles); BLI_freelistN(&U.uifonts); BLI_freelistN(&U.themes); BLI_freelistN(&U.user_keymaps); - BLI_freelistN(&U.addons); } /* handle changes in settings that need recalc */ diff --git a/source/blender/blenkernel/intern/bmfont.c b/source/blender/blenkernel/intern/bmfont.c index 0495e729937..fc83b24da5b 100644 --- a/source/blender/blenkernel/intern/bmfont.c +++ b/source/blender/blenkernel/intern/bmfont.c @@ -65,8 +65,8 @@ void printfGlyph(bmGlyph * glyph) printf(" advan: %3d reser: %3d\n", glyph->advance, glyph->reserved); } -#define MAX2(x,y) ((x) > (y) ? (x) : (y)) -#define MAX3(x,y,z) MAX2(MAX2((x), (y)), (z)) +#define MAX2(x, y) ((x) > (y) ? (x) : (y)) +#define MAX3(x, y, z) (MAX2(MAX2((x), (y)), (z))) void calcAlpha(ImBuf * ibuf) { diff --git a/source/blender/blenkernel/intern/booleanops_mesh.c b/source/blender/blenkernel/intern/booleanops_mesh.c index 461b945282f..f53a89fccfd 100644 --- a/source/blender/blenkernel/intern/booleanops_mesh.c +++ b/source/blender/blenkernel/intern/booleanops_mesh.c @@ -56,7 +56,7 @@ CSG_DestroyBlenderMeshInternals( CSG_MeshDescriptor *mesh ) { /* Free face and vertex iterators. */ - FreeMeshDescriptors(&(mesh->m_face_iterator),&(mesh->m_vertex_iterator)); + FreeMeshDescriptors(&(mesh->m_face_iterator), &(mesh->m_vertex_iterator)); } @@ -138,7 +138,7 @@ CSG_AddMeshToBlender( if (mesh == NULL) return 0; if (mesh->base == NULL) return 0; - invert_m4_m4(inv_mat,mesh->base->object->obmat); + invert_m4_m4(inv_mat, mesh->base->object->obmat); /* Create a new blender mesh object - using 'base' as * a template for the new object. */ @@ -191,7 +191,7 @@ CSG_PerformOp( default : op_type = e_csg_intersection; } - output->m_descriptor = CSG_DescibeOperands(bool_op,mesh1->m_descriptor,mesh2->m_descriptor); + output->m_descriptor = CSG_DescibeOperands(bool_op, mesh1->m_descriptor, mesh2->m_descriptor); output->base = mesh1->base; if (output->m_descriptor.user_face_vertex_data_size) { @@ -228,8 +228,8 @@ CSG_PerformOp( /* get the ouput mesh descriptors. */ - CSG_OutputFaceDescriptor(bool_op,&(output->m_face_iterator)); - CSG_OutputVertexDescriptor(bool_op,&(output->m_vertex_iterator)); + CSG_OutputFaceDescriptor(bool_op, &(output->m_face_iterator)); + CSG_OutputVertexDescriptor(bool_op, &(output->m_vertex_iterator)); output->m_destroy_func = CSG_DestroyCSGMeshInternals; return 1; @@ -242,20 +242,20 @@ NewBooleanMeshTest( int op_type ) { - CSG_MeshDescriptor m1,m2,output; - CSG_MeshDescriptor output2,output3; + CSG_MeshDescriptor m1, m2, output; + CSG_MeshDescriptor output2, output3; - if (!MakeCSGMeshFromBlenderBase(base,&m1)) { + if (!MakeCSGMeshFromBlenderBase(base, &m1)) { return 0; } - if (!MakeCSGMeshFromBlenderBase(base_select,&m2)) { + if (!MakeCSGMeshFromBlenderBase(base_select, &m2)) { return 0; } - CSG_PerformOp(&m1,&m2,1,&output); - CSG_PerformOp(&m1,&m2,2,&output2); - CSG_PerformOp(&m1,&m2,3,&output3); + CSG_PerformOp(&m1, &m2, 1, &output); + CSG_PerformOp(&m1, &m2, 2, &output2); + CSG_PerformOp(&m1, &m2, 3, &output3); if (!CSG_AddMeshToBlender(&output)) { return 0; diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 0d44f5cad6f..6db1052d6bd 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -603,8 +603,11 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int case ID_LI: { Library *lib = (Library *)id; - if (rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) { - BKE_library_filepath_set(lib, lib->name); + /* keep packedfile paths always relative to the blend */ + if (lib->packedfile == NULL) { + if (rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) { + BKE_library_filepath_set(lib, lib->name); + } } break; } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 405b1efb25d..aeb0407b37f 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -29,29 +29,16 @@ * \ingroup bke */ - -#include <math.h> -#include <string.h> - #include "MEM_guardedalloc.h" #include "DNA_brush_types.h" -#include "DNA_color_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" -#include "DNA_userdef_types.h" -#include "DNA_windowmanager_types.h" - -#include "WM_types.h" - -#include "RNA_access.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_rand.h" -#include "BLI_utildefines.h" -#include "BKE_blender.h" #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_global.h" @@ -66,7 +53,6 @@ #include "IMB_imbuf_types.h" #include "RE_render_ext.h" /* externtex */ -#include "RE_shader_ext.h" static void brush_defaults(Brush *brush) { @@ -696,7 +682,7 @@ float BKE_brush_unprojected_radius_get(const Scene *scene, Brush *brush) brush->unprojected_radius; } -static void brush_alpha_set(Scene *scene, Brush *brush, float alpha) +void BKE_brush_alpha_set(Scene *scene, Brush *brush, float alpha) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; @@ -754,315 +740,6 @@ void BKE_brush_scale_size(int *r_brush_size, (*r_brush_size) = (int)((float)(*r_brush_size) * scale); } -/* Brush Painting */ - -typedef struct BrushPainterCache { - short enabled; - - int size; /* size override, if 0 uses 2*BKE_brush_size_get(brush) */ - short flt; /* need float imbuf? */ - short texonly; /* no alpha, color or fallof, only texture in imbuf */ - - int lastsize; - float lastalpha; - float lastjitter; - - ImBuf *ibuf; - ImBuf *texibuf; - ImBuf *maskibuf; -} BrushPainterCache; - -struct BrushPainter { - Scene *scene; - Brush *brush; - - float lastmousepos[2]; /* mouse position of last paint call */ - - float accumdistance; /* accumulated distance of brush since last paint op */ - float lastpaintpos[2]; /* position of last paint op */ - float startpaintpos[2]; /* position of first paint */ - - double accumtime; /* accumulated time since last paint op (airbrush) */ - double lasttime; /* time of last update */ - - float lastpressure; - - short firsttouch; /* first paint op */ - - float startsize; - float startalpha; - float startjitter; - float startspacing; - - BrushPainterCache cache; -}; - -BrushPainter *BKE_brush_painter_new(Scene *scene, Brush *brush) -{ - BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter"); - - painter->brush = brush; - painter->scene = scene; - painter->firsttouch = 1; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ - - painter->startsize = BKE_brush_size_get(scene, brush); - painter->startalpha = BKE_brush_alpha_get(scene, brush); - painter->startjitter = brush->jitter; - painter->startspacing = brush->spacing; - - return painter; -} - -void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size) -{ - if ((painter->cache.flt != flt) || (painter->cache.size != size) || - ((painter->cache.texonly != texonly) && texonly)) - { - if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); - if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); - painter->cache.ibuf = painter->cache.maskibuf = NULL; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ - } - - if (painter->cache.flt != flt) { - if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); - painter->cache.texibuf = NULL; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ - } - - painter->cache.size = size; - painter->cache.flt = flt; - painter->cache.texonly = texonly; - painter->cache.enabled = 1; -} - -void BKE_brush_painter_free(BrushPainter *painter) -{ - Brush *brush = painter->brush; - - BKE_brush_size_set(painter->scene, brush, painter->startsize); - brush_alpha_set(painter->scene, brush, painter->startalpha); - brush->jitter = painter->startjitter; - brush->spacing = painter->startspacing; - - if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); - if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); - if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); - MEM_freeN(painter); -} - -static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, - int x, int y, int w, int h, int xt, int yt, - const float pos[2]) -{ - Scene *scene = painter->scene; - Brush *brush = painter->brush; - ImBuf *ibuf, *maskibuf, *texibuf; - float *bf, *mf, *tf, *otf = NULL, xoff, yoff, xy[2], rgba[4]; - unsigned char *b, *m, *t, *ot = NULL; - int dotexold, origx = x, origy = y; - const int radius = BKE_brush_size_get(painter->scene, brush); - - xoff = -radius + 0.5f; - yoff = -radius + 0.5f; - xoff += (int)pos[0] - (int)painter->startpaintpos[0]; - yoff += (int)pos[1] - (int)painter->startpaintpos[1]; - - ibuf = painter->cache.ibuf; - texibuf = painter->cache.texibuf; - maskibuf = painter->cache.maskibuf; - - dotexold = (oldtexibuf != NULL); - - /* not sure if it's actually needed or it's a mistake in coords/sizes - * calculation in brush_painter_fixed_tex_partial_update(), but without this - * limitation memory gets corrupted at fast strokes with quite big spacing (sergey) */ - w = min_ii(w, ibuf->x); - h = min_ii(h, ibuf->y); - - if (painter->cache.flt) { - for (; y < h; y++) { - bf = ibuf->rect_float + (y * ibuf->x + origx) * 4; - tf = texibuf->rect_float + (y * texibuf->x + origx) * 4; - mf = maskibuf->rect_float + (y * maskibuf->x + origx) * 4; - - if (dotexold) - otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + xt) * 4; - - for (x = origx; x < w; x++, bf += 4, mf += 4, tf += 4) { - if (dotexold) { - copy_v3_v3(tf, otf); - tf[3] = otf[3]; - otf += 4; - } - else { - xy[0] = x + xoff; - xy[1] = y + yoff; - - BKE_brush_sample_tex(scene, brush, xy, tf, 0); - } - - bf[0] = tf[0] * mf[0]; - bf[1] = tf[1] * mf[1]; - bf[2] = tf[2] * mf[2]; - bf[3] = tf[3] * mf[3]; - } - } - } - else { - for (; y < h; y++) { - b = (unsigned char *)ibuf->rect + (y * ibuf->x + origx) * 4; - t = (unsigned char *)texibuf->rect + (y * texibuf->x + origx) * 4; - m = (unsigned char *)maskibuf->rect + (y * maskibuf->x + origx) * 4; - - if (dotexold) - ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + xt) * 4; - - for (x = origx; x < w; x++, b += 4, m += 4, t += 4) { - if (dotexold) { - t[0] = ot[0]; - t[1] = ot[1]; - t[2] = ot[2]; - t[3] = ot[3]; - ot += 4; - } - else { - xy[0] = x + xoff; - xy[1] = y + yoff; - - BKE_brush_sample_tex(scene, brush, xy, rgba, 0); - rgba_float_to_uchar(t, rgba); - } - - b[0] = t[0] * m[0] / 255; - b[1] = t[1] * m[1] / 255; - b[2] = t[2] * m[2] / 255; - b[3] = t[3] * m[3] / 255; - } - } - } -} - -static void brush_painter_fixed_tex_partial_update(BrushPainter *painter, const float pos[2]) -{ - const Scene *scene = painter->scene; - Brush *brush = painter->brush; - BrushPainterCache *cache = &painter->cache; - ImBuf *oldtexibuf, *ibuf; - int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2; - const int diameter = 2 * BKE_brush_size_get(scene, brush); - - imbflag = (cache->flt) ? IB_rectfloat : IB_rect; - if (!cache->ibuf) - cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag); - ibuf = cache->ibuf; - - oldtexibuf = cache->texibuf; - cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag); - - if (oldtexibuf) { - srcx = srcy = 0; - destx = (int)painter->lastpaintpos[0] - (int)pos[0]; - desty = (int)painter->lastpaintpos[1] - (int)pos[1]; - w = oldtexibuf->x; - h = oldtexibuf->y; - - IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h); - } - else { - srcx = srcy = 0; - destx = desty = 0; - w = h = 0; - } - - x1 = destx; - y1 = desty; - x2 = destx + w; - y2 = desty + h; - - /* blend existing texture in new position */ - if ((x1 < x2) && (y1 < y2)) - brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos); - - if (oldtexibuf) - IMB_freeImBuf(oldtexibuf); - - /* sample texture in new areas */ - if ((0 < x1) && (0 < ibuf->y)) - brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos); - if ((x2 < ibuf->x) && (0 < ibuf->y)) - brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos); - if ((x1 < x2) && (0 < y1)) - brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos); - if ((x1 < x2) && (y2 < ibuf->y)) - brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos); -} - -static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction) -{ - const Scene *scene = painter->scene; - Brush *brush = painter->brush; - BrushPainterCache *cache = &painter->cache; - MTex *mtex = &brush->mtex; - int size; - short flt; - const int diameter = 2 * BKE_brush_size_get(scene, brush); - const float alpha = BKE_brush_alpha_get(scene, brush); - - if (diameter != cache->lastsize || - alpha != cache->lastalpha || - brush->jitter != cache->lastjitter) - { - if (cache->ibuf) { - IMB_freeImBuf(cache->ibuf); - cache->ibuf = NULL; - } - if (cache->maskibuf) { - IMB_freeImBuf(cache->maskibuf); - cache->maskibuf = NULL; - } - - flt = cache->flt; - size = (cache->size) ? cache->size : diameter; - - if (brush->flag & BRUSH_FIXED_TEX) { - BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction); - brush_painter_fixed_tex_partial_update(painter, pos); - } - else - BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction); - - cache->lastsize = diameter; - cache->lastalpha = alpha; - cache->lastjitter = brush->jitter; - } - else if ((brush->flag & BRUSH_FIXED_TEX) && mtex && mtex->tex) { - int dx = (int)painter->lastpaintpos[0] - (int)pos[0]; - int dy = (int)painter->lastpaintpos[1] - (int)pos[1]; - - if ((dx != 0) || (dy != 0)) - brush_painter_fixed_tex_partial_update(painter, pos); - } -} - -void BKE_brush_painter_break_stroke(BrushPainter *painter) -{ - painter->firsttouch = 1; -} - -static void brush_pressure_apply(BrushPainter *painter, Brush *brush, float pressure) -{ - if (BKE_brush_use_alpha_pressure(painter->scene, brush)) - brush_alpha_set(painter->scene, brush, max_ff(0.0f, painter->startalpha * pressure)); - if (BKE_brush_use_size_pressure(painter->scene, brush)) - BKE_brush_size_set(painter->scene, brush, max_ff(1.0f, painter->startsize * pressure)); - if (brush->flag & BRUSH_JITTER_PRESSURE) - brush->jitter = max_ff(0.0f, painter->startjitter * pressure); - if (brush->flag & BRUSH_SPACING_PRESSURE) - brush->spacing = max_ff(1.0f, painter->startspacing * (1.5f - pressure)); -} - void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], float jitterpos[2]) { int use_jitter = brush->jitter != 0; @@ -1090,165 +767,6 @@ void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], } } -int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float pos[2], double time, float pressure, - void *user, int use_color_correction) -{ - Scene *scene = painter->scene; - Brush *brush = painter->brush; - int totpaintops = 0; - - if (pressure == 0.0f) { - if (painter->lastpressure) // XXX - hack, operator misses - pressure = painter->lastpressure; - else - pressure = 1.0f; /* zero pressure == not using tablet */ - } - if (painter->firsttouch) { - /* paint exactly once on first touch */ - painter->startpaintpos[0] = pos[0]; - painter->startpaintpos[1] = pos[1]; - - brush_pressure_apply(painter, brush, pressure); - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, pos, use_color_correction); - totpaintops += func(user, painter->cache.ibuf, pos, pos); - - painter->lasttime = time; - painter->firsttouch = 0; - painter->lastpaintpos[0] = pos[0]; - painter->lastpaintpos[1] = pos[1]; - } -#if 0 - else if (painter->brush->flag & BRUSH_AIRBRUSH) { - float spacing, step, paintpos[2], dmousepos[2], len; - double starttime, curtime = time; - - /* compute brush spacing adapted to brush size */ - spacing = brush->rate; //radius*brush->spacing*0.01f; - - /* setup starting time, direction vector and accumulated time */ - starttime = painter->accumtime; - sub_v2_v2v2(dmousepos, pos, painter->lastmousepos); - len = normalize_v2(dmousepos); - painter->accumtime += curtime - painter->lasttime; - - /* do paint op over unpainted time distance */ - while (painter->accumtime >= spacing) { - step = (spacing - starttime) * len; - paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step; - paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step; - - if (painter->cache.enabled) - brush_painter_refresh_cache(painter); - totpaintops += func(user, painter->cache.ibuf, - painter->lastpaintpos, paintpos); - - painter->lastpaintpos[0] = paintpos[0]; - painter->lastpaintpos[1] = paintpos[1]; - painter->accumtime -= spacing; - starttime -= spacing; - } - - painter->lasttime = curtime; - } -#endif - else { - float startdistance, spacing, step, paintpos[2], dmousepos[2], finalpos[2]; - float t, len, press; - const int radius = BKE_brush_size_get(scene, brush); - - /* compute brush spacing adapted to brush radius, spacing may depend - * on pressure, so update it */ - brush_pressure_apply(painter, brush, painter->lastpressure); - spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f; - - /* setup starting distance, direction vector and accumulated distance */ - startdistance = painter->accumdistance; - sub_v2_v2v2(dmousepos, pos, painter->lastmousepos); - len = normalize_v2(dmousepos); - painter->accumdistance += len; - - if (brush->flag & BRUSH_SPACE) { - /* do paint op over unpainted distance */ - while ((len > 0.0f) && (painter->accumdistance >= spacing)) { - step = spacing - startdistance; - paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step; - paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step; - - t = step / len; - press = (1.0f - t) * painter->lastpressure + t * pressure; - brush_pressure_apply(painter, brush, press); - spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f; - - BKE_brush_jitter_pos(scene, brush, paintpos, finalpos); - - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos, use_color_correction); - - totpaintops += - func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos); - - painter->lastpaintpos[0] = paintpos[0]; - painter->lastpaintpos[1] = paintpos[1]; - painter->accumdistance -= spacing; - startdistance -= spacing; - } - } - else { - BKE_brush_jitter_pos(scene, brush, pos, finalpos); - - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos, use_color_correction); - - totpaintops += func(user, painter->cache.ibuf, pos, finalpos); - - painter->lastpaintpos[0] = pos[0]; - painter->lastpaintpos[1] = pos[1]; - painter->accumdistance = 0; - } - - /* do airbrush paint ops, based on the number of paint ops left over - * from regular painting. this is a temporary solution until we have - * accurate time stamps for mouse move events */ - if (brush->flag & BRUSH_AIRBRUSH) { - double curtime = time; - double painttime = brush->rate * totpaintops; - - painter->accumtime += curtime - painter->lasttime; - if (painter->accumtime <= painttime) - painter->accumtime = 0.0; - else - painter->accumtime -= painttime; - - while (painter->accumtime >= (double)brush->rate) { - brush_pressure_apply(painter, brush, pressure); - - BKE_brush_jitter_pos(scene, brush, pos, finalpos); - - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos, use_color_correction); - - totpaintops += - func(user, painter->cache.ibuf, painter->lastmousepos, finalpos); - painter->accumtime -= (double)brush->rate; - } - - painter->lasttime = curtime; - } - } - - painter->lastmousepos[0] = pos[0]; - painter->lastmousepos[1] = pos[1]; - painter->lastpressure = pressure; - - brush_alpha_set(scene, brush, painter->startalpha); - BKE_brush_size_set(scene, brush, painter->startsize); - brush->jitter = painter->startjitter; - brush->spacing = painter->startspacing; - - return totpaintops; -} - /* Uses the brush curve control to find a strength value between 0 and 1 */ float BKE_brush_curve_strength_clamp(Brush *br, float p, const float len) { @@ -1275,48 +793,6 @@ float BKE_brush_curve_strength(Brush *br, float p, const float len) return curvemapping_evaluateF(br->curve, 0, p); } -/* TODO: should probably be unified with BrushPainter stuff? */ -unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side) -{ - unsigned int *texcache = NULL; - MTex *mtex = &br->mtex; - TexResult texres = {0}; - int hasrgb, ix, iy; - int side = half_side * 2; - - if (mtex->tex) { - float x, y, step = 2.0 / side, co[3]; - - texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache"); - - /*do normalized cannonical view coords for texture*/ - for (y = -1.0, iy = 0; iy < side; iy++, y += step) { - for (x = -1.0, ix = 0; ix < side; ix++, x += step) { - co[0] = x; - co[1] = y; - co[2] = 0.0f; - - /* This is copied from displace modifier code */ - hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres); - - /* if the texture gave an RGB value, we assume it didn't give a valid - * intensity, so calculate one (formula from do_material_tex). - * if the texture didn't give an RGB value, copy the intensity across - */ - if (hasrgb & TEX_RGB) - texres.tin = rgb_to_grayscale(&texres.tr); - - ((char *)texcache)[(iy * side + ix) * 4] = - ((char *)texcache)[(iy * side + ix) * 4 + 1] = - ((char *)texcache)[(iy * side + ix) * 4 + 2] = - ((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(texres.tin * 255.0f); - } - } - } - - return texcache; -} - /**** Radial Control ****/ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br) { diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 61d0936d41d..51890851ebc 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -262,6 +262,17 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) cddm->pbvh_draw = can_pbvh_draw(ob, dm); } + /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH */ + if (!cddm->pbvh && ob->sculpt->bm) { + cddm->pbvh = BKE_pbvh_new(); + cddm->pbvh_draw = TRUE; + + BKE_pbvh_build_bmesh(cddm->pbvh, ob->sculpt->bm, + ob->sculpt->bm_smooth_shading, + ob->sculpt->bm_log); + } + + /* always build pbvh from original mesh, and only use it for drawing if * this derivedmesh is just original mesh. it's the multires subsurf dm * that this is actually for, to support a pbvh on a modified mesh */ @@ -270,14 +281,14 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) Mesh *me = ob->data; int deformed = 0; - cddm->pbvh = BLI_pbvh_new(); + cddm->pbvh = BKE_pbvh_new(); cddm->pbvh_draw = can_pbvh_draw(ob, dm); pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color); BKE_mesh_tessface_ensure(me); - BLI_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert, + BKE_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert, me->totface, me->totvert, &me->vdata); deformed = ss->modifiers_active || me->key; @@ -290,7 +301,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) totvert = deformdm->getNumVerts(deformdm); vertCos = MEM_callocN(3 * totvert * sizeof(float), "cdDM_getPBVH vertCos"); deformdm->getVertCos(deformdm, vertCos); - BLI_pbvh_apply_vertCos(cddm->pbvh, vertCos); + BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos); MEM_freeN(vertCos); } } @@ -310,7 +321,7 @@ static void cdDM_update_normals_from_pbvh(DerivedMesh *dm) face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL); - BLI_pbvh_update(cddm->pbvh, PBVH_UpdateNormals, face_nors); + BKE_pbvh_update(cddm->pbvh, PBVH_UpdateNormals, face_nors); } static void cdDM_drawVerts(DerivedMesh *dm) @@ -414,6 +425,14 @@ static void cdDM_drawEdges(DerivedMesh *dm, int drawLooseEdges, int drawAllEdges MVert *mvert = cddm->mvert; MEdge *medge = cddm->medge; int i; + + if (cddm->pbvh && cddm->pbvh_draw && + BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) + { + BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, TRUE); + + return; + } if (GPU_buffer_legacy(dm)) { DEBUG_VBO("Using legacy code. cdDM_drawEdges\n"); @@ -530,7 +549,8 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, if (dm->numTessFaceData) { float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL); - BLI_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, setMaterial); + BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, + setMaterial, FALSE); glShadeModel(GL_FLAT); } @@ -664,8 +684,9 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, } else { if (nors) { - nors += 3; continue; + nors += 3; } + continue; } } else if (drawParamsMapped) { @@ -673,8 +694,9 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, } else { if (nors) { - nors += 3; continue; + nors += 3; } + continue; } } diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index f1d73c7777a..fdd7dc94979 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -1153,7 +1153,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) if ( !mface[i].v4 ) continue; - spring = ( ClothSpring *) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); if (!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index f0043d9fa77..60bf67e19e3 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -528,7 +528,7 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned /* extend array */ if (*numobj >= *maxobj) { *maxobj *= 2; - *objs= MEM_reallocN(*objs, sizeof(Object*)*(*maxobj)); + *objs= MEM_reallocN(*objs, sizeof(Object *)*(*maxobj)); } (*objs)[*numobj] = ob; @@ -740,7 +740,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData * clmd, float step, flo /* move object to position (step) in time */ for (i = 0; i < numcollobj; i++) { Object *collob= collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData*)modifiers_findByType(collob, eModifierType_Collision); + CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); if (!collmd->bvhtree) continue; @@ -760,7 +760,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData * clmd, float step, flo // check all collision objects for (i = 0; i < numcollobj; i++) { Object *collob= collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData*)modifiers_findByType(collob, eModifierType_Collision); + CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); BVHTreeOverlap *overlap = NULL; unsigned int result = 0; diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index c3aab22fe5a..1a25def3829 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -96,7 +96,7 @@ /* -------------- Naming -------------- */ /* Find the first available, non-duplicate name for a given constraint */ -void unique_constraint_name(bConstraint *con, ListBase *list) +void BKE_unique_constraint_name(bConstraint *con, ListBase *list) { BLI_uniquename(list, con, "Const", '.', offsetof(bConstraint, name), sizeof(con->name)); } @@ -105,7 +105,7 @@ void unique_constraint_name(bConstraint *con, ListBase *list) /* package an object/bone for use in constraint evaluation */ /* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */ -bConstraintOb *constraints_make_evalob(Scene *scene, Object *ob, void *subdata, short datatype) +bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subdata, short datatype) { bConstraintOb *cob; @@ -169,7 +169,7 @@ bConstraintOb *constraints_make_evalob(Scene *scene, Object *ob, void *subdata, } /* cleanup after constraint evaluation */ -void constraints_clear_evalob(bConstraintOb *cob) +void BKE_constraints_clear_evalob(bConstraintOb *cob) { float delta[4][4], imat[4][4]; @@ -219,7 +219,7 @@ void constraints_clear_evalob(bConstraintOb *cob) * of a matrix from one space to another for constraint evaluation. * For now, this is only implemented for Objects and PoseChannels. */ -void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to) +void BKE_constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to) { float diff_mat[4][4]; float imat[4][4]; @@ -242,7 +242,7 @@ void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4 /* use pose-space as stepping stone for other spaces... */ if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) { /* call self with slightly different values */ - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); } } break; @@ -278,7 +278,7 @@ void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4 /* use pose-space as stepping stone for other spaces */ if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) { /* call self with slightly different values */ - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); } } break; @@ -293,7 +293,7 @@ void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4 /* use pose-space as stepping stone for other spaces */ if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) { /* call self with slightly different values */ - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); } } break; @@ -499,7 +499,7 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m /* Case OBJECT */ if (!strlen(substring)) { copy_m4_m4(mat, ob->obmat); - constraint_mat_convertspace(ob, NULL, mat, from, to); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); } /* Case VERTEXGROUP */ /* Current method just takes the average location of all the points in the @@ -512,11 +512,11 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m */ else if (ob->type == OB_MESH) { contarget_get_mesh_mat(ob, substring, mat); - constraint_mat_convertspace(ob, NULL, mat, from, to); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); } else if (ob->type == OB_LATTICE) { contarget_get_lattice_mat(ob, substring, mat); - constraint_mat_convertspace(ob, NULL, mat, from, to); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); } /* Case BONE */ else { @@ -549,7 +549,7 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m copy_m4_m4(mat, ob->obmat); /* convert matrix space as required */ - constraint_mat_convertspace(ob, pchan, mat, from, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, from, to); } } @@ -4211,7 +4211,7 @@ static void constraints_init_typeinfo(void) /* This function should be used for getting the appropriate type-info when only * a constraint type is known */ -bConstraintTypeInfo *get_constraint_typeinfo(int type) +bConstraintTypeInfo *BKE_get_constraint_typeinfo(int type) { /* initialize the type-info list? */ if (CTI_INIT) { @@ -4236,11 +4236,11 @@ bConstraintTypeInfo *get_constraint_typeinfo(int type) /* This function should always be used to get the appropriate type-info, as it * has checks which prevent segfaults in some weird cases. */ -bConstraintTypeInfo *constraint_get_typeinfo(bConstraint *con) +bConstraintTypeInfo *BKE_constraint_get_typeinfo(bConstraint *con) { /* only return typeinfo for valid constraints */ if (con) - return get_constraint_typeinfo(con->type); + return BKE_get_constraint_typeinfo(con->type); else return NULL; } @@ -4252,7 +4252,7 @@ bConstraintTypeInfo *constraint_get_typeinfo(bConstraint *con) /* ---------- Data Management ------- */ -/* helper function for free_constraint_data() - unlinks references */ +/* helper function for BKE_free_constraint_data() - unlinks references */ static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, short isReference, void *UNUSED(userData)) { if (*idpoin && isReference) @@ -4263,10 +4263,10 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, short isRe * be sure to run BIK_clear_data() when freeing an IK constraint, * unless DAG_scene_sort is called. */ -void free_constraint_data(bConstraint *con) +void BKE_free_constraint_data(bConstraint *con) { if (con->data) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (cti) { /* perform any special freeing constraint may have */ @@ -4284,13 +4284,13 @@ void free_constraint_data(bConstraint *con) } /* Free all constraints from a constraint-stack */ -void free_constraints(ListBase *list) +void BKE_free_constraints(ListBase *list) { bConstraint *con; /* Free constraint data and also any extra data */ for (con = list->first; con; con = con->next) - free_constraint_data(con); + BKE_free_constraint_data(con); /* Free the whole list */ BLI_freelistN(list); @@ -4298,10 +4298,10 @@ void free_constraints(ListBase *list) /* Remove the specified constraint from the given constraint stack */ -int remove_constraint(ListBase *list, bConstraint *con) +int BKE_remove_constraint(ListBase *list, bConstraint *con) { if (con) { - free_constraint_data(con); + BKE_free_constraint_data(con); BLI_freelinkN(list, con); return 1; } @@ -4310,7 +4310,7 @@ int remove_constraint(ListBase *list, bConstraint *con) } /* Remove all the constraints of the specified type from the given constraint stack */ -void remove_constraints_type(ListBase *list, short type, short last_only) +void BKE_remove_constraints_type(ListBase *list, short type, short last_only) { bConstraint *con, *conp; @@ -4322,7 +4322,7 @@ void remove_constraints_type(ListBase *list, short type, short last_only) conp = con->prev; if (con->type == type) { - remove_constraint(list, con); + BKE_remove_constraint(list, con); if (last_only) return; } @@ -4335,7 +4335,7 @@ void remove_constraints_type(ListBase *list, short type, short last_only) static bConstraint *add_new_constraint_internal(const char *name, short type) { bConstraint *con = MEM_callocN(sizeof(bConstraint), "Constraint"); - bConstraintTypeInfo *cti = get_constraint_typeinfo(type); + bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(type); const char *newName; /* Set up a generic constraint datablock */ @@ -4385,17 +4385,17 @@ static bConstraint *add_new_constraint(Object *ob, bPoseChannel *pchan, const ch * (otherwise unique-naming code will fail, since it assumes element exists in list) */ BLI_addtail(list, con); - unique_constraint_name(con, list); + BKE_unique_constraint_name(con, list); /* if the target list is a list on some PoseChannel belonging to a proxy-protected * Armature layer, we must tag newly added constraints with a flag which allows them * to persist after proxy syncing has been done */ - if (proxylocked_constraints_owner(ob, pchan)) + if (BKE_proxylocked_constraints_owner(ob, pchan)) con->flag |= CONSTRAINT_PROXY_LOCAL; /* make this constraint the active one */ - constraints_set_active(list, con); + BKE_constraints_set_active(list, con); } /* set type+owner specific immutable settings */ @@ -4419,7 +4419,7 @@ static bConstraint *add_new_constraint(Object *ob, bPoseChannel *pchan, const ch /* ......... */ /* Add new constraint for the given bone */ -bConstraint *add_pose_constraint(Object *ob, bPoseChannel *pchan, const char *name, short type) +bConstraint *BKE_add_pose_constraint(Object *ob, bPoseChannel *pchan, const char *name, short type) { if (pchan == NULL) return NULL; @@ -4428,14 +4428,14 @@ bConstraint *add_pose_constraint(Object *ob, bPoseChannel *pchan, const char *na } /* Add new constraint for the given object */ -bConstraint *add_ob_constraint(Object *ob, const char *name, short type) +bConstraint *BKE_add_ob_constraint(Object *ob, const char *name, short type) { return add_new_constraint(ob, NULL, name, type); } /* ......... */ -/* helper for relink_constraints() - call ID_NEW() on every ID reference the constraint has */ +/* helper for BKE_relink_constraints() - call ID_NEW() on every ID reference the constraint has */ static void con_relink_id_cb(bConstraint *UNUSED(con), ID **idpoin, short UNUSED(isReference), void *UNUSED(userdata)) { /* ID_NEW() expects a struct with inline "id" member as first @@ -4449,20 +4449,20 @@ static void con_relink_id_cb(bConstraint *UNUSED(con), ID **idpoin, short UNUSED } /* Reassign links that constraints have to other data (called during file loading?) */ -void relink_constraints(ListBase *conlist) +void BKE_relink_constraints(ListBase *conlist) { /* just a wrapper around ID-loop for just calling ID_NEW() on all ID refs */ - id_loop_constraints(conlist, con_relink_id_cb, NULL); + BKE_id_loop_constraints(conlist, con_relink_id_cb, NULL); } /* Run the given callback on all ID-blocks in list of constraints */ -void id_loop_constraints(ListBase *conlist, ConstraintIDFunc func, void *userdata) +void BKE_id_loop_constraints(ListBase *conlist, ConstraintIDFunc func, void *userdata) { bConstraint *con; for (con = conlist->first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (cti) { if (cti->id_looper) @@ -4473,14 +4473,14 @@ void id_loop_constraints(ListBase *conlist, ConstraintIDFunc func, void *userdat /* ......... */ -/* helper for copy_constraints(), to be used for making sure that ID's are valid */ +/* helper for BKE_copy_constraints(), to be used for making sure that ID's are valid */ static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, short UNUSED(isReference), void *UNUSED(userData)) { if (*idpoin && (*idpoin)->lib) id_lib_extern(*idpoin); } -/* helper for copy_constraints(), to be used for making sure that usercounts of copied ID's are fixed up */ +/* helper for BKE_copy_constraints(), to be used for making sure that usercounts of copied ID's are fixed up */ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, short isReference, void *UNUSED(userData)) { /* increment usercount if this is a reference type */ @@ -4489,7 +4489,7 @@ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, short } /* duplicate all of the constraints in a constraint stack */ -void copy_constraints(ListBase *dst, const ListBase *src, int do_extern) +void BKE_copy_constraints(ListBase *dst, const ListBase *src, int do_extern) { bConstraint *con, *srccon; @@ -4497,7 +4497,7 @@ void copy_constraints(ListBase *dst, const ListBase *src, int do_extern) BLI_duplicatelist(dst, src); for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); /* make a new copy of the constraint's data */ con->data = MEM_dupallocN(con->data); @@ -4524,13 +4524,13 @@ void copy_constraints(ListBase *dst, const ListBase *src, int do_extern) /* ......... */ -bConstraint *constraints_findByName(ListBase *list, const char *name) +bConstraint *BKE_constraints_findByName(ListBase *list, const char *name) { return BLI_findstring(list, name, offsetof(bConstraint, name)); } /* finds the 'active' constraint in a constraint stack */ -bConstraint *constraints_get_active(ListBase *list) +bConstraint *BKE_constraints_get_active(ListBase *list) { bConstraint *con; @@ -4547,7 +4547,7 @@ bConstraint *constraints_get_active(ListBase *list) } /* Set the given constraint as the active one (clearing all the others) */ -void constraints_set_active(ListBase *list, bConstraint *con) +void BKE_constraints_set_active(ListBase *list, bConstraint *con) { bConstraint *c; @@ -4564,7 +4564,7 @@ void constraints_set_active(ListBase *list, bConstraint *con) /* -------- Constraints and Proxies ------- */ /* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL (i.e. added to bone that's proxy-synced in this file) */ -void extract_proxylocal_constraints(ListBase *dst, ListBase *src) +void BKE_extract_proxylocal_constraints(ListBase *dst, ListBase *src) { bConstraint *con, *next; @@ -4581,7 +4581,7 @@ void extract_proxylocal_constraints(ListBase *dst, ListBase *src) } /* Returns if the owner of the constraint is proxy-protected */ -short proxylocked_constraints_owner(Object *ob, bPoseChannel *pchan) +short BKE_proxylocked_constraints_owner(Object *ob, bPoseChannel *pchan) { /* Currently, constraints can only be on object or bone level */ if (ob && ob->proxy) { @@ -4610,9 +4610,9 @@ short proxylocked_constraints_owner(Object *ob, bPoseChannel *pchan) * None of the actual calculations of the matrices should be done here! Also, this function is * not to be used by any new constraints, particularly any that have multiple targets. */ -void get_constraint_target_matrix(struct Scene *scene, bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime) +void BKE_get_constraint_target_matrix(Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintOb *cob; bConstraintTarget *ct; @@ -4657,10 +4657,8 @@ void get_constraint_target_matrix(struct Scene *scene, bConstraint *con, int n, cti->get_constraint_targets(con, &targets); /* only calculate the target matrix on the first target */ - ct = (bConstraintTarget *)targets.first; - while (ct && n-- > 0) - ct = ct->next; - + ct = (bConstraintTarget *)BLI_findlink(&targets, index); + if (ct) { if (cti->get_target_matrix) cti->get_target_matrix(con, cob, ct, ctime); @@ -4679,9 +4677,9 @@ void get_constraint_target_matrix(struct Scene *scene, bConstraint *con, int n, } /* Get the list of targets required for solving a constraint */ -void get_constraint_targets_for_solving(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime) +void BKE_get_constraint_targets_for_solving(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (cti && cti->get_constraint_targets) { bConstraintTarget *ct; @@ -4711,10 +4709,10 @@ void get_constraint_targets_for_solving(bConstraint *con, bConstraintOb *cob, Li /* This function is called whenever constraints need to be evaluated. Currently, all * constraints that can be evaluated are everytime this gets run. * - * constraints_make_evalob and constraints_clear_evalob should be called before and + * BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and * after running this function, to sort out cob */ -void solve_constraints(ListBase *conlist, bConstraintOb *cob, float ctime) +void BKE_solve_constraints(ListBase *conlist, bConstraintOb *cob, float ctime) { bConstraint *con; float oldmat[4][4]; @@ -4726,7 +4724,7 @@ void solve_constraints(ListBase *conlist, bConstraintOb *cob, float ctime) /* loop over available constraints, solving and blending them */ for (con = conlist->first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; /* these we can skip completely (invalid constraints...) */ @@ -4746,10 +4744,10 @@ void solve_constraints(ListBase *conlist, bConstraintOb *cob, float ctime) copy_m4_m4(oldmat, cob->matrix); /* move owner matrix into right space */ - constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); + BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); /* prepare targets for constraint solving */ - get_constraint_targets_for_solving(con, cob, &targets, ctime); + BKE_get_constraint_targets_for_solving(con, cob, &targets, ctime); /* Solve the constraint and put result in cob->matrix */ cti->evaluate_constraint(con, cob, &targets); @@ -4764,7 +4762,7 @@ void solve_constraints(ListBase *conlist, bConstraintOb *cob, float ctime) /* move owner back into worldspace for next constraint/other business */ if ((con->flag & CONSTRAINT_SPACEONCE) == 0) - constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD); + BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD); /* Interpolate the enforcement, to blend result of constraint into final owner transform * - all this happens in worldspace to prevent any weirdness creeping in ([#26014] and [#25725]), diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 7009f1235c9..a45afa5e69a 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -29,6 +29,7 @@ #include <string.h> +#include <stdlib.h> #include <stddef.h> #include "MEM_guardedalloc.h" @@ -327,10 +328,13 @@ static void *ctx_data_pointer_get(const bContext *C, const char *member) { bContextDataResult result; - if (C && ctx_data_get((bContext *)C, member, &result) == 1) + if (C && ctx_data_get((bContext *)C, member, &result) == 1) { + BLI_assert(result.type == CTX_DATA_TYPE_POINTER); return result.ptr.data; - - return NULL; + } + else { + return NULL; + } } static int ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer) @@ -343,6 +347,7 @@ static int ctx_data_pointer_verify(const bContext *C, const char *member, void * return 1; } else if (ctx_data_get((bContext *)C, member, &result) == 1) { + BLI_assert(result.type == CTX_DATA_TYPE_POINTER); *pointer = result.ptr.data; return 1; } @@ -357,6 +362,7 @@ static int ctx_data_collection_get(const bContext *C, const char *member, ListBa bContextDataResult result; if (ctx_data_get((bContext *)C, member, &result) == 1) { + BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION); *list = result.list; return 1; } @@ -371,10 +377,13 @@ PointerRNA CTX_data_pointer_get(const bContext *C, const char *member) { bContextDataResult result; - if (ctx_data_get((bContext *)C, member, &result) == 1) + if (ctx_data_get((bContext *)C, member, &result) == 1) { + BLI_assert(result.type == CTX_DATA_TYPE_POINTER); return result.ptr; - else + } + else { return PointerRNA_NULL; + } } PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type) @@ -399,6 +408,7 @@ ListBase CTX_data_collection_get(const bContext *C, const char *member) bContextDataResult result; if (ctx_data_get((bContext *)C, member, &result) == 1) { + BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION); return result.list; } else { diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 7c13ca388e0..cea92d53916 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -34,6 +34,7 @@ #include <math.h> #include <ctype.h> #include <stdlib.h> +#include <stddef.h> #include "MEM_guardedalloc.h" @@ -337,37 +338,12 @@ void defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int flip bDeformGroup *defgroup_find_name(Object *ob, const char *name) { - /* return a pointer to the deform group with this name - * or return NULL otherwise. - */ - bDeformGroup *curdef; - - for (curdef = ob->defbase.first; curdef; curdef = curdef->next) { - if (!strcmp(curdef->name, name)) { - return curdef; - } - } - return NULL; + return BLI_findstring(&ob->defbase, name, offsetof(bDeformGroup, name)); } int defgroup_name_index(Object *ob, const char *name) { - /* Return the location of the named deform group within the list of - * deform groups. This function is a combination of BLI_findlink and - * defgroup_find_name. The other two could be called instead, but that - * require looping over the vertexgroups twice. - */ - bDeformGroup *curdef; - int def_nr; - - if (name && name[0] != '\0') { - for (curdef = ob->defbase.first, def_nr = 0; curdef; curdef = curdef->next, def_nr++) { - if (!strcmp(curdef->name, name)) - return def_nr; - } - } - - return -1; + return (name) ? BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)) : -1; } /* note, must be freed */ @@ -810,3 +786,43 @@ int defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert_b) return -1; } + +/* -------------------------------------------------------------------- */ +/* Defvert Array functions */ + +void BKE_defvert_array_copy(MDeformVert *dst, const MDeformVert *src, int copycount) +{ + /* Assumes dst is already set up */ + int i; + + if (!src || !dst) + return; + + memcpy(dst, src, copycount * sizeof(MDeformVert)); + + for (i = 0; i < copycount; i++) { + if (src[i].dw) { + dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * src[i].totweight, "copy_deformWeight"); + memcpy(dst[i].dw, src[i].dw, sizeof(MDeformWeight) * src[i].totweight); + } + } + +} + +void BKE_defvert_array_free(MDeformVert *dvert, int totvert) +{ + /* Instead of freeing the verts directly, + * call this function to delete any special + * vert data */ + int i; + + if (!dvert) + return; + + /* Free any special data from the verts */ + for (i = 0; i < totvert; i++) { + if (dvert[i].dw) MEM_freeN(dvert[i].dw); + } + MEM_freeN(dvert); +} + diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 6ba140fcec1..42389564ec0 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -472,7 +472,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -754,7 +754,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O /* object constraints */ for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -2295,7 +2295,7 @@ static void dag_object_time_update_flags(Object *ob) if (ob->constraints.first) { bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -2738,7 +2738,7 @@ static void dag_id_flush_update(Scene *sce, ID *id) for (obt = bmain->object.first; obt; obt = obt->id.next) { bConstraint *con; for (con = obt->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { @@ -3030,7 +3030,7 @@ void DAG_pose_sort(Object *ob) addtoroot = 0; } for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 083cb02fd3d..71e9daaee6b 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -225,29 +225,48 @@ void BKE_displist_normals_add(ListBase *lb) } } -void BKE_displist_count(ListBase *lb, int *totvert, int *totface) +void BKE_displist_count(ListBase *lb, int *totvert, int *totface, int *tottri) { DispList *dl; - dl = lb->first; - while (dl) { + for (dl = lb->first; dl; dl = dl->next) { + int vert_tot = 0; + int face_tot = 0; + int tri_tot = 0; + switch (dl->type) { case DL_SURF: - *totvert += dl->nr * dl->parts; - *totface += (dl->nr - 1) * (dl->parts - 1); + { + vert_tot = dl->nr * dl->parts; + face_tot = (dl->nr - 1) * (dl->parts - 1); + tri_tot = face_tot * 2; break; + } case DL_INDEX3: + { + vert_tot = dl->nr; + face_tot = dl->parts; + tri_tot = face_tot; + break; + } case DL_INDEX4: - *totvert += dl->nr; - *totface += dl->parts; + { + vert_tot = dl->nr; + face_tot = dl->parts; + tri_tot = face_tot * 2; break; + } case DL_POLY: case DL_SEGM: - *totvert += dl->nr * dl->parts; + { + vert_tot = dl->nr * dl->parts; break; + } } - dl = dl->next; + *totvert += vert_tot; + *totface += face_tot; + *tottri += tri_tot; } } @@ -487,7 +506,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, int flipnormal) } /* XXX (obedit && obedit->actcol)?(obedit->actcol-1):0)) { */ - if (totvert && (tot = BLI_scanfill_calc(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES))) { + if (totvert && (tot = BLI_scanfill_calc(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES | BLI_SCANFILL_CALC_HOLES))) { if (tot) { dlnew = MEM_callocN(sizeof(DispList), "filldisplist"); dlnew->type = DL_INDEX3; @@ -780,7 +799,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, fl required_mode |= eModifierMode_Editmode; if (cu->editnurb == NULL) { - keyVerts = do_ob_key(scene, ob); + keyVerts = BKE_key_evaluate_object(scene, ob, &numVerts); if (keyVerts) { /* split coords from key data, the latter also includes @@ -789,7 +808,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, fl * shape key modifier yet. */ deformedVerts = BKE_curve_keyVertexCos_get(cu, nurb, keyVerts); originalVerts = MEM_dupallocN(deformedVerts); - numVerts = BKE_nurbList_verts_count(nurb); + BLI_assert(BKE_nurbList_verts_count(nurb) == numVerts); } } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index e32f8d53b7d..fff51ab2a59 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -529,7 +529,7 @@ static int subframe_updateObject(Scene *scene, Object *ob, int flags, float fram /* also update constraint targets */ for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; if (cti && cti->get_constraint_targets) { @@ -2689,7 +2689,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam if (format == R_IMF_IMTYPE_OPENEXR) format = R_IMF_IMTYPE_PNG; #endif BLI_strncpy(output_file, filename, sizeof(output_file)); - BKE_add_image_extension(output_file, format); + BKE_add_image_extension_from_type(output_file, format); /* Validate output file path */ BLI_path_abs(output_file, G.main->name); @@ -2839,7 +2839,9 @@ static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats) /* * Get material diffuse color and alpha (including linked textures) in given coordinates */ -static void dynamicPaint_doMaterialTex(BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb, const float volume_co[3], const float surface_co[3], int faceIndex, short isQuad, DerivedMesh *orcoDm) +static void dynamicPaint_doMaterialTex(BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb, + const float volume_co[3], const float surface_co[3], + int faceIndex, short isQuad, DerivedMesh *orcoDm) { Material *mat = bMats->mat; MFace *mface = orcoDm->getTessFaceArray(orcoDm); diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 480ff23f100..1c43b418a1c 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -113,8 +113,13 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) #define USE_TESSFACE_SPEEDUP BMesh *bm = em->bm; - BMLoop *(*looptris)[3] = NULL; - BLI_array_declare(looptris); + + /* this assumes all faces can be scan-filled, which isn't always true, + * worst case we over alloc a little which is acceptable */ + const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); + const int looptris_tot_prev_alloc = em->looptris ? (MEM_allocN_len(em->looptris) / sizeof(*em->looptris)) : 0; + + BMLoop *(*looptris)[3]; BMIter iter; BMFace *efa; BMLoop *l; @@ -135,17 +140,16 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) #else /* this means no reallocs for quad dominant models, for */ - if ( (em->looptris != NULL) && - (em->tottri != 0) && - /* (totrti <= bm->totface * 2) would be fine for all quads, - * but in case there are some ngons, still re-use the array */ - (em->tottri <= bm->totface * 3)) + if ((em->looptris != NULL) && + /* (em->tottri >= looptris_tot)) */ + /* check against alloc'd size incase we over alloc'd a little */ + ((looptris_tot_prev_alloc >= looptris_tot) && (looptris_tot_prev_alloc <= looptris_tot * 2))) { looptris = em->looptris; } else { if (em->looptris) MEM_freeN(em->looptris); - BLI_array_reserve(looptris, bm->totface); + looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__); } #endif @@ -163,20 +167,16 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) else if (efa->len == 3) { #if 0 int j; - BLI_array_grow_one(looptris); BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, j) { looptris[i][j] = l; } i += 1; #else /* more cryptic but faster */ - BLI_array_grow_one(looptris); - { - BMLoop **l_ptr = looptris[i++]; - l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa); - l_ptr[1] = l = l->next; - l_ptr[2] = l->next; - } + BMLoop **l_ptr = looptris[i++]; + l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa); + l_ptr[1] = l = l->next; + l_ptr[2] = l->next; #endif } else if (efa->len == 4) { @@ -199,15 +199,12 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) i += 1; #else /* more cryptic but faster */ - BLI_array_grow_items(looptris, 2); - { - BMLoop **l_ptr_a = looptris[i++]; - BMLoop **l_ptr_b = looptris[i++]; - (l_ptr_a[0] = l_ptr_b[0] = l = BM_FACE_FIRST_LOOP(efa)); - (l_ptr_a[1] = l = l->next); - (l_ptr_a[2] = l_ptr_b[1] = l = l->next); - ( l_ptr_b[2] = l->next); - } + BMLoop **l_ptr_a = looptris[i++]; + BMLoop **l_ptr_b = looptris[i++]; + (l_ptr_a[0] = l_ptr_b[0] = l = BM_FACE_FIRST_LOOP(efa)); + (l_ptr_a[1] = l = l->next); + (l_ptr_a[2] = l_ptr_b[1] = l = l->next); + ( l_ptr_b[2] = l->next); #endif } @@ -250,9 +247,10 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) BLI_scanfill_edge_add(&sf_ctx, sf_vert_first, sf_vert); totfilltri = BLI_scanfill_calc_ex(&sf_ctx, 0, efa->no); - BLI_array_grow_items(looptris, totfilltri); + BLI_assert(totfilltri <= efa->len - 2); for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { + BMLoop **l_ptr = looptris[i++]; BMLoop *l1 = sf_tri->v1->tmp.p; BMLoop *l2 = sf_tri->v2->tmp.p; BMLoop *l3 = sf_tri->v3->tmp.p; @@ -261,10 +259,9 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) if (BM_elem_index_get(l2) > BM_elem_index_get(l3)) { SWAP(BMLoop *, l2, l3); } if (BM_elem_index_get(l1) > BM_elem_index_get(l2)) { SWAP(BMLoop *, l1, l2); } - looptris[i][0] = l1; - looptris[i][1] = l2; - looptris[i][2] = l3; - i += 1; + l_ptr[0] = l1; + l_ptr[1] = l2; + l_ptr[2] = l3; } BLI_scanfill_end(&sf_ctx); @@ -274,6 +271,8 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) em->tottri = i; em->looptris = looptris; + BLI_assert(em->tottri <= looptris_tot); + #undef USE_TESSFACE_SPEEDUP } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 5e01773cab9..23f3a3ad3fd 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -859,7 +859,7 @@ void testhandles_fcurve(FCurve *fcu, const short use_handle) short flag = 0; /* flag is initialized as selection status - * of beztriple control-points (labelled 0,1,2) + * of beztriple control-points (labelled 0, 1, 2) */ if (bezt->f2 & SELECT) flag |= (1 << 1); // == 2 if (use_handle == FALSE) { @@ -1192,7 +1192,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) /* extract transform just like how the constraints do it! */ copy_m4_m4(mat, pchan->pose_mat); - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); /* ... and from that, we get our transform */ copy_v3_v3(tmp_loc, mat[3]); @@ -1217,7 +1217,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) /* extract transform just like how the constraints do it! */ copy_m4_m4(mat, ob->obmat); - constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); /* ... and from that, we get our transform */ copy_v3_v3(tmp_loc, mat[3]); @@ -1288,7 +1288,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { /* just like how the constraints do it! */ copy_m4_m4(mat, pchan->pose_mat); - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); } else { /* specially calculate local matrix, since chan_mat is not valid @@ -1315,7 +1315,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { /* just like how the constraints do it! */ copy_m4_m4(mat, ob->obmat); - constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); } else { /* transforms to matrix */ @@ -2022,12 +2022,12 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime } else { /* bezier interpolation */ - /* v1,v2 are the first keyframe and its 2nd handle */ + /* (v1, v2) are the first keyframe and its 2nd handle */ v1[0] = prevbezt->vec[1][0]; v1[1] = prevbezt->vec[1][1]; v2[0] = prevbezt->vec[2][0]; v2[1] = prevbezt->vec[2][1]; - /* v3,v4 are the last keyframe's 1st handle + the last keyframe */ + /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ v3[0] = bezt->vec[0][0]; v3[1] = bezt->vec[0][1]; v4[0] = bezt->vec[1][0]; diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 5dd0f08dc71..3be47668fb5 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -815,6 +815,13 @@ void IDP_FreeProperty(IDProperty *prop) } } +void IDP_ClearProperty(IDProperty *prop) +{ + IDP_FreeProperty(prop); + prop->data.pointer = NULL; + prop->len = prop->totallen = 0; +} + /* Unlinks any IDProperty<->ID linkage that might be going on. * note: currently unused.*/ void IDP_UnlinkProperty(IDProperty *prop) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f3cdf11d664..dbc423f98b3 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -312,10 +312,6 @@ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame) break; ibuf->index = index; - if (ima->flag & IMA_CM_PREDIVIDE) - ibuf->flags |= IB_cm_predivide; - else - ibuf->flags &= ~IB_cm_predivide; /* this function accepts (link == NULL) */ BLI_insertlinkbefore(&ima->ibufs, link, ibuf); @@ -552,6 +548,26 @@ int BKE_image_scale(Image *image, int width, int height) return (ibuf != NULL); } +static void image_init_color_management(Image *ima) +{ + ImBuf *ibuf; + char name[FILE_MAX]; + + BKE_image_user_file_path(NULL, ima, name); + + /* will set input color space to image format default's */ + ibuf = IMB_loadiffname(name, IB_test | IB_alphamode_detect, ima->colorspace_settings.name); + + if (ibuf) { + if (ibuf->flags & IB_alphamode_premul) + ima->alpha_mode = IMA_ALPHA_PREMUL; + else + ima->alpha_mode = IMA_ALPHA_STRAIGHT; + + IMB_freeImBuf(ibuf); + } +} + Image *BKE_image_load(const char *filepath) { Image *ima; @@ -579,6 +595,8 @@ Image *BKE_image_load(const char *filepath) if (BLI_testextensie_array(filepath, imb_ext_movie)) ima->source = IMA_SRC_MOVIE; + image_init_color_management(ima); + return ima; } @@ -666,7 +684,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char /* both byte and float buffers are filling in sRGB space, need to linearize float buffer after BKE_image_buf_fill* functions */ IMB_buffer_float_from_float(rect_float, rect_float, ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB, - ibuf->flags & IB_cm_predivide, ibuf->x, ibuf->y, ibuf->x, ibuf->x); + TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); } return ibuf; @@ -1119,6 +1137,8 @@ char BKE_imtype_valid_depths(const char imtype) return R_IMF_CHAN_DEPTH_10; case R_IMF_IMTYPE_JP2: return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16; + case R_IMF_IMTYPE_PNG: + return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16; /* most formats are 8bit only */ default: return R_IMF_CHAN_DEPTH_8; @@ -1165,9 +1185,10 @@ char BKE_imtype_from_arg(const char *imtype_arg) else return R_IMF_IMTYPE_INVALID; } -int BKE_add_image_extension(char *string, const char imtype) +static int do_add_image_extension(char *string, const char imtype, const ImageFormatData *im_format) { const char *extension = NULL; + (void)im_format; /* may be unused, depends on build options */ if (imtype == R_IMF_IMTYPE_IRIS) { if (!BLI_testextensie(string, ".rgb")) @@ -1232,8 +1253,22 @@ int BKE_add_image_extension(char *string, const char imtype) } #ifdef WITH_OPENJPEG else if (imtype == R_IMF_IMTYPE_JP2) { - if (!BLI_testextensie(string, ".jp2")) - extension = ".jp2"; + if (im_format) { + if (im_format->jp2_codec == R_IMF_JP2_CODEC_JP2) { + if (!BLI_testextensie(string, ".jp2")) + extension = ".jp2"; + } + else if (im_format->jp2_codec == R_IMF_JP2_CODEC_J2K) { + if (!BLI_testextensie(string, ".j2c")) + extension = ".j2c"; + } + else + BLI_assert(!"Unsupported jp2 codec was specified in im_format->jp2_codec"); + } + else { + if (!BLI_testextensie(string, ".jp2")) + extension = ".jp2"; + } } #endif else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90, R_IMF_IMTYPE_QUICKTIME etc @@ -1259,11 +1294,22 @@ int BKE_add_image_extension(char *string, const char imtype) } } +int BKE_add_image_extension(char *string, const ImageFormatData *im_format) +{ + return do_add_image_extension(string, im_format->imtype, im_format); +} + +int BKE_add_image_extension_from_type(char *string, const char imtype) +{ + return do_add_image_extension(string, imtype, NULL); +} + void BKE_imformat_defaults(ImageFormatData *im_format) { memset(im_format, 0, sizeof(*im_format)); im_format->planes = R_IMF_PLANES_RGB; im_format->imtype = R_IMF_IMTYPE_PNG; + im_format->depth = R_IMF_CHAN_DEPTH_8; im_format->quality = 90; im_format->compress = 90; @@ -1288,9 +1334,13 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i im_format->imtype = R_IMF_IMTYPE_RADHDR; #endif - else if (ftype == PNG) + else if (ftype == PNG) { im_format->imtype = R_IMF_IMTYPE_PNG; + if (custom_flags & PNG_16BIT) + im_format->depth = R_IMF_CHAN_DEPTH_16; + } + #ifdef WITH_DDS else if (ftype == DDS) im_format->imtype = R_IMF_IMTYPE_DDS; @@ -1351,6 +1401,13 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i if (ftype & JP2_CINE_48FPS) im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_48; } + + if (ftype & JP2_JP2) + im_format->jp2_codec = R_IMF_JP2_CODEC_JP2; + else if (ftype & JP2_J2K) + im_format->jp2_codec = R_IMF_JP2_CODEC_J2K; + else + BLI_assert(!"Unsupported jp2 codec was specified in file type"); } #endif @@ -1815,8 +1872,12 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf) else if (ELEM5(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) { ibuf->ftype = PNG; - if (imtype == R_IMF_IMTYPE_PNG) + if (imtype == R_IMF_IMTYPE_PNG) { + if (imf->depth == R_IMF_CHAN_DEPTH_16) + ibuf->ftype |= PNG_16BIT; + ibuf->ftype |= compress; + } } #ifdef WITH_DDS @@ -1906,6 +1967,13 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf) if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_48) ibuf->ftype |= JP2_CINE_48FPS; } + + if (imf->jp2_codec == R_IMF_JP2_CODEC_JP2) + ibuf->ftype |= JP2_JP2; + else if (imf->jp2_codec == R_IMF_JP2_CODEC_J2K) + ibuf->ftype |= JP2_J2K; + else + BLI_assert(!"Unsupported jp2 codec was specified in im_format->jp2_codec"); } #endif else { @@ -1956,7 +2024,8 @@ int BKE_imbuf_write_stamp(Scene *scene, struct Object *camera, ImBuf *ibuf, cons } -void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame, const char imtype, const short use_ext, const short use_frames) +static void do_makepicstring(char *string, const char *base, const char *relbase, int frame, const char imtype, + const ImageFormatData *im_format, const short use_ext, const short use_frames) { if (string == NULL) return; BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */ @@ -1966,8 +2035,17 @@ void BKE_makepicstring(char *string, const char *base, const char *relbase, int BLI_path_frame(string, frame, 4); if (use_ext) - BKE_add_image_extension(string, imtype); + do_add_image_extension(string, imtype, im_format); +} +void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame, const ImageFormatData *im_format, const short use_ext, const short use_frames) +{ + do_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames); +} + +void BKE_makepicstring_from_type(char *string, const char *base, const char *relbase, int frame, const char imtype, const short use_ext, const short use_frames) +{ + do_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames); } /* used by sequencer too */ @@ -2284,7 +2362,7 @@ void BKE_image_backup_render(Scene *scene, Image *ima) static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr) { const char *colorspace = ima->colorspace_settings.name; - int predivide = ima->flag & IMA_CM_PREDIVIDE; + int predivide = ima->alpha_mode == IMA_ALPHA_PREMUL; ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y); @@ -2316,6 +2394,18 @@ static void image_initialize_after_load(Image *ima, ImBuf *ibuf) } +static int imbuf_alpha_flags_for_image(Image *ima) +{ + int flag = 0; + + if (ima->flag & IMA_IGNORE_ALPHA) + flag |= IB_ignore_alpha; + else if (ima->alpha_mode == IMA_ALPHA_PREMUL) + flag |= IB_alphamode_premul; + + return flag; +} + static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) { struct ImBuf *ibuf; @@ -2330,8 +2420,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) BKE_image_user_file_path(iuser, ima, name); flag = IB_rect | IB_multilayer; - if (ima->flag & IMA_DO_PREMUL) - flag |= IB_premul; + flag |= imbuf_alpha_flags_for_image(ima); /* read ibuf */ ibuf = IMB_loadiffname(name, flag, ima->colorspace_settings.name); @@ -2490,15 +2579,14 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) /* is there a PackedFile with this image ? */ if (ima->packedfile) { flag = IB_rect | IB_multilayer; - if (ima->flag & IMA_DO_PREMUL) flag |= IB_premul; + flag |= imbuf_alpha_flags_for_image(ima); ibuf = IMB_ibImageFromMemory((unsigned char *)ima->packedfile->data, ima->packedfile->size, flag, ima->colorspace_settings.name, "<packed data>"); } else { flag = IB_rect | IB_multilayer | IB_metadata; - if (ima->flag & IMA_DO_PREMUL) - flag |= IB_premul; + flag |= imbuf_alpha_flags_for_image(ima); /* get the right string */ BKE_image_user_frame_calc(iuser, cfra, 0); @@ -2718,15 +2806,6 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ ibuf->dither = dither; - if (iuser->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE) { - ibuf->flags |= IB_cm_predivide; - ima->flag |= IMA_CM_PREDIVIDE; - } - else { - ibuf->flags &= ~IB_cm_predivide; - ima->flag &= ~IMA_CM_PREDIVIDE; - } - ima->ok = IMA_OK_LOADED; return ibuf; diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index ad95f09826a..ccc57a24540 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -1300,13 +1300,13 @@ static void do_latt_key(Scene *scene, Object *ob, Key *key, char *out, const int } /* returns key coordinates (+ tilt) when key applied, NULL otherwise */ -float *do_ob_key(Scene *scene, Object *ob) +float *BKE_key_evaluate_object(Scene *scene, Object *ob, int *r_totelem) { Key *key = BKE_key_from_object(ob); KeyBlock *actkb = BKE_keyblock_from_object(ob); char *out; int tot = 0, size = 0; - + if (key == NULL || key->block.first == NULL) return NULL; @@ -1344,7 +1344,7 @@ float *do_ob_key(Scene *scene, Object *ob) return NULL; /* allocate array */ - out = MEM_callocN(size, "do_ob_key out"); + out = MEM_callocN(size, "BKE_key_evaluate_object out"); /* prevent python from screwing this up? anyhoo, the from pointer could be dropped */ key->from = (ID *)ob->data; @@ -1383,6 +1383,9 @@ float *do_ob_key(Scene *scene, Object *ob) else if (ob->type == OB_SURF) do_curve_key(scene, ob, key, out, tot); } + if (r_totelem) { + *r_totelem = tot; + } return (float *)out; } @@ -1732,7 +1735,7 @@ void BKE_key_convert_to_mesh(KeyBlock *kb, Mesh *me) } /************************* vert coords ************************/ -float (*BKE_key_convert_to_vertcos(Object * ob, KeyBlock * kb))[3] +float (*BKE_key_convert_to_vertcos(Object *ob, KeyBlock *kb))[3] { float (*vertCos)[3], *co; float *fp = kb->data; diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index d98188d8a6f..fa01e9fd933 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -88,7 +88,7 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) /* vertex weight groups are just freed all for now */ if (lt->dvert) { - free_dverts(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); lt->dvert = NULL; } @@ -209,7 +209,7 @@ Lattice *BKE_lattice_copy(Lattice *lt) if (lt->dvert) { int tot = lt->pntsu * lt->pntsv * lt->pntsw; ltn->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); - copy_dverts(ltn->dvert, lt->dvert, tot); + BKE_defvert_array_copy(ltn->dvert, lt->dvert, tot); } ltn->editlatt = NULL; @@ -220,12 +220,12 @@ Lattice *BKE_lattice_copy(Lattice *lt) void BKE_lattice_free(Lattice *lt) { if (lt->def) MEM_freeN(lt->def); - if (lt->dvert) free_dverts(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + if (lt->dvert) BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); if (lt->editlatt) { Lattice *editlt = lt->editlatt->latt; if (editlt->def) MEM_freeN(editlt->def); - if (editlt->dvert) free_dverts(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + if (editlt->dvert) BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); MEM_freeN(editlt); MEM_freeN(lt->editlatt); diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index 2fa928e7c07..73452b216ff 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -933,7 +933,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas } /* main scan-fill */ - sf_tri_tot = BLI_scanfill_calc_ex(&sf_ctx, 0, zvec); + sf_tri_tot = BLI_scanfill_calc_ex(&sf_ctx, BLI_SCANFILL_CALC_HOLES, zvec); face_array = MEM_mallocN(sizeof(*face_array) * (sf_tri_tot + tot_feather_quads), "maskrast_face_index"); face_index = 0; diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 54bd03ece70..4655dd04261 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -631,11 +631,14 @@ Material *give_current_material(Object *ob, short act) if (totcolp == NULL || ob->totcol == 0) return NULL; if (act < 0) { - printf("no!\n"); + printf("Negative material index!\n"); } - if (act > ob->totcol) act = ob->totcol; - else if (act <= 0) act = 1; + /* return NULL for invalid 'act', can happen for mesh face indices */ + if (act > ob->totcol) + return NULL; + else if (act <= 0) + return NULL; if (ob->matbits && ob->matbits[act - 1]) { /* in object */ ma = ob->mat[act - 1]; @@ -1237,6 +1240,11 @@ int object_remove_material_slot(Object *ob) if (*matarar == NULL) return FALSE; + /* can happen on face selection in editmode */ + if (ob->actcol > ob->totcol) { + ob->actcol = ob->totcol; + } + /* we delete the actcol */ mao = (*matarar)[ob->actcol - 1]; if (mao) mao->id.us--; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 3eb96f218e4..30e7cb3bb36 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -430,42 +430,6 @@ void BKE_mesh_free(Mesh *me, int unlink) if (me->edit_btmesh) MEM_freeN(me->edit_btmesh); } -void copy_dverts(MDeformVert *dst, const MDeformVert *src, int copycount) -{ - /* Assumes dst is already set up */ - int i; - - if (!src || !dst) - return; - - memcpy(dst, src, copycount * sizeof(MDeformVert)); - - for (i = 0; i < copycount; i++) { - if (src[i].dw) { - dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * src[i].totweight, "copy_deformWeight"); - memcpy(dst[i].dw, src[i].dw, sizeof(MDeformWeight) * src[i].totweight); - } - } - -} - -void free_dverts(MDeformVert *dvert, int totvert) -{ - /* Instead of freeing the verts directly, - * call this function to delete any special - * vert data */ - int i; - - if (!dvert) - return; - - /* Free any special data from the verts */ - for (i = 0; i < totvert; i++) { - if (dvert[i].dw) MEM_freeN(dvert[i].dw); - } - MEM_freeN(dvert); -} - static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) { if (free_customdata) { @@ -2488,7 +2452,7 @@ void BKE_mesh_loops_to_mface_corners(CustomData *fdata, CustomData *ldata, */ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomData *pdata, - MVert *mvert, int totface, int UNUSED(totloop), + MVert *mvert, int totface, int totloop, int totpoly, /* when tessellating to recalculate normals after * we can skip copying here */ @@ -2503,15 +2467,15 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, #define TESSFACE_SCANFILL (1 << 0) #define TESSFACE_IS_QUAD (1 << 1) + const int looptris_tot = poly_to_tri_count(totpoly, totloop); + MPoly *mp, *mpoly; MLoop *ml, *mloop; - MFace *mface = NULL, *mf; - BLI_array_declare(mface); + MFace *mface, *mf; ScanFillContext sf_ctx; ScanFillVert *sf_vert, *sf_vert_last, *sf_vert_first; ScanFillFace *sf_tri; - int *mface_to_poly_map = NULL; - BLI_array_declare(mface_to_poly_map); + int *mface_to_poly_map; int lindex[4]; /* only ever use 3 in this case */ int poly_index, j, mface_index; @@ -2525,8 +2489,9 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, /* allocate the length of totfaces, avoid many small reallocs, * if all faces are tri's it will be correct, quads == 2x allocs */ - BLI_array_reserve(mface_to_poly_map, totpoly); - BLI_array_reserve(mface, totpoly); + /* take care. we are _not_ calloc'ing so be sure to initialize each field */ + mface_to_poly_map = MEM_mallocN(sizeof(*mface_to_poly_map) * looptris_tot, __func__); + mface = MEM_mallocN(sizeof(*mface) * looptris_tot, __func__); mface_index = 0; mp = mpoly; @@ -2538,8 +2503,6 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, #ifdef USE_TESSFACE_SPEEDUP #define ML_TO_MF(i1, i2, i3) \ - BLI_array_grow_one(mface_to_poly_map); \ - BLI_array_grow_one(mface); \ mface_to_poly_map[mface_index] = poly_index; \ mf = &mface[mface_index]; \ /* set loop indices, transformed to vert indices later */ \ @@ -2549,12 +2512,11 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, mf->v4 = 0; \ mf->mat_nr = mp->mat_nr; \ mf->flag = mp->flag; \ + mf->edcode = 0; \ (void)0 /* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */ #define ML_TO_MF_QUAD() \ - BLI_array_grow_one(mface_to_poly_map); \ - BLI_array_grow_one(mface); \ mface_to_poly_map[mface_index] = poly_index; \ mf = &mface[mface_index]; \ /* set loop indices, transformed to vert indices later */ \ @@ -2564,7 +2526,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, mf->v4 = mp->loopstart + 3; /* EXCEPTION */ \ mf->mat_nr = mp->mat_nr; \ mf->flag = mp->flag; \ - mf->edcode |= TESSFACE_IS_QUAD; /* EXCEPTION */ \ + mf->edcode = TESSFACE_IS_QUAD; /* EXCEPTION */ \ (void)0 @@ -2607,29 +2569,26 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert_first); totfilltri = BLI_scanfill_calc(&sf_ctx, 0); - if (totfilltri) { - BLI_array_grow_items(mface_to_poly_map, totfilltri); - BLI_array_grow_items(mface, totfilltri); + BLI_assert(totfilltri <= mp->totloop - 2); - for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next, mf++) { - mface_to_poly_map[mface_index] = poly_index; - mf = &mface[mface_index]; + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next, mf++) { + mface_to_poly_map[mface_index] = poly_index; + mf = &mface[mface_index]; - /* set loop indices, transformed to vert indices later */ - mf->v1 = sf_tri->v1->keyindex; - mf->v2 = sf_tri->v2->keyindex; - mf->v3 = sf_tri->v3->keyindex; - mf->v4 = 0; + /* set loop indices, transformed to vert indices later */ + mf->v1 = sf_tri->v1->keyindex; + mf->v2 = sf_tri->v2->keyindex; + mf->v3 = sf_tri->v3->keyindex; + mf->v4 = 0; - mf->mat_nr = mp->mat_nr; - mf->flag = mp->flag; + mf->mat_nr = mp->mat_nr; + mf->flag = mp->flag; #ifdef USE_TESSFACE_SPEEDUP - mf->edcode |= TESSFACE_SCANFILL; /* tag for sorting loop indices */ + mf->edcode = TESSFACE_SCANFILL; /* tag for sorting loop indices */ #endif - mface_index++; - } + mface_index++; } BLI_scanfill_end(&sf_ctx); @@ -2639,9 +2598,10 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData_free(fdata, totface); totface = mface_index; + BLI_assert(totface <= looptris_tot); /* not essential but without this we store over-alloc'd memory in the CustomData layers */ - if (LIKELY((MEM_allocN_len(mface) / sizeof(*mface)) != totface)) { + if (LIKELY(looptris_tot != totface)) { mface = MEM_reallocN(mface, sizeof(*mface) * totface); mface_to_poly_map = MEM_reallocN(mface_to_poly_map, sizeof(*mface_to_poly_map) * totface); } diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 4156b5b4367..69e368f0d08 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1325,7 +1325,7 @@ void BKE_movieclip_unlink(Main *bmain, MovieClip *clip) bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data; diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 06d7cf55d49..b12463daf72 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -379,7 +379,7 @@ void multires_force_update(Object *ob) ob->derivedFinal = NULL; } if (ob->sculpt && ob->sculpt->pbvh) { - BLI_pbvh_free(ob->sculpt->pbvh); + BKE_pbvh_free(ob->sculpt->pbvh); ob->sculpt->pbvh = NULL; } } @@ -1407,7 +1407,7 @@ void multires_stitch_grids(Object *ob) int totface; if (ccgdm->pbvh) { - BLI_pbvh_get_grid_updates(ccgdm->pbvh, 0, (void ***)&faces, &totface); + BKE_pbvh_get_grid_updates(ccgdm->pbvh, 0, (void ***)&faces, &totface); if (totface) { ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 8babdf2402f..84e280034ed 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1161,11 +1161,11 @@ void ntreeSetOutput(bNodeTree *ntree) bNodeTree *ntreeFromID(ID *id) { switch (GS(id->name)) { - case ID_MA: return ((Material*)id)->nodetree; - case ID_LA: return ((Lamp*)id)->nodetree; - case ID_WO: return ((World*)id)->nodetree; - case ID_TE: return ((Tex*)id)->nodetree; - case ID_SCE: return ((Scene*)id)->nodetree; + case ID_MA: return ((Material *)id)->nodetree; + case ID_LA: return ((Lamp *)id)->nodetree; + case ID_WO: return ((World *)id)->nodetree; + case ID_TE: return ((Tex *)id)->nodetree; + case ID_SCE: return ((Scene *)id)->nodetree; default: return NULL; } } @@ -2323,6 +2323,7 @@ static void registerShaderNodes(bNodeTreeType *ttype) register_node_type_sh_layer_weight(ttype); register_node_type_sh_tex_coord(ttype); register_node_type_sh_particle_info(ttype); + register_node_type_sh_hair_info(ttype); register_node_type_sh_bump(ttype); register_node_type_sh_script(ttype); register_node_type_sh_tangent(ttype); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index d13d456a183..5a22973164e 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -268,14 +268,44 @@ void free_sculptsession_deformMats(SculptSession *ss) ss->deform_imats = NULL; } +/* Write out the sculpt dynamic-topology BMesh to the Mesh */ +void sculptsession_bm_to_me(struct Object *ob, int reorder) +{ + if (ob && ob->sculpt) { + SculptSession *ss = ob->sculpt; + + if (ss->bm) { + if (ob->data) { + BMIter iter; + BMFace *efa; + BM_ITER_MESH (efa, &iter, ss->bm, BM_FACES_OF_MESH) { + BM_elem_flag_set(efa, BM_ELEM_SMOOTH, + ss->bm_smooth_shading); + } + if (reorder) + BM_log_mesh_elems_reorder(ss->bm, ss->bm_log); + BM_mesh_bm_to_me(ss->bm, ob->data, FALSE); + } + } + } +} + void free_sculptsession(Object *ob) { if (ob && ob->sculpt) { SculptSession *ss = ob->sculpt; DerivedMesh *dm = ob->derivedFinal; + if (ss->bm) { + sculptsession_bm_to_me(ob, TRUE); + BM_mesh_free(ss->bm); + } + if (ss->pbvh) - BLI_pbvh_free(ss->pbvh); + BKE_pbvh_free(ss->pbvh); + if (ss->bm_log) + BM_log_free(ss->bm_log); + if (dm && dm->getPBVH) dm->getPBVH(NULL, dm); /* signal to clear */ @@ -353,7 +383,7 @@ void BKE_object_free(Object *ob) free_controllers(&ob->controllers); free_actuators(&ob->actuators); - free_constraints(&ob->constraints); + BKE_free_constraints(&ob->constraints); free_partdeflect(ob->pd); @@ -438,7 +468,7 @@ void BKE_object_unlink(Object *ob) bPoseChannel *pchan; for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -469,7 +499,7 @@ void BKE_object_unlink(Object *ob) sca_remove_ob_poin(obt, ob); for (con = obt->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1143,7 +1173,7 @@ static void copy_object_pose(Object *obn, Object *ob) } for (con = chan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1243,7 +1273,7 @@ static Object *object_copy_do(Object *ob, int copy_caches) BKE_pose_rebuild(obn, obn->data); } defgroup_copy_list(&obn->defbase, &ob->defbase); - copy_constraints(&obn->constraints, &ob->constraints, TRUE); + BKE_copy_constraints(&obn->constraints, &ob->constraints, TRUE); obn->mode = 0; obn->sculpt = NULL; @@ -2127,9 +2157,9 @@ void BKE_object_where_is_calc_time(Scene *scene, Object *ob, float ctime) if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) { bConstraintOb *cob; - cob = constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); - solve_constraints(&ob->constraints, cob, ctime); - constraints_clear_evalob(cob); + cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + BKE_solve_constraints(&ob->constraints, cob, ctime); + BKE_constraints_clear_evalob(cob); } /* set negative scale flag in object */ @@ -2198,9 +2228,9 @@ void BKE_object_where_is_calc_simul(Scene *scene, Object *ob) if (ob->constraints.first) { bConstraintOb *cob; - cob = constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); - solve_constraints(&ob->constraints, cob, (float)scene->r.cfra); - constraints_clear_evalob(cob); + cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + BKE_solve_constraints(&ob->constraints, cob, (float)scene->r.cfra); + BKE_constraints_clear_evalob(cob); } } @@ -2799,7 +2829,7 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) * changing PVBH node organization, we hope topology does not change in * the meantime .. weak */ if (ss->pbvh) { - BLI_pbvh_free(ss->pbvh); + BKE_pbvh_free(ss->pbvh); ss->pbvh = NULL; } @@ -2809,10 +2839,10 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) PBVHNode **nodes; int n, totnode; - BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); for (n = 0; n < totnode; n++) - BLI_pbvh_node_mark_update(nodes[n]); + BKE_pbvh_node_mark_update(nodes[n]); MEM_freeN(nodes); } @@ -2965,12 +2995,13 @@ static KeyBlock *insert_meshkey(Scene *scene, Object *ob, const char *name, int } else { /* copy from current values */ - float *data = do_ob_key(scene, ob); + int totelem; + float *data = BKE_key_evaluate_object(scene, ob, &totelem); /* create new block with prepared data */ kb = BKE_keyblock_add_ctime(key, name, FALSE); kb->data = data; - kb->totelem = me->totvert; + kb->totelem = totelem; } return kb; @@ -3002,11 +3033,12 @@ static KeyBlock *insert_lattkey(Scene *scene, Object *ob, const char *name, int } else { /* copy from current values */ - float *data = do_ob_key(scene, ob); + int totelem; + float *data = BKE_key_evaluate_object(scene, ob, &totelem); /* create new block with prepared data */ kb = BKE_keyblock_add_ctime(key, name, FALSE); - kb->totelem = lt->pntsu * lt->pntsv * lt->pntsw; + kb->totelem = totelem; kb->data = data; } @@ -3041,11 +3073,12 @@ static KeyBlock *insert_curvekey(Scene *scene, Object *ob, const char *name, int } else { /* copy from current values */ - float *data = do_ob_key(scene, ob); + int totelem; + float *data = BKE_key_evaluate_object(scene, ob, &totelem); /* create new block with prepared data */ kb = BKE_keyblock_add_ctime(key, name, FALSE); - kb->totelem = BKE_nurbList_verts_count(lb); + kb->totelem = totelem; kb->data = data; } @@ -3148,11 +3181,11 @@ void BKE_object_relink(Object *ob) if (ob->id.lib) return; - relink_constraints(&ob->constraints); + BKE_relink_constraints(&ob->constraints); if (ob->pose) { bPoseChannel *chan; for (chan = ob->pose->chanbase.first; chan; chan = chan->next) { - relink_constraints(&chan->constraints); + BKE_relink_constraints(&chan->constraints); } } modifiers_foreachIDLink(ob, copy_object__forwardModifierLinks, NULL); diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index e694a7e7eb3..c4274aa1f93 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -35,16 +35,15 @@ #include "DNA_scene_types.h" +#include "BKE_global.h" /* XXX TESTING */ #include "BKE_image.h" #include "BKE_ocean.h" -#include "BKE_global.h" // XXX TESTING -#include "BLI_math_base.h" -#include "BLI_math_inline.h" +#include "BLI_math.h" +#include "BLI_path_util.h" #include "BLI_rand.h" #include "BLI_string.h" #include "BLI_threads.h" -#include "BLI_path_util.h" #include "BLI_utildefines.h" #include "IMB_imbuf.h" @@ -54,7 +53,7 @@ #ifdef WITH_OCEANSIM -// Ocean code +/* Ocean code */ #include "fftw3.h" #define GRAVITY 9.81f @@ -82,7 +81,7 @@ typedef struct Ocean { float _Lx; float _Lz; - float normalize_factor; // init w + float normalize_factor; /* init w */ float time; short _do_disp_y; @@ -96,51 +95,52 @@ typedef struct Ocean { /* ********* sim data arrays ********* */ /* two dimensional arrays of complex */ - fftw_complex *_fft_in; // init w sim w - fftw_complex *_fft_in_x; // init w sim w - fftw_complex *_fft_in_z; // init w sim w - fftw_complex *_fft_in_jxx; // init w sim w - fftw_complex *_fft_in_jzz; // init w sim w - fftw_complex *_fft_in_jxz; // init w sim w - fftw_complex *_fft_in_nx; // init w sim w - fftw_complex *_fft_in_nz; // init w sim w - fftw_complex *_htilda; // init w sim w (only once) + fftw_complex *_fft_in; /* init w sim w */ + fftw_complex *_fft_in_x; /* init w sim w */ + fftw_complex *_fft_in_z; /* init w sim w */ + fftw_complex *_fft_in_jxx; /* init w sim w */ + fftw_complex *_fft_in_jzz; /* init w sim w */ + fftw_complex *_fft_in_jxz; /* init w sim w */ + fftw_complex *_fft_in_nx; /* init w sim w */ + fftw_complex *_fft_in_nz; /* init w sim w */ + fftw_complex *_htilda; /* init w sim w (only once) */ /* fftw "plans" */ - fftw_plan _disp_y_plan; // init w sim r - fftw_plan _disp_x_plan; // init w sim r - fftw_plan _disp_z_plan; // init w sim r - fftw_plan _N_x_plan; // init w sim r - fftw_plan _N_z_plan; // init w sim r - fftw_plan _Jxx_plan; // init w sim r - fftw_plan _Jxz_plan; // init w sim r - fftw_plan _Jzz_plan; // init w sim r + fftw_plan _disp_y_plan; /* init w sim r */ + fftw_plan _disp_x_plan; /* init w sim r */ + fftw_plan _disp_z_plan; /* init w sim r */ + fftw_plan _N_x_plan; /* init w sim r */ + fftw_plan _N_z_plan; /* init w sim r */ + fftw_plan _Jxx_plan; /* init w sim r */ + fftw_plan _Jxz_plan; /* init w sim r */ + fftw_plan _Jzz_plan; /* init w sim r */ /* two dimensional arrays of float */ - double *_disp_y; // init w sim w via plan? - double *_N_x; // init w sim w via plan? - /*float * _N_y; all member of this array has same values, so convert this array to a float to reduce memory usage (MEM01)*/ - double _N_y; // sim w ********* can be rearranged? - double *_N_z; // init w sim w via plan? - double *_disp_x; // init w sim w via plan? - double *_disp_z; // init w sim w via plan? + double *_disp_y; /* init w sim w via plan? */ + double *_N_x; /* init w sim w via plan? */ + /* all member of this array has same values, so convert this array to a float to reduce memory usage (MEM01)*/ + /*float * _N_y; */ + double _N_y; /* sim w ********* can be rearranged? */ + double *_N_z; /* init w sim w via plan? */ + double *_disp_x; /* init w sim w via plan? */ + double *_disp_z; /* init w sim w via plan? */ /* two dimensional arrays of float */ /* Jacobian and minimum eigenvalue */ - double *_Jxx; // init w sim w - double *_Jzz; // init w sim w - double *_Jxz; // init w sim w + double *_Jxx; /* init w sim w */ + double *_Jzz; /* init w sim w */ + double *_Jxz; /* init w sim w */ /* one dimensional float array */ - float *_kx; // init w sim r - float *_kz; // init w sim r + float *_kx; /* init w sim r */ + float *_kz; /* init w sim r */ /* two dimensional complex array */ - fftw_complex *_h0; // init w sim r - fftw_complex *_h0_minus; // init w sim r + fftw_complex *_h0; /* init w sim r */ + fftw_complex *_h0_minus; /* init w sim r */ /* two dimensional float array */ - float *_k; // init w sim r + float *_k; /* init w sim r */ } Ocean; @@ -152,10 +152,13 @@ static float nextfr(float min, float max) static float gaussRand(void) { - float x; // Note: to avoid numerical problems with very small - float y; // numbers, we make these variables singe-precision - float length2; // floats, but later we call the double-precision log() - // and sqrt() functions instead of logf() and sqrtf(). + /* Note: to avoid numerical problems with very small numbers, we make these variables singe-precision floats, + * but later we call the double-precision log() and sqrt() functions instead of logf() and sqrtf(). + */ + float x; + float y; + float length2; + do { x = (float) (nextfr(-1, 1)); y = (float)(nextfr(-1, 1)); @@ -167,12 +170,7 @@ static float gaussRand(void) /** * Some useful functions - * */ -MINLINE float lerp(float a, float b, float f) -{ - return a + (b - a) * f; -} - + */ MINLINE float catrom(float p0, float p1, float p2, float p3, float f) { return 0.5f * ((2.0f * p1) + @@ -186,23 +184,24 @@ MINLINE float omega(float k, float depth) return sqrtf(GRAVITY * k * tanhf(k * depth)); } -// modified Phillips spectrum +/* modified Phillips spectrum */ static float Ph(struct Ocean *o, float kx, float kz) { float tmp; float k2 = kx * kx + kz * kz; if (k2 == 0.0f) { - return 0.0f; // no DC component + return 0.0f; /* no DC component */ } - // damp out the waves going in the direction opposite the wind + /* damp out the waves going in the direction opposite the wind */ tmp = (o->_wx * kx + o->_wz * kz) / sqrtf(k2); if (tmp < 0) { tmp *= o->_damp_reflections; } - return o->_A * expf(-1.0f / (k2 * (o->_L * o->_L))) * expf(-k2 * (o->_l * o->_l)) * powf(fabsf(tmp), o->_wind_alignment) / (k2 * k2); + return o->_A * expf(-1.0f / (k2 * (o->_L * o->_L))) * expf(-k2 * (o->_l * o->_l)) * + powf(fabsf(tmp), o->_wind_alignment) / (k2 * k2); } static void compute_eigenstuff(struct OceanResult *ocr, float jxx, float jzz, float jxz) @@ -240,7 +239,7 @@ static void init_complex(fftw_complex cmpl, float real, float image) cmpl[1] = image; } -#if 0 // unused +#if 0 /* unused */ static void add_complex_f(fftw_complex res, fftw_complex cmpl, float f) { res[0] = cmpl[0] + f; @@ -306,7 +305,7 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float float frac_x, frac_z; float uu, vv; - // first wrap the texture so 0 <= (u, v) < 1 + /* first wrap the texture so 0 <= (u, v) < 1 */ u = fmodf(u, 1.0f); v = fmodf(v, 1.0f); @@ -334,7 +333,9 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float j1 = j1 % oc->_N; -#define BILERP(m) (lerp(lerp(m[i0 * oc->_N + j0], m[i1 * oc->_N + j0], frac_x), lerp(m[i0 * oc->_N + j1], m[i1 * oc->_N + j1], frac_x), frac_z)) +#define BILERP(m) (interpf(interpf(m[i1 * oc->_N + j1], m[i0 * oc->_N + j1], frac_x), \ + interpf(m[i1 * oc->_N + j0], m[i0 * oc->_N + j0], frac_x), \ + frac_z)) { if (oc->_do_disp_y) { ocr->disp[1] = BILERP(oc->_disp_y); @@ -364,14 +365,14 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float BLI_rw_mutex_unlock(&oc->oceanmutex); } -// use catmullrom interpolation rather than linear +/* use catmullrom interpolation rather than linear */ void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u, float v) { int i0, i1, i2, i3, j0, j1, j2, j3; float frac_x, frac_z; float uu, vv; - // first wrap the texture so 0 <= (u, v) < 1 + /* first wrap the texture so 0 <= (u, v) < 1 */ u = fmod(u, 1.0f); v = fmod(v, 1.0f); @@ -408,11 +409,15 @@ void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u j0 = j0 < 0 ? j0 + oc->_N : j0; j3 = j3 >= oc->_N ? j3 - oc->_N : j3; -#define INTERP(m) catrom(catrom(m[i0 * oc->_N + j0], m[i1 * oc->_N + j0], m[i2 * oc->_N + j0], m[i3 * oc->_N + j0], frac_x), \ - catrom(m[i0 * oc->_N + j1], m[i1 * oc->_N + j1], m[i2 * oc->_N + j1], m[i3 * oc->_N + j1], frac_x), \ - catrom(m[i0 * oc->_N + j2], m[i1 * oc->_N + j2], m[i2 * oc->_N + j2], m[i3 * oc->_N + j2], frac_x), \ - catrom(m[i0 * oc->_N + j3], m[i1 * oc->_N + j3], m[i2 * oc->_N + j3], m[i3 * oc->_N + j3], frac_x), \ - frac_z) +#define INTERP(m) catrom(catrom(m[i0 * oc->_N + j0], m[i1 * oc->_N + j0], \ + m[i2 * oc->_N + j0], m[i3 * oc->_N + j0], frac_x), \ + catrom(m[i0 * oc->_N + j1], m[i1 * oc->_N + j1], \ + m[i2 * oc->_N + j1], m[i3 * oc->_N + j1], frac_x), \ + catrom(m[i0 * oc->_N + j2], m[i1 * oc->_N + j2], \ + m[i2 * oc->_N + j2], m[i3 * oc->_N + j2], frac_x), \ + catrom(m[i0 * oc->_N + j3], m[i1 * oc->_N + j3], \ + m[i2 * oc->_N + j3], m[i3 * oc->_N + j3], frac_x), \ + frac_z) { if (oc->_do_disp_y) { @@ -452,9 +457,9 @@ void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x BKE_ocean_eval_uv_catrom(oc, ocr, x / oc->_Lx, z / oc->_Lz); } -// note that this doesn't wrap properly for i, j < 0, but its -// not really meant for that being just a way to get the raw data out -// to save in some image format. +/* note that this doesn't wrap properly for i, j < 0, but its not really meant for that being just a way to get + * the raw data out to save in some image format. + */ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j) { BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); @@ -496,11 +501,10 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); - // compute a new htilda + /* compute a new htilda */ #pragma omp parallel for private(i, j) for (i = 0; i < o->_M; ++i) { - // note the <= _N/2 here, see the fftw doco about - // the mechanics of the complex->real fft storage + /* note the <= _N/2 here, see the fftw doco about the mechanics of the complex->real fft storage */ for (j = 0; j <= o->_N / 2; ++j) { fftw_complex exp_param1; fftw_complex exp_param2; @@ -527,15 +531,15 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount #pragma omp section { if (o->_do_disp_y) { - // y displacement + /* y displacement */ fftw_execute(o->_disp_y_plan); } - } // section 1 + } /* section 1 */ #pragma omp section { if (o->_do_chop) { - // x displacement + /* x displacement */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; @@ -546,18 +550,21 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, minus_i); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0f ? 0.0f : o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_x[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_disp_x_plan); } - } //section 2 + } /* section 2 */ #pragma omp section { if (o->_do_chop) { - // z displacement + /* z displacement */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; @@ -568,28 +575,34 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, minus_i); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0f ? 0.0f : o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_z[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_disp_z_plan); } - } // section 3 + } /* section 3 */ #pragma omp section { if (o->_do_jacobian) { - // Jxx + /* Jxx */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; - //init_complex(mul_param, -scale, 0); + /* init_complex(mul_param, -scale, 0); */ init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0f ? 0.0f : o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_jxx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } @@ -601,22 +614,25 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount } } } - } // section 4 + } /* section 4 */ #pragma omp section { if (o->_do_jacobian) { - // Jzz + /* Jzz */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; - //init_complex(mul_param, -scale, 0); + /* init_complex(mul_param, -scale, 0); */ init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0f ? 0.0f : o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_jzz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } @@ -627,32 +643,35 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount } } } - } // section 5 + } /* section 5 */ #pragma omp section { if (o->_do_jacobian) { - // Jxz + /* Jxz */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; - //init_complex(mul_param, -scale, 0); + /* init_complex(mul_param, -scale, 0); */ init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0f ? 0.0f : o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_jxz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_Jxz_plan); } - } // section 6 + } /* section 6 */ #pragma omp section { - // fft normals + /* fft normals */ if (o->_do_normals) { for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { @@ -667,7 +686,7 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount fftw_execute(o->_N_x_plan); } - } // section 7 + } /* section 7 */ #pragma omp section { @@ -694,9 +713,9 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount #endif o->_N_y = 1.0f / scale; } - } // section 8 + } /* section 8 */ - } // omp sections + } /* omp sections */ BLI_rw_mutex_unlock(&o->oceanmutex); } @@ -726,7 +745,8 @@ static void set_height_normalize_factor(struct Ocean *oc) BLI_rw_mutex_unlock(&oc->oceanmutex); - if (max_h == 0.0f) max_h = 0.00001f; // just in case ... + if (max_h == 0.0f) + max_h = 0.00001f; /* just in case ... */ res = 1.0f / (max_h); @@ -743,7 +763,8 @@ struct Ocean *BKE_add_ocean(void) } void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp, - float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed) + float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, + short do_jacobian, int seed) { int i, j, ii; @@ -761,8 +782,8 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, o->_Lx = Lx; o->_Lz = Lz; o->_wx = cos(w); - o->_wz = -sin(w); // wave direction - o->_L = V * V / GRAVITY; // largest wave for a given velocity V + o->_wz = -sin(w); /* wave direction */ + o->_L = V * V / GRAVITY; /* largest wave for a given velocity V */ o->time = time; o->_do_disp_y = do_height_field; @@ -776,30 +797,30 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, o->_kx = (float *) MEM_mallocN(o->_M * sizeof(float), "ocean_kx"); o->_kz = (float *) MEM_mallocN(o->_N * sizeof(float), "ocean_kz"); - // make this robust in the face of erroneous usage + /* make this robust in the face of erroneous usage */ if (o->_Lx == 0.0f) o->_Lx = 0.001f; if (o->_Lz == 0.0f) o->_Lz = 0.001f; - // the +ve components and DC + /* the +ve components and DC */ for (i = 0; i <= o->_M / 2; ++i) o->_kx[i] = 2.0f * (float)M_PI * i / o->_Lx; - // the -ve components + /* the -ve components */ for (i = o->_M - 1, ii = 0; i > o->_M / 2; --i, ++ii) o->_kx[i] = -2.0f * (float)M_PI * ii / o->_Lx; - // the +ve components and DC + /* the +ve components and DC */ for (i = 0; i <= o->_N / 2; ++i) o->_kz[i] = 2.0f * (float)M_PI * i / o->_Lz; - // the -ve components + /* the -ve components */ for (i = o->_N - 1, ii = 0; i > o->_N / 2; --i, ++ii) o->_kz[i] = -2.0f * (float)M_PI * ii / o->_Lz; - // pre-calculate the k matrix + /* pre-calculate the k matrix */ for (i = 0; i < o->_M; ++i) for (j = 0; j <= o->_N / 2; ++j) o->_k[i * (1 + o->_N / 2) + j] = sqrt(o->_kx[i] * o->_kx[i] + o->_kz[j] * o->_kz[j]); @@ -819,11 +840,11 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, } } - o->_fft_in = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in"); - o->_htilda = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_htilda"); + o->_fft_in = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in"); + o->_htilda = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_htilda"); if (o->_do_disp_y) { - o->_disp_y = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_y"); + o->_disp_y = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_y"); o->_disp_y_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in, o->_disp_y, FFTW_ESTIMATE); } @@ -831,32 +852,35 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, o->_fft_in_nx = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_nx"); o->_fft_in_nz = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_nz"); - o->_N_x = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x"); + o->_N_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x"); /* o->_N_y = (float *) fftwf_malloc(o->_M * o->_N * sizeof(float)); (MEM01) */ - o->_N_z = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z"); + o->_N_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z"); o->_N_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nx, o->_N_x, FFTW_ESTIMATE); o->_N_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nz, o->_N_z, FFTW_ESTIMATE); } if (o->_do_chop) { - o->_fft_in_x = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_x"); - o->_fft_in_z = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_z"); + o->_fft_in_x = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_x"); + o->_fft_in_z = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_z"); - o->_disp_x = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_x"); - o->_disp_z = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_z"); + o->_disp_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_x"); + o->_disp_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_z"); o->_disp_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_x, o->_disp_x, FFTW_ESTIMATE); o->_disp_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_z, o->_disp_z, FFTW_ESTIMATE); } if (o->_do_jacobian) { - o->_fft_in_jxx = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_jxx"); - o->_fft_in_jzz = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_jzz"); - o->_fft_in_jxz = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_jxz"); + o->_fft_in_jxx = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), + "ocean_fft_in_jxx"); + o->_fft_in_jzz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), + "ocean_fft_in_jzz"); + o->_fft_in_jxz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), + "ocean_fft_in_jxz"); - o->_Jxx = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxx"); - o->_Jzz = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jzz"); - o->_Jxz = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxz"); + o->_Jxx = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxx"); + o->_Jzz = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jzz"); + o->_Jxz = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxz"); o->_Jxx_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxx, o->_Jxx, FFTW_ESTIMATE); o->_Jzz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jzz, o->_Jzz, FFTW_ESTIMATE); @@ -967,7 +991,7 @@ static void cache_filename(char *string, const char *path, const char *relbase, BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname); - BKE_makepicstring(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, 1, TRUE); + BKE_makepicstring_from_type(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, 1, TRUE); } /* silly functions but useful to inline when the args do a lot of indirections */ @@ -1076,8 +1100,7 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, in } } -struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbase, - int start, int end, float wave_scale, +struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbase, int start, int end, float wave_scale, float chop_amount, float foam_coverage, float foam_fade, int resolution) { OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data"); @@ -1112,7 +1135,7 @@ void BKE_simulate_ocean_cache(struct OceanCache *och, int frame) /* ibufs array is zero based, but filenames are based on frame numbers */ /* still need to clamp frame numbers to valid range of images on disk though */ CLAMP(frame, och->start, och->end); - f = frame - och->start; // shift to 0 based + f = frame - och->start; /* shift to 0 based */ /* if image is already loaded in mem, return */ if (och->ibufs_disp[f] != NULL) return; @@ -1121,22 +1144,35 @@ void BKE_simulate_ocean_cache(struct OceanCache *och, int frame) cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_DISPLACE); och->ibufs_disp[f] = IMB_loadiffname(string, 0, NULL); - //if (och->ibufs_disp[f] == NULL) printf("error loading %s\n", string); - //else printf("loaded cache %s\n", string); +#if 0 + if (och->ibufs_disp[f] == NULL) + printf("error loading %s\n", string); + else + printf("loaded cache %s\n", string); +#endif cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_FOAM); och->ibufs_foam[f] = IMB_loadiffname(string, 0, NULL); - //if (och->ibufs_foam[f] == NULL) printf("error loading %s\n", string); - //else printf("loaded cache %s\n", string); +#if 0 + if (och->ibufs_foam[f] == NULL) + printf("error loading %s\n", string); + else + printf("loaded cache %s\n", string); +#endif cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_NORMAL); och->ibufs_norm[f] = IMB_loadiffname(string, 0, NULL); - //if (och->ibufs_norm[f] == NULL) printf("error loading %s\n", string); - //else printf("loaded cache %s\n", string); +#if 0 + if (och->ibufs_norm[f] == NULL) + printf("error loading %s\n", string); + else + printf("loaded cache %s\n", string); +#endif } -void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data) +void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), + void *update_cb_data) { /* note: some of these values remain uninitialized unless certain options * are enabled, take care that BKE_ocean_eval_ij() initializes a member @@ -1197,13 +1233,13 @@ void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v pr = prev_foam[res_x * y + x]; } - /* r = BLI_frand(); */ /* UNUSED */ // randomly reduce foam + /* r = BLI_frand(); */ /* UNUSED */ /* randomly reduce foam */ - //pr = pr * och->foam_fade; // overall fade + /* pr = pr * och->foam_fade; */ /* overall fade */ - // remember ocean coord sys is Y up! - // break up the foam where height (Y) is low (wave valley), - // and X and Z displacement is greatest + /* remember ocean coord sys is Y up! + * break up the foam where height (Y) is low (wave valley), and X and Z displacement is greatest + */ #if 0 vec[0] = ocr.disp[0]; @@ -1219,22 +1255,27 @@ void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v neg_eplus = ocr.Eplus[2] < 0.0f ? 1.0f + ocr.Eplus[2] : 1.0f; neg_eplus = neg_eplus < 0.0f ? 0.0f : neg_eplus; - //if (ocr.disp[1] < 0.0 || r > och->foam_fade) - // pr *= och->foam_fade; +#if 0 + if (ocr.disp[1] < 0.0 || r > och->foam_fade) + pr *= och->foam_fade; - //pr = pr * (1.0 - hor_stretch) * ocr.disp[1]; - //pr = pr * neg_disp * neg_eplus; + pr = pr * (1.0 - hor_stretch) * ocr.disp[1]; + pr = pr * neg_disp * neg_eplus; +#endif - if (pr < 1.0f) pr *= pr; + if (pr < 1.0f) + pr *= pr; pr *= och->foam_fade * (0.75f + neg_eplus * 0.25f); - - foam_result = pr + ocr.foam; + /* A full clamping should not be needed! */ + foam_result = min_ff(pr + ocr.foam, 1.0f); prev_foam[res_x * y + x] = foam_result; + /*foam_result = min_ff(foam_result, 1.0f); */ + value_to_rgba_unit_alpha(&ibuf_foam->rect_float[4 * (res_x * y + x)], foam_result); } @@ -1279,7 +1320,7 @@ void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v och->baked = 1; } -#else // WITH_OCEANSIM +#else /* WITH_OCEANSIM */ /* stub */ typedef struct Ocean { @@ -1297,8 +1338,9 @@ void BKE_ocean_eval_uv(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr) { } -// use catmullrom interpolation rather than linear -void BKE_ocean_eval_uv_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(u), float UNUSED(v)) +/* use catmullrom interpolation rather than linear */ +void BKE_ocean_eval_uv_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(u), + float UNUSED(v)) { } @@ -1306,7 +1348,8 @@ void BKE_ocean_eval_xz(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr) { } -void BKE_ocean_eval_xz_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(x), float UNUSED(z)) +void BKE_ocean_eval_xz_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(x), + float UNUSED(z)) { } @@ -1325,8 +1368,10 @@ struct Ocean *BKE_add_ocean(void) return oc; } -void BKE_init_ocean(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz), float UNUSED(V), float UNUSED(l), float UNUSED(A), float UNUSED(w), float UNUSED(damp), - float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), short UNUSED(do_height_field), short UNUSED(do_chop), short UNUSED(do_normals), short UNUSED(do_jacobian), int UNUSED(seed)) +void BKE_init_ocean(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz), + float UNUSED(V), float UNUSED(l), float UNUSED(A), float UNUSED(w), float UNUSED(damp), + float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), short UNUSED(do_height_field), + short UNUSED(do_chop), short UNUSED(do_normals), short UNUSED(do_jacobian), int UNUSED(seed)) { } @@ -1351,17 +1396,19 @@ void BKE_free_ocean_cache(struct OceanCache *och) MEM_freeN(och); } -void BKE_ocean_cache_eval_uv(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), float UNUSED(u), float UNUSED(v)) +void BKE_ocean_cache_eval_uv(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), + float UNUSED(u), float UNUSED(v)) { } -void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), int UNUSED(i), int UNUSED(j)) +void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), + int UNUSED(i), int UNUSED(j)) { } -OceanCache *BKE_init_ocean_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), - int UNUSED(start), int UNUSED(end), float UNUSED(wave_scale), - float UNUSED(chop_amount), float UNUSED(foam_coverage), float UNUSED(foam_fade), int UNUSED(resolution)) +OceanCache *BKE_init_ocean_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), int UNUSED(start), + int UNUSED(end), float UNUSED(wave_scale), float UNUSED(chop_amount), + float UNUSED(foam_coverage), float UNUSED(foam_fade), int UNUSED(resolution)) { OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data"); @@ -1372,9 +1419,10 @@ void BKE_simulate_ocean_cache(struct OceanCache *UNUSED(och), int UNUSED(frame)) { } -void BKE_bake_ocean(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och), void (*update_cb)(void *, float progress, int *cancel), void *UNUSED(update_cb_data)) +void BKE_bake_ocean(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och), + void (*update_cb)(void *, float progress, int *cancel), void *UNUSED(update_cb_data)) { /* unused */ (void)update_cb; } -#endif // WITH_OCEANSIM +#endif /* WITH_OCEANSIM */
\ No newline at end of file diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index dec49f417ae..9f77094994d 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -43,6 +43,7 @@ #include "MEM_guardedalloc.h" #include "DNA_image_types.h" +#include "DNA_ID.h" #include "DNA_sound_types.h" #include "DNA_vfont_types.h" #include "DNA_packedFile_types.h" @@ -226,6 +227,7 @@ PackedFile *newPackedFile(ReportList *reports, const char *filename, const char return (pf); } +/* no libraries for now */ void packAll(Main *bmain, ReportList *reports) { Image *ima; @@ -538,6 +540,41 @@ int unpackImage(ReportList *reports, Image *ima, int how) return(ret_value); } +int unpackLibraries(Main *bmain, ReportList *reports) +{ + Library *lib; + char *newname; + int ret_value = RET_ERROR; + + for (lib = bmain->library.first; lib; lib = lib->id.next) { + if (lib->packedfile && lib->name[0]) { + + newname = unpackFile(reports, lib->filepath, lib->filepath, lib->packedfile, PF_WRITE_ORIGINAL); + if (newname != NULL) { + ret_value = RET_OK; + + printf("Saved .blend library: %s\n", newname); + + freePackedFile(lib->packedfile); + lib->packedfile = NULL; + + MEM_freeN(newname); + } + } + } + + return(ret_value); +} + +void packLibraries(Main *bmain, ReportList *reports) +{ + Library *lib; + + for (lib = bmain->library.first; lib; lib = lib->id.next) + if (lib->packedfile == NULL) + lib->packedfile = newPackedFile(reports, lib->name, bmain->name); +} + void unpackAll(Main *bmain, ReportList *reports, int how) { Image *ima; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index fa5268e039e..5847e7508f0 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -212,7 +212,7 @@ int paint_is_face_hidden(const MFace *f, const MVert *mvert) } /* returns non-zero if any of the corners of the grid - * face whose inner corner is at (x,y) are hidden, + * face whose inner corner is at (x, y) are hidden, * zero otherwise */ int paint_is_grid_face_hidden(const unsigned int *grid_hidden, int gridsize, int x, int y) diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 090082b333d..3b897e94241 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -522,9 +522,9 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) vec[0]/=delta[0]; vec[1]/=delta[1]; vec[2]/=delta[2]; - (pa + ((int)(vec[0] * (size[0] - 1)) * res + - (int)(vec[1] * (size[1] - 1))) * res + - (int)(vec[2] * (size[2] - 1)))->flag &= ~PARS_UNEXIST; + pa[((int)(vec[0] * (size[0] - 1)) * res + + (int)(vec[1] * (size[1] - 1))) * res + + (int)(vec[2] * (size[2] - 1))].flag &= ~PARS_UNEXIST; } } else if (ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) { diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 209461bad2f..2df2dd631d5 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -41,124 +41,12 @@ #include "GPU_buffers.h" +#include "pbvh_intern.h" + #define LEAF_LIMIT 10000 //#define PERFCNTRS -/* Axis-aligned bounding box */ -typedef struct { - float bmin[3], bmax[3]; -} BB; - -/* Axis-aligned bounding box with centroid */ -typedef struct { - float bmin[3], bmax[3], bcentroid[3]; -} BBC; - -struct PBVHNode { - /* Opaque handle for drawing code */ - GPU_Buffers *draw_buffers; - - /* Voxel bounds */ - BB vb; - BB orig_vb; - - /* For internal nodes, the offset of the children in the PBVH - * 'nodes' array. */ - int children_offset; - - /* Pointer into the PBVH prim_indices array and the number of - * primitives used by this leaf node. - * - * Used for leaf nodes in both mesh- and multires-based PBVHs. - */ - int *prim_indices; - unsigned int totprim; - - /* Array of indices into the mesh's MVert array. Contains the - * indices of all vertices used by faces that are within this - * node's bounding box. - * - * Note that a vertex might be used by a multiple faces, and - * these faces might be in different leaf nodes. Such a vertex - * will appear in the vert_indices array of each of those leaf - * nodes. - * - * In order to support cases where you want access to multiple - * nodes' vertices without duplication, the vert_indices array - * is ordered such that the first part of the array, up to - * index 'uniq_verts', contains "unique" vertex indices. These - * vertices might not be truly unique to this node, but if - * they appear in another node's vert_indices array, they will - * be above that node's 'uniq_verts' value. - * - * Used for leaf nodes in a mesh-based PBVH (not multires.) - */ - int *vert_indices; - unsigned int uniq_verts, face_verts; - - /* An array mapping face corners into the vert_indices - * array. The array is sized to match 'totprim', and each of - * the face's corners gets an index into the vert_indices - * array, in the same order as the corners in the original - * MFace. The fourth value should not be used if the original - * face is a triangle. - * - * Used for leaf nodes in a mesh-based PBVH (not multires.) - */ - int (*face_vert_indices)[4]; - - /* Indicates whether this node is a leaf or not; also used for - * marking various updates that need to be applied. */ - PBVHNodeFlags flag : 8; - - /* Used for raycasting: how close bb is to the ray point. */ - float tmin; - - int proxy_count; - PBVHProxyNode *proxies; -}; - -struct PBVH { - PBVHType type; - - PBVHNode *nodes; - int node_mem_count, totnode; - - int *prim_indices; - int totprim; - int totvert; - - int leaf_limit; - - /* Mesh data */ - MVert *verts; - MFace *faces; - CustomData *vdata; - - /* Grid Data */ - CCGKey gridkey; - CCGElem **grids; - DMGridAdjacency *gridadj; - void **gridfaces; - const DMFlagMat *grid_flag_mats; - int totgrid; - BLI_bitmap *grid_hidden; - - /* Only used during BVH build and update, - * don't need to remain valid after */ - BLI_bitmap vert_bitmap; - -#ifdef PERFCNTRS - int perf_modified; -#endif - - /* flag are verts/faces deformed */ - int deformed; - - int show_diffuse_color; -}; - #define STACK_FIXED_DEPTH 100 typedef struct PBVHStack { @@ -168,7 +56,7 @@ typedef struct PBVHStack { typedef struct PBVHIter { PBVH *bvh; - BLI_pbvh_SearchCallback scb; + BKE_pbvh_SearchCallback scb; void *search_data; PBVHStack *stack; @@ -178,14 +66,14 @@ typedef struct PBVHIter { int stackspace; } PBVHIter; -static void BB_reset(BB *bb) +void BB_reset(BB *bb) { bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX; bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX; } /* Expand the bounding box to include a new coordinate */ -static void BB_expand(BB *bb, float co[3]) +void BB_expand(BB *bb, const float co[3]) { int i; for (i = 0; i < 3; ++i) { @@ -195,7 +83,7 @@ static void BB_expand(BB *bb, float co[3]) } /* Expand the bounding box to include another bounding box */ -static void BB_expand_with_bb(BB *bb, BB *bb2) +void BB_expand_with_bb(BB *bb, BB *bb2) { int i; for (i = 0; i < 3; ++i) { @@ -205,7 +93,7 @@ static void BB_expand_with_bb(BB *bb, BB *bb2) } /* Return 0, 1, or 2 to indicate the widest axis of the bounding box */ -static int BB_widest_axis(BB *bb) +int BB_widest_axis(const BB *bb) { float dim[3]; int i; @@ -227,7 +115,7 @@ static int BB_widest_axis(BB *bb) } } -static void BBC_update_centroid(BBC *bbc) +void BBC_update_centroid(BBC *bbc) { int i; for (i = 0; i < 3; ++i) @@ -244,11 +132,11 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node) if (node->flag & PBVH_Leaf) { PBVHVertexIter vd; - BLI_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL) + BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL) { BB_expand(&vb, vd.co); } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } else { BB_expand_with_bb(&vb, @@ -260,12 +148,12 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node) node->vb = vb; } -//void BLI_pbvh_node_BB_reset(PBVHNode *node) +//void BKE_pbvh_node_BB_reset(PBVHNode *node) //{ // BB_reset(&node->vb); //} // -//void BLI_pbvh_node_BB_expand(PBVHNode *node, float co[3]) +//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]) //{ // BB_expand(&node->vb, co); //} @@ -332,7 +220,7 @@ static int partition_indices_material(PBVH *bvh, int lo, int hi) } } -static void grow_nodes(PBVH *bvh, int totnode) +void pbvh_grow_nodes(PBVH *bvh, int totnode) { if (totnode > bvh->node_mem_count) { PBVHNode *prev = bvh->nodes; @@ -545,7 +433,7 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, /* Add two child nodes */ bvh->nodes[node_index].children_offset = bvh->totnode; - grow_nodes(bvh, bvh->totnode + 2); + pbvh_grow_nodes(bvh, bvh->totnode + 2); /* Update parent node bounding box */ update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count); @@ -605,7 +493,7 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim) } /* Do a full rebuild with on Mesh data structure */ -void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert, struct CustomData *vdata) +void BKE_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert, struct CustomData *vdata) { BBC *prim_bbc = NULL; BB cb; @@ -647,7 +535,7 @@ void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int } /* Do a full rebuild with on Grids data structure */ -void BLI_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, +void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap *grid_hidden) { BBC *prim_bbc = NULL; @@ -690,14 +578,14 @@ void BLI_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, MEM_freeN(prim_bbc); } -PBVH *BLI_pbvh_new(void) +PBVH *BKE_pbvh_new(void) { PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); return bvh; } -void BLI_pbvh_free(PBVH *bvh) +void BKE_pbvh_free(PBVH *bvh) { PBVHNode *node; int i; @@ -712,6 +600,14 @@ void BLI_pbvh_free(PBVH *bvh) MEM_freeN(node->vert_indices); if (node->face_vert_indices) MEM_freeN(node->face_vert_indices); + BKE_pbvh_node_layer_disp_free(node); + + if (node->bm_faces) + BLI_ghash_free(node->bm_faces, NULL, NULL); + if (node->bm_unique_verts) + BLI_ghash_free(node->bm_unique_verts, NULL, NULL); + if (node->bm_other_verts) + BLI_ghash_free(node->bm_other_verts, NULL, NULL); } } @@ -731,10 +627,15 @@ void BLI_pbvh_free(PBVH *bvh) if (bvh->prim_indices) MEM_freeN(bvh->prim_indices); + if (bvh->bm_vert_to_node) + BLI_ghash_free(bvh->bm_vert_to_node, NULL, NULL); + if (bvh->bm_face_to_node) + BLI_ghash_free(bvh->bm_face_to_node, NULL, NULL); + MEM_freeN(bvh); } -static void pbvh_iter_begin(PBVHIter *iter, PBVH *bvh, BLI_pbvh_SearchCallback scb, void *search_data) +static void pbvh_iter_begin(PBVHIter *iter, PBVH *bvh, BKE_pbvh_SearchCallback scb, void *search_data) { iter->bvh = bvh; iter->scb = scb; @@ -845,8 +746,8 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter) return NULL; } -void BLI_pbvh_search_gather(PBVH *bvh, - BLI_pbvh_SearchCallback scb, void *search_data, +void BKE_pbvh_search_gather(PBVH *bvh, + BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot) { PBVHIter iter; @@ -886,9 +787,9 @@ void BLI_pbvh_search_gather(PBVH *bvh, *r_tot = tot; } -void BLI_pbvh_search_callback(PBVH *bvh, - BLI_pbvh_SearchCallback scb, void *search_data, - BLI_pbvh_HitCallback hcb, void *hit_data) +void BKE_pbvh_search_callback(PBVH *bvh, + BKE_pbvh_SearchCallback scb, void *search_data, + BKE_pbvh_HitCallback hcb, void *hit_data) { PBVHIter iter; PBVHNode *node; @@ -929,7 +830,7 @@ static void node_tree_insert(node_tree *tree, node_tree *new_node) } } -static void traverse_tree(node_tree *tree, BLI_pbvh_HitOccludedCallback hcb, void *hit_data, float *tmin) +static void traverse_tree(node_tree *tree, BKE_pbvh_HitOccludedCallback hcb, void *hit_data, float *tmin) { if (tree->left) traverse_tree(tree->left, hcb, hit_data, tmin); @@ -953,14 +854,14 @@ static void free_tree(node_tree *tree) free(tree); } -float BLI_pbvh_node_get_tmin(PBVHNode *node) +float BKE_pbvh_node_get_tmin(PBVHNode *node) { return node->tmin; } -static void BLI_pbvh_search_callback_occluded(PBVH *bvh, - BLI_pbvh_SearchCallback scb, void *search_data, - BLI_pbvh_HitOccludedCallback hcb, void *hit_data) +static void BKE_pbvh_search_callback_occluded(PBVH *bvh, + BKE_pbvh_SearchCallback scb, void *search_data, + BKE_pbvh_HitOccludedCallback hcb, void *hit_data) { PBVHIter iter; PBVHNode *node; @@ -1011,6 +912,11 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, float (*vnor)[3]; int n; + if (bvh->type == PBVH_BMESH) { + pbvh_bmesh_normals_update(nodes, totnode); + return; + } + if (bvh->type != PBVH_FACES) return; @@ -1104,8 +1010,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, MEM_freeN(vnor); } -static void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, - int totnode, int flag) +void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) { int n; @@ -1152,6 +1057,11 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) node->prim_indices, node->totprim); break; + case PBVH_BMESH: + node->draw_buffers = + GPU_build_bmesh_buffers(bvh->flags & + PBVH_DYNTOPO_SMOOTH_SHADING); + break; } node->flag &= ~PBVH_RebuildDrawBuffers; @@ -1179,6 +1089,13 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) node->face_vert_indices, bvh->show_diffuse_color); break; + case PBVH_BMESH: + GPU_update_bmesh_buffers(node->draw_buffers, + bvh->bm, + node->bm_faces, + node->bm_unique_verts, + node->bm_other_verts); + break; } node->flag &= ~PBVH_UpdateDrawBuffers; @@ -1217,7 +1134,7 @@ static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) return update; } -void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) +void BKE_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) { PBVHNode **nodes; int totnode; @@ -1225,7 +1142,7 @@ void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) if (!bvh->nodes) return; - BLI_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(flag), + BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(flag), &nodes, &totnode); if (flag & PBVH_UpdateNormals) @@ -1240,7 +1157,7 @@ void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) if (nodes) MEM_freeN(nodes); } -void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]) +void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]) { PBVHIter iter; PBVHNode *node; @@ -1260,7 +1177,7 @@ void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]) copy_v3_v3(bb_max, bb.bmax); } -void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface) +void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface) { PBVHIter iter; PBVHNode *node; @@ -1316,36 +1233,42 @@ void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *tot /***************************** PBVH Access ***********************************/ -PBVHType BLI_pbvh_type(const PBVH *bvh) +PBVHType BKE_pbvh_type(const PBVH *bvh) { return bvh->type; } -BLI_bitmap *BLI_pbvh_grid_hidden(const PBVH *bvh) +BLI_bitmap *BKE_pbvh_grid_hidden(const PBVH *bvh) { BLI_assert(bvh->type == PBVH_GRIDS); return bvh->grid_hidden; } -void BLI_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key) +void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key) { BLI_assert(bvh->type == PBVH_GRIDS); *key = bvh->gridkey; } +BMesh *BKE_pbvh_get_bmesh(PBVH *bvh) +{ + BLI_assert(bvh->type == PBVH_BMESH); + return bvh->bm; +} + /***************************** Node Access ***********************************/ -void BLI_pbvh_node_mark_update(PBVHNode *node) +void BKE_pbvh_node_mark_update(PBVHNode *node) { node->flag |= PBVH_UpdateNormals | PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; } -void BLI_pbvh_node_mark_rebuild_draw(PBVHNode *node) +void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node) { node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; } -void BLI_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden) +void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden) { BLI_assert(node->flag & PBVH_Leaf); @@ -1355,13 +1278,13 @@ void BLI_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden) node->flag &= ~PBVH_FullyHidden; } -void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, int **vert_indices, MVert **verts) +void BKE_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, int **vert_indices, MVert **verts) { if (vert_indices) *vert_indices = node->vert_indices; if (verts) *verts = bvh->verts; } -void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *totvert) +void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *totvert) { int tot; @@ -1375,10 +1298,15 @@ void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to if (totvert) *totvert = node->uniq_verts + node->face_verts; if (uniquevert) *uniquevert = node->uniq_verts; break; + case PBVH_BMESH: + tot = BLI_ghash_size(node->bm_unique_verts); + if (totvert) *totvert = tot + BLI_ghash_size(node->bm_other_verts); + if (uniquevert) *uniquevert = tot; + break; } } -void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata, DMGridAdjacency **gridadj) +void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata, DMGridAdjacency **gridadj) { switch (bvh->type) { case PBVH_GRIDS: @@ -1390,6 +1318,7 @@ void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int if (gridadj) *gridadj = bvh->gridadj; break; case PBVH_FACES: + case PBVH_BMESH: if (grid_indices) *grid_indices = NULL; if (totgrid) *totgrid = 0; if (maxgrid) *maxgrid = 0; @@ -1400,19 +1329,19 @@ void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int } } -void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) +void BKE_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) { copy_v3_v3(bb_min, node->vb.bmin); copy_v3_v3(bb_max, node->vb.bmax); } -void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) +void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) { copy_v3_v3(bb_min, node->orig_vb.bmin); copy_v3_v3(bb_max, node->orig_vb.bmax); } -void BLI_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count) +void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count) { if (node->proxy_count > 0) { if (proxies) *proxies = node->proxies; @@ -1437,14 +1366,14 @@ static int ray_aabb_intersect(PBVHNode *node, void *data_v) float bb_min[3], bb_max[3]; if (rcd->original) - BLI_pbvh_node_get_original_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_original_BB(node, bb_min, bb_max); else - BLI_pbvh_node_get_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_BB(node, bb_min, bb_max); return isect_ray_aabb(&rcd->ray, bb_min, bb_max, &node->tmin); } -void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data, +void BKE_pbvh_raycast(PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data, const float ray_start[3], const float ray_normal[3], int original) { @@ -1453,14 +1382,14 @@ void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data, isect_ray_aabb_initialize(&rcd.ray, ray_start, ray_normal); rcd.original = original; - BLI_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data); + BKE_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data); } -static int ray_face_intersection(const float ray_start[3], - const float ray_normal[3], - const float *t0, const float *t1, - const float *t2, const float *t3, - float *fdist) +int ray_face_intersection(const float ray_start[3], + const float ray_normal[3], + const float *t0, const float *t1, + const float *t2, const float *t3, + float *fdist) { float dist; @@ -1566,7 +1495,7 @@ static int pbvh_grids_node_raycast(PBVH *bvh, PBVHNode *node, return hit; } -int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], +int BKE_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco, const float ray_start[3], const float ray_normal[3], float *dist) { @@ -1584,6 +1513,9 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], hit |= pbvh_grids_node_raycast(bvh, node, origco, ray_start, ray_normal, dist); break; + case PBVH_BMESH: + hit = pbvh_bmesh_node_raycast(node, ray_start, ray_normal, dist, use_origco); + break; } return hit; @@ -1591,8 +1523,15 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], //#include <GL/glew.h> -void BLI_pbvh_node_draw(PBVHNode *node, void *setMaterial) +typedef struct { + DMSetMaterial setMaterial; + int wireframe; +} PBVHNodeDrawData; + +void BKE_pbvh_node_draw(PBVHNode *node, void *data_v) { + PBVHNodeDrawData *data = data_v; + #if 0 /* XXX: Just some quick code to show leaf nodes in different colors */ float col[3]; int i; @@ -1611,7 +1550,9 @@ void BLI_pbvh_node_draw(PBVHNode *node, void *setMaterial) #endif if (!(node->flag & PBVH_FullyHidden)) - GPU_draw_buffers(node->draw_buffers, setMaterial); + GPU_draw_buffers(node->draw_buffers, + data->setMaterial, + data->wireframe); } typedef enum { @@ -1654,19 +1595,19 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3], return ret; } -int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data) +int BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data) { float bb_min[3], bb_max[3]; - BLI_pbvh_node_get_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_BB(node, bb_min, bb_max); return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE; } -int BLI_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) +int BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) { float bb_min[3], bb_max[3]; - BLI_pbvh_node_get_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_BB(node, bb_min, bb_max); return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE; } @@ -1679,16 +1620,17 @@ static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node) node->flag |= PBVH_UpdateDrawBuffers; } -void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], - DMSetMaterial setMaterial) +void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], + DMSetMaterial setMaterial, int wireframe) { + PBVHNodeDrawData draw_data = {setMaterial, wireframe}; PBVHNode **nodes; int a, totnode; for (a = 0; a < bvh->totnode; a++) pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]); - BLI_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers), + BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers), &nodes, &totnode); pbvh_update_normals(bvh, nodes, totnode, face_nors); @@ -1697,15 +1639,15 @@ void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], if (nodes) MEM_freeN(nodes); if (planes) { - BLI_pbvh_search_callback(bvh, BLI_pbvh_node_planes_contain_AABB, - planes, BLI_pbvh_node_draw, setMaterial); + BKE_pbvh_search_callback(bvh, BKE_pbvh_node_planes_contain_AABB, + planes, BKE_pbvh_node_draw, &draw_data); } else { - BLI_pbvh_search_callback(bvh, NULL, NULL, BLI_pbvh_node_draw, setMaterial); + BKE_pbvh_search_callback(bvh, NULL, NULL, BKE_pbvh_node_draw, &draw_data); } } -void BLI_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces, +void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap *grid_hidden) { int a; @@ -1719,11 +1661,31 @@ void BLI_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, bvh->grid_hidden = grid_hidden; for (a = 0; a < bvh->totnode; ++a) - BLI_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]); + BKE_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]); + } +} + +/* Get the node's displacement layer, creating it if necessary */ +float *BKE_pbvh_node_layer_disp_get(PBVH *bvh, PBVHNode *node) +{ + if (!node->layer_disp) { + int totvert = 0; + BKE_pbvh_node_num_verts(bvh, node, &totvert, NULL); + node->layer_disp = MEM_callocN(sizeof(float) * totvert, "layer disp"); } + return node->layer_disp; } -float (*BLI_pbvh_get_vertCos(PBVH * pbvh))[3] +/* If the node has a displacement layer, free it and set to null */ +void BKE_pbvh_node_layer_disp_free(PBVHNode *node) +{ + if (node->layer_disp) { + MEM_freeN(node->layer_disp); + node->layer_disp = NULL; + } +} + +float (*BKE_pbvh_get_vertCos(PBVH * pbvh))[3] { int a; float (*vertCos)[3] = NULL; @@ -1732,7 +1694,7 @@ float (*BLI_pbvh_get_vertCos(PBVH * pbvh))[3] float *co; MVert *mvert = pbvh->verts; - vertCos = MEM_callocN(3 * pbvh->totvert * sizeof(float), "BLI_pbvh_get_vertCoords"); + vertCos = MEM_callocN(3 * pbvh->totvert * sizeof(float), "BKE_pbvh_get_vertCoords"); co = (float *)vertCos; for (a = 0; a < pbvh->totvert; a++, mvert++, co += 3) { @@ -1743,7 +1705,7 @@ float (*BLI_pbvh_get_vertCos(PBVH * pbvh))[3] return vertCos; } -void BLI_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) +void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) { int a; @@ -1772,21 +1734,21 @@ void BLI_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) BKE_mesh_calc_normals_tessface(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL); for (a = 0; a < pbvh->totnode; ++a) - BLI_pbvh_node_mark_update(&pbvh->nodes[a]); + BKE_pbvh_node_mark_update(&pbvh->nodes[a]); - BLI_pbvh_update(pbvh, PBVH_UpdateBB, NULL); - BLI_pbvh_update(pbvh, PBVH_UpdateOriginalBB, NULL); + BKE_pbvh_update(pbvh, PBVH_UpdateBB, NULL); + BKE_pbvh_update(pbvh, PBVH_UpdateOriginalBB, NULL); } } -int BLI_pbvh_isDeformed(PBVH *pbvh) +int BKE_pbvh_isDeformed(PBVH *pbvh) { return pbvh->deformed; } /* Proxies */ -PBVHProxyNode *BLI_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node) +PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node) { int index, totverts; @@ -1802,14 +1764,14 @@ PBVHProxyNode *BLI_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node) else node->proxies = MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy"); - BLI_pbvh_node_num_verts(bvh, node, &totverts, NULL); + BKE_pbvh_node_num_verts(bvh, node, &totverts, NULL); node->proxies[index].co = MEM_callocN(sizeof(float[3]) * totverts, "PBVHNodeProxy.co"); } return node->proxies + index; } -void BLI_pbvh_node_free_proxies(PBVHNode *node) +void BKE_pbvh_node_free_proxies(PBVHNode *node) { #pragma omp critical { @@ -1827,7 +1789,7 @@ void BLI_pbvh_node_free_proxies(PBVHNode *node) } } -void BLI_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot) +void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot) { PBVHNode **array = NULL, **newarray, *node; int tot = 0, space = 0; @@ -1840,7 +1802,7 @@ void BLI_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot) if (tot == space) { /* resize array if needed */ space = (tot == 0) ? 32 : space * 2; - newarray = MEM_callocN(sizeof(PBVHNode) * space, "BLI_pbvh_gather_proxies"); + newarray = MEM_callocN(sizeof(PBVHNode) * space, "BKE_pbvh_gather_proxies"); if (array) { memcpy(newarray, array, sizeof(PBVHNode) * tot); @@ -1877,9 +1839,9 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, vi->fno = 0; vi->mvert = 0; - BLI_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); - BLI_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); - BLI_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); + BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); + BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); + BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); vi->key = &bvh->gridkey; vi->grids = grids; @@ -1894,12 +1856,18 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, vi->vert_indices = vert_indices; vi->mverts = verts; + if (bvh->type == PBVH_BMESH) { + BLI_ghashIterator_init(&vi->bm_unique_verts, node->bm_unique_verts); + BLI_ghashIterator_init(&vi->bm_other_verts, node->bm_other_verts); + vi->bm_vdata = &bvh->bm->vdata; + } + vi->gh = NULL; if (vi->grids && mode == PBVH_ITER_UNIQUE) vi->grid_hidden = bvh->grid_hidden; vi->mask = NULL; - if (!vi->grids) + if (bvh->type == PBVH_FACES) vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK); } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c new file mode 100644 index 00000000000..791288a4dda --- /dev/null +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -0,0 +1,1414 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_buffer.h" +#include "BLI_ghash.h" +#include "BLI_heap.h" +#include "BLI_math.h" + +#include "BKE_ccg.h" +#include "BKE_DerivedMesh.h" +#include "BKE_global.h" +#include "BKE_pbvh.h" + +#include "GPU_buffers.h" + +#include "bmesh.h" +#include "pbvh_intern.h" + +#include <assert.h> + +/****************************** Building ******************************/ + +/* Update node data after splitting */ +static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index) +{ + GHashIterator gh_iter; + PBVHNode *n = &bvh->nodes[node_index]; + + /* Create vert hash sets */ + n->bm_unique_verts = BLI_ghash_ptr_new("bm_unique_verts"); + n->bm_other_verts = BLI_ghash_ptr_new("bm_other_verts"); + + BB_reset(&n->vb); + + GHASH_ITER (gh_iter, n->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BMIter bm_iter; + BMVert *v; + void *node_val = SET_INT_IN_POINTER(node_index); + + /* Update ownership of faces */ + BLI_ghash_insert(bvh->bm_face_to_node, f, node_val); + + /* Update vertices */ + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + if (!BLI_ghash_haskey(n->bm_unique_verts, v)) { + if (BLI_ghash_haskey(bvh->bm_vert_to_node, v)) { + if (!BLI_ghash_haskey(n->bm_other_verts, v)) + BLI_ghash_insert(n->bm_other_verts, v, NULL); + } + else { + BLI_ghash_insert(n->bm_unique_verts, v, NULL); + BLI_ghash_insert(bvh->bm_vert_to_node, v, node_val); + } + } + /* Update node bounding box */ + BB_expand(&n->vb, v->co); + } + } + + BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && + n->vb.bmin[1] <= n->vb.bmax[1] && + n->vb.bmin[2] <= n->vb.bmax[2]); + + n->orig_vb = n->vb; + + /* Build GPU buffers */ + if (!G.background) { + int smooth = bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING; + n->draw_buffers = GPU_build_bmesh_buffers(smooth); + n->flag |= PBVH_UpdateDrawBuffers; + } +} + +/* Recursively split the node if it exceeds the leaf_limit */ +static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) +{ + GHash *empty, *other; + GHashIterator gh_iter; + PBVHNode *n, *c1, *c2; + BB cb; + float mid; + int axis, children; + + n = &bvh->nodes[node_index]; + + if (BLI_ghash_size(n->bm_faces) <= bvh->leaf_limit) { + /* Node limit not exceeded */ + pbvh_bmesh_node_finalize(bvh, node_index); + return; + } + + /* Calculate bounding box around primitive centroids */ + BB_reset(&cb); + GHASH_ITER (gh_iter, n->bm_faces) { + const BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + const BBC *bbc = BLI_ghash_lookup(prim_bbc, f); + + BB_expand(&cb, bbc->bcentroid); + } + + /* Find widest axis and its midpoint */ + axis = BB_widest_axis(&cb); + mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f; + + /* Add two new child nodes */ + children = bvh->totnode; + n->children_offset = children; + pbvh_grow_nodes(bvh, bvh->totnode + 2); + + /* Array reallocated, update current node pointer */ + n = &bvh->nodes[node_index]; + + /* Initialize children */ + c1 = &bvh->nodes[children]; + c2 = &bvh->nodes[children + 1]; + c1->flag |= PBVH_Leaf; + c2->flag |= PBVH_Leaf; + c1->bm_faces = BLI_ghash_ptr_new("bm_faces"); + c2->bm_faces = BLI_ghash_ptr_new("bm_faces"); + + /* Partition the parent node's faces between the two children */ + GHASH_ITER (gh_iter, n->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + const BBC *bbc = BLI_ghash_lookup(prim_bbc, f); + + if (bbc->bcentroid[axis] < mid) + BLI_ghash_insert(c1->bm_faces, f, NULL); + else + BLI_ghash_insert(c2->bm_faces, f, NULL); + } + + /* Enforce at least one primitive in each node */ + empty = NULL; + if (BLI_ghash_size(c1->bm_faces) == 0) { + empty = c1->bm_faces; + other = c2->bm_faces; + } + else if (BLI_ghash_size(c2->bm_faces) == 0) { + empty = c2->bm_faces; + other = c1->bm_faces; + } + if (empty) { + GHASH_ITER (gh_iter, other) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + BLI_ghash_insert(empty, key, NULL); + BLI_ghash_remove(other, key, NULL, NULL); + break; + } + } + + /* Clear this node */ + + /* Mark this node's unique verts as unclaimed */ + if (n->bm_unique_verts) { + GHASH_ITER (gh_iter, n->bm_unique_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + BLI_ghash_remove(bvh->bm_vert_to_node, v, NULL, NULL); + } + BLI_ghash_free(n->bm_unique_verts, NULL, NULL); + } + + /* Unclaim faces */ + GHASH_ITER (gh_iter, n->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BLI_ghash_remove(bvh->bm_face_to_node, f, NULL, NULL); + } + BLI_ghash_free(n->bm_faces, NULL, NULL); + + if (n->bm_other_verts) + BLI_ghash_free(n->bm_other_verts, NULL, NULL); + + if (n->layer_disp) + MEM_freeN(n->layer_disp); + + n->bm_faces = NULL; + n->bm_unique_verts = NULL; + n->bm_other_verts = NULL; + n->layer_disp = NULL; + + if (n->draw_buffers) { + GPU_free_buffers(n->draw_buffers); + n->draw_buffers = NULL; + } + n->flag &= ~PBVH_Leaf; + + /* Recurse */ + c1 = c2 = NULL; + pbvh_bmesh_node_split(bvh, prim_bbc, children); + pbvh_bmesh_node_split(bvh, prim_bbc, children + 1); + + /* Array maybe reallocated, update current node pointer */ + n = &bvh->nodes[node_index]; + + /* Update bounding box */ + BB_reset(&n->vb); + BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb); + BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb); + n->orig_vb = n->vb; +} + +/* Recursively split the node if it exceeds the leaf_limit */ +static int pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) +{ + GHash *prim_bbc; + GHashIterator gh_iter; + + if (BLI_ghash_size(bvh->nodes[node_index].bm_faces) <= bvh->leaf_limit) { + /* Node limit not exceeded */ + return FALSE; + } + + /* For each BMFace, store the AABB and AABB centroid */ + prim_bbc = BLI_ghash_ptr_new("prim_bbc"); + + GHASH_ITER (gh_iter, bvh->nodes[node_index].bm_faces) { + BMIter bm_iter; + BMVert *v; + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BBC *bbc = MEM_callocN(sizeof(BBC), "BBC"); + + BB_reset((BB *)bbc); + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + BB_expand((BB *)bbc, v->co); + } + BBC_update_centroid(bbc); + + BLI_ghash_insert(prim_bbc, f, bbc); + } + + pbvh_bmesh_node_split(bvh, prim_bbc, node_index); + + BLI_ghash_free(prim_bbc, NULL, (void *)MEM_freeN); + + return TRUE; +} + +/**********************************************************************/ + +static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, GHash *map, void *key) +{ + int node_index; + + BLI_assert(BLI_ghash_haskey(map, key)); + + node_index = GET_INT_FROM_POINTER(BLI_ghash_lookup(map, key)); + BLI_assert(node_index < bvh->totnode); + + return &bvh->nodes[node_index]; +} + +static BMVert *pbvh_bmesh_vert_create(PBVH *bvh, int node_index, + const float co[3], + const BMVert *example) +{ + BMVert *v = BM_vert_create(bvh->bm, co, example, 0); + void *val = SET_INT_IN_POINTER(node_index); + + BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode); + + BLI_ghash_insert(bvh->nodes[node_index].bm_unique_verts, v, NULL); + BLI_ghash_insert(bvh->bm_vert_to_node, v, val); + + /* Log the new vertex */ + BM_log_vert_added(bvh->bm, bvh->bm_log, v); + + return v; +} + +static BMFace *pbvh_bmesh_face_create(PBVH *bvh, int node_index, BMVert *v1, + BMVert *v2, BMVert *v3, + const BMFace *UNUSED(example)) +{ + BMFace *f; + void *val = SET_INT_IN_POINTER(node_index); + + /* Note: passing NULL for the 'example' parameter, profiling shows + * a small performance bump */ + f = BM_face_create_quad_tri(bvh->bm, v1, v2, v3, NULL, NULL, TRUE); + if (!BLI_ghash_haskey(bvh->bm_face_to_node, f)) { + + BLI_ghash_insert(bvh->nodes[node_index].bm_faces, f, NULL); + BLI_ghash_insert(bvh->bm_face_to_node, f, val); + + /* Log the new face */ + BM_log_face_added(bvh->bm_log, f); + } + + return f; +} + +/* Return the number of faces in 'node' that use vertex 'v' */ +static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v) +{ + BMIter bm_iter; + BMFace *f; + int count = 0; + + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + PBVHNode *f_node; + + f_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); + + if (f_node == node) + count++; + } + + return count; +} + +/* Return a node that uses vertex 'v' other than its current owner */ +static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v) +{ + BMIter bm_iter; + BMFace *f; + PBVHNode *current_node; + + current_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v); + + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + PBVHNode *f_node; + + f_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); + + if (f_node != current_node) + return f_node; + } + + return NULL; +} + +static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner, + BMVert *v) +{ + PBVHNode *current_owner; + + current_owner = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v); + BLI_assert(current_owner != new_owner); + + /* Remove current ownership */ + BLI_ghash_remove(bvh->bm_vert_to_node, v, NULL, NULL); + BLI_ghash_remove(current_owner->bm_unique_verts, v, NULL, NULL); + + /* Set new ownership */ + BLI_ghash_insert(bvh->bm_vert_to_node, v, + SET_INT_IN_POINTER(new_owner - bvh->nodes)); + BLI_ghash_insert(new_owner->bm_unique_verts, v, NULL); + BLI_ghash_remove(new_owner->bm_other_verts, v, NULL, NULL); + BLI_assert(!BLI_ghash_haskey(new_owner->bm_other_verts, v)); +} + +static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v) +{ + PBVHNode *v_node; + BMIter bm_iter; + BMFace *f; + + BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v)); + v_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v); + BLI_ghash_remove(v_node->bm_unique_verts, v, NULL, NULL); + BLI_ghash_remove(bvh->bm_vert_to_node, v, NULL, NULL); + + /* Have to check each neighboring face's node */ + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); + + BLI_ghash_remove(f_node->bm_unique_verts, v, NULL, NULL); + BLI_ghash_remove(f_node->bm_other_verts, v, NULL, NULL); + + BLI_assert(!BLI_ghash_haskey(f_node->bm_unique_verts, v)); + BLI_assert(!BLI_ghash_haskey(f_node->bm_other_verts, v)); + } +} + +static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) +{ + PBVHNode *f_node; + BMIter bm_iter; + BMVert *v; + + f_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); + + /* Check if any of this face's vertices need to be removed + * from the node */ + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + if (pbvh_bmesh_node_vert_use_count(bvh, f_node, v) == 1) { + if (BLI_ghash_lookup(f_node->bm_unique_verts, v)) { + /* Find a different node that uses 'v' */ + PBVHNode *new_node; + + new_node = pbvh_bmesh_vert_other_node_find(bvh, v); + BLI_assert(new_node || BM_vert_face_count(v) == 1); + + if (new_node) { + pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v); + } + } + else { + /* Remove from other verts */ + BLI_ghash_remove(f_node->bm_other_verts, v, NULL, NULL); + } + } + } + + /* Remove face from node and top level */ + BLI_ghash_remove(f_node->bm_faces, f, NULL, NULL); + BLI_ghash_remove(bvh->bm_face_to_node, f, NULL, NULL); + + /* Log removed face */ + BM_log_face_removed(bvh->bm_log, f); +} + +static BMVert *bm_triangle_other_vert_find(BMFace *triangle, const BMVert *v1, + const BMVert *v2) +{ + BLI_assert(triangle->len == 3); + BLI_assert(v1 != v2); + + if (triangle->len == 3) { + BMIter iter; + BMVert *v, *other = NULL; + int found_v1 = FALSE, found_v2 = FALSE; + + BM_ITER_ELEM (v, &iter, triangle, BM_VERTS_OF_FACE) { + if (v == v1) + found_v1 = TRUE; + else if (v == v2) + found_v2 = TRUE; + else + other = v; + } + + if (found_v1 && found_v2) + return other; + } + + BLI_assert(0); + return NULL; +} + +static void pbvh_bmesh_edge_faces(BLI_Buffer *buf, BMEdge *e) +{ + BLI_buffer_resize(buf, BM_edge_face_count(e)); + BM_iter_as_array(NULL, BM_FACES_OF_EDGE, e, buf->data, buf->count); +} + +/* TODO: maybe a better way to do this, if not then this should go to + * bmesh_queries */ +static int bm_face_edge_backwards(BMFace *f, BMEdge *e) +{ + BMIter bm_iter; + BMLoop *l, *l1 = NULL, *l2 = NULL; + + BM_ITER_ELEM (l, &bm_iter, f, BM_LOOPS_OF_FACE) { + if (l->v == e->v1) + l1 = l; + else if (l->v == e->v2) + l2 = l; + } + + BLI_assert(l1 && l2); + BLI_assert(l1->next == l2 || l2->next == l1); + return l2->next == l1; +} + +static void pbvh_bmesh_node_drop_orig(PBVHNode *node) +{ + if (node->bm_orco) + MEM_freeN(node->bm_orco); + if (node->bm_ortri) + MEM_freeN(node->bm_ortri); + node->bm_orco = NULL; + node->bm_ortri = NULL; + node->bm_tot_ortri = 0; +} + +/****************************** EdgeQueue *****************************/ + +typedef struct { + Heap *heap; + const float *center; + float radius_squared; + float limit_len_squared; +} EdgeQueue; + +static int edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f) +{ + BMVert *v[3]; + float c[3]; + + /* Get closest point in triangle to sphere center */ + BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); + closest_on_tri_to_point_v3(c, q->center, v[0]->co, v[1]->co, v[2]->co); + + /* Check if triangle intersects the sphere */ + return ((len_squared_v3v3(q->center, c) <= q->radius_squared)); +} + +static void edge_queue_insert(EdgeQueue *q, BLI_mempool *pool, BMEdge *e, + float priority) +{ + BMVert **pair; + + pair = BLI_mempool_alloc(pool); + pair[0] = e->v1; + pair[1] = e->v2; + BLI_heap_insert(q->heap, priority, pair); +} + +static void long_edge_queue_edge_add(EdgeQueue *q, BLI_mempool *pool, + BMEdge *e) +{ + const float len_sq = BM_edge_calc_length_squared(e); + if (len_sq > q->limit_len_squared) + edge_queue_insert(q, pool, e, 1.0f / len_sq); +} + +static void short_edge_queue_edge_add(EdgeQueue *q, BLI_mempool *pool, + BMEdge *e) +{ + const float len_sq = BM_edge_calc_length_squared(e); + if (len_sq < q->limit_len_squared) + edge_queue_insert(q, pool, e, len_sq); +} + +static int long_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, + BMFace *f) +{ + BMIter bm_iter; + BMEdge *e; + + if (edge_queue_tri_in_sphere(q, f)) { + /* Check each edge of the face */ + BM_ITER_ELEM (e, &bm_iter, f, BM_EDGES_OF_FACE) { + long_edge_queue_edge_add(q, pool, e); + } + } + + return TRUE; +} + +static int short_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, + BMFace *f) +{ + BMIter bm_iter; + BMEdge *e; + + if (edge_queue_tri_in_sphere(q, f)) { + /* Check each edge of the face */ + BM_ITER_ELEM (e, &bm_iter, f, BM_EDGES_OF_FACE) { + short_edge_queue_edge_add(q, pool, e); + } + } + + return TRUE; +} + +/* Create a priority queue containing vertex pairs connected by a long + * edge as defined by PBVH.bm_max_edge_len. + * + * Only nodes marked for topology update are checked, and in those + * nodes only edges used by a face intersecting the (center, radius) + * sphere are checked. + * + * The highest priority (lowest number) is given to the longest edge. + */ +static void long_edge_queue_create(EdgeQueue *q, BLI_mempool *pool, + PBVH *bvh, const float center[3], + float radius) +{ + int n; + + q->heap = BLI_heap_new(); + q->center = center; + q->radius_squared = radius * radius; + q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len; + + for (n = 0; n < bvh->totnode; n++) { + PBVHNode *node = &bvh->nodes[n]; + + /* Check leaf nodes marked for topology update */ + if ((node->flag & PBVH_Leaf) && + (node->flag & PBVH_UpdateTopology)) + { + GHashIterator gh_iter; + + /* Check each face */ + GHASH_ITER (gh_iter, node->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + long_edge_queue_face_add(q, pool, f); + } + } + } +} + +/* Create a priority queue containing vertex pairs connected by a + * short edge as defined by PBVH.bm_min_edge_len. + * + * Only nodes marked for topology update are checked, and in those + * nodes only edges used by a face intersecting the (center, radius) + * sphere are checked. + * + * The highest priority (lowest number) is given to the shortest edge. + */ +static void short_edge_queue_create(EdgeQueue *q, BLI_mempool *pool, + PBVH *bvh, const float center[3], + float radius) +{ + int n; + + q->heap = BLI_heap_new(); + q->center = center; + q->radius_squared = radius * radius; + q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; + + for (n = 0; n < bvh->totnode; n++) { + PBVHNode *node = &bvh->nodes[n]; + + /* Check leaf nodes marked for topology update */ + if ((node->flag & PBVH_Leaf) && + (node->flag & PBVH_UpdateTopology)) + { + GHashIterator gh_iter; + + /* Check each face */ + GHASH_ITER (gh_iter, node->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + short_edge_queue_face_add(q, pool, f); + } + } + } +} + +/*************************** Topology update **************************/ + +static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, + BMEdge *e, BLI_Buffer *edge_faces) +{ + BMVert *v_new; + float mid[3]; + int i, node_index; + + /* Get all faces adjacent to the edge */ + pbvh_bmesh_edge_faces(edge_faces, e); + + /* Create a new vertex in current node at the edge's midpoint */ + mid_v3_v3v3(mid, e->v1->co, e->v2->co); + + node_index = GET_INT_FROM_POINTER(BLI_ghash_lookup(bvh->bm_vert_to_node, + e->v1)); + v_new = pbvh_bmesh_vert_create(bvh, node_index, mid, e->v1); + + /* For each face, add two new triangles and delete the original */ + for (i = 0; i < edge_faces->count; i++) { + BMFace *f_adj = BLI_buffer_at(edge_faces, BMFace *, i); + BMFace *f_new; + BMVert *opp, *v1, *v2; + void *nip; + int ni; + + BLI_assert(f_adj->len == 3); + nip = BLI_ghash_lookup(bvh->bm_face_to_node, f_adj); + ni = GET_INT_FROM_POINTER(nip); + + /* Ensure node gets redrawn */ + bvh->nodes[ni].flag |= PBVH_UpdateDrawBuffers; + + /* Find the vertex not in the edge */ + opp = bm_triangle_other_vert_find(f_adj, e->v1, e->v2); + + /* Get e->v1 and e->v2 in the order they appear in the + * existing face so that the new faces' winding orders + * match */ + v1 = e->v1; + v2 = e->v2; + if (bm_face_edge_backwards(f_adj, e)) + SWAP(BMVert *, v1, v2); + + if (ni != node_index && i == 0) + pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new); + + /* Create two new faces */ + f_new = pbvh_bmesh_face_create(bvh, ni, v1, v_new, opp, f_adj); + long_edge_queue_face_add(q, pool, f_new); + f_new = pbvh_bmesh_face_create(bvh, ni, v_new, v2, opp, f_adj); + long_edge_queue_face_add(q, pool, f_new); + + /* Delete original */ + pbvh_bmesh_face_remove(bvh, f_adj); + BM_face_kill(bvh->bm, f_adj); + + /* Ensure new vertex is in the node */ + if (!BLI_ghash_haskey(bvh->nodes[ni].bm_unique_verts, v_new) && + !BLI_ghash_haskey(bvh->nodes[ni].bm_other_verts, v_new)) + { + BLI_ghash_insert(bvh->nodes[ni].bm_other_verts, v_new, NULL); + } + + if (BM_vert_edge_count(opp) >= 9) { + BMIter bm_iter; + BMEdge *e2; + + BM_ITER_ELEM (e2, &bm_iter, opp, BM_EDGES_OF_VERT) { + long_edge_queue_edge_add(q, pool, e2); + } + } + } + + BM_edge_kill(bvh->bm, e); +} + +static int pbvh_bmesh_subdivide_long_edges(PBVH *bvh, EdgeQueue *q, + BLI_mempool *pool, + BLI_Buffer *edge_faces) +{ + int any_subdivided = FALSE; + + while (!BLI_heap_is_empty(q->heap)) { + BMVert **pair = BLI_heap_popmin(q->heap); + BMEdge *e; + + /* Check that the edge still exists */ + if (!(e = BM_edge_exists(pair[0], pair[1]))) { + BLI_mempool_free(pool, pair); + continue; + } + + BLI_mempool_free(pool, pair); + pair = NULL; + + /* Check that the edge's vertices are still in the PBVH. It's + * possible that an edge collapse has deleted adjacent faces + * and the node has been split, thus leaving wire edges and + * associated vertices. */ + if (!BLI_ghash_haskey(bvh->bm_vert_to_node, e->v1) || + !BLI_ghash_haskey(bvh->bm_vert_to_node, e->v2)) + { + continue; + } + + if (BM_edge_calc_length_squared(e) <= q->limit_len_squared) + continue; + + any_subdivided = TRUE; + + pbvh_bmesh_split_edge(bvh, q, pool, e, edge_faces); + } + + return any_subdivided; +} + +static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1, + BMVert *v2, GHash *deleted_verts, + BLI_Buffer *edge_faces, + BLI_Buffer *deleted_faces) +{ + BMIter bm_iter; + BMFace *f; + int i; + + /* Get all faces adjacent to the edge */ + pbvh_bmesh_edge_faces(edge_faces, e); + + /* Remove the merge vertex from the PBVH */ + pbvh_bmesh_vert_remove(bvh, v2); + + /* Remove all faces adjacent to the edge */ + for (i = 0; i < edge_faces->count; i++) { + BMFace *f_adj = BLI_buffer_at(edge_faces, BMFace *, i); + + pbvh_bmesh_face_remove(bvh, f_adj); + BM_face_kill(bvh->bm, f_adj); + } + + /* Kill the edge */ + BLI_assert(BM_edge_face_count(e) == 0); + BM_edge_kill(bvh->bm, e); + + /* For all remaining faces of v2, create a new face that is the + same except it uses v1 instead of v2 */ + /* Note: this could be done with BM_vert_splice(), but that + * requires handling other issues like duplicate edges, so doesn't + * really buy anything. */ + deleted_faces->count = 0; + BM_ITER_ELEM (f, &bm_iter, v2, BM_FACES_OF_VERT) { + BMVert *v[3]; + BMFace *existing_face; + PBVHNode *n; + int ni; + + /* Get vertices, replace use of v2 with v1 */ + BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); + for (i = 0; i < 3; i++) { + if (v[i] == v2) + v[i] = v1; + } + + /* Check if a face using these vertices already exists. If so, + * skip adding this face and mark the existing one for + * deletion as well. Prevents extraneous "flaps" from being + * created. */ + if (BM_face_exists(v, 3, &existing_face)) { + BLI_assert(existing_face); + BLI_buffer_append(deleted_faces, BMFace *, existing_face); + } + else { + n = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); + ni = n - bvh->nodes; + pbvh_bmesh_face_create(bvh, ni, v[0], v[1], v[2], f); + + /* Ensure that v1 is in the new face's node */ + if (!BLI_ghash_haskey(n->bm_unique_verts, v1) && + !BLI_ghash_haskey(n->bm_other_verts, v1)) { + BLI_ghash_insert(n->bm_other_verts, v1, NULL); + } + } + + BLI_buffer_append(deleted_faces, BMFace *, f); + } + + /* Delete the tagged faces */ + for (i = 0; i < deleted_faces->count; i++) { + BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i); + BMVert *v[3]; + int j; + + BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f_del, (void **)v, 3); + + /* Check if any of the face's vertices are now unused, if so + remove them from the PBVH */ + for (j = 0; j < 3; j++) { + if (v[j] != v2 && BM_vert_face_count(v[j]) == 0) { + BLI_ghash_insert(deleted_verts, v[j], NULL); + pbvh_bmesh_vert_remove(bvh, v[j]); + } + else { + v[j] = NULL; + } + } + + /* Remove the face */ + pbvh_bmesh_face_remove(bvh, f_del); + BM_face_kill(bvh->bm, f_del); + + /* Delete unused vertices */ + for (j = 0; j < 3; j++) { + if (v[j]) { + BM_log_vert_removed(bvh->bm, bvh->bm_log, v[j]); + BM_vert_kill(bvh->bm, v[j]); + } + } + } + + /* Move v1 to the midpoint of v1 and v2 */ + BM_log_vert_before_modified(bvh->bm, bvh->bm_log, v1); + mid_v3_v3v3(v1->co, v1->co, v2->co); + + /* Delete v2 */ + BLI_assert(BM_vert_face_count(v2) == 0); + BLI_ghash_insert(deleted_verts, v2, NULL); + BM_log_vert_removed(bvh->bm, bvh->bm_log, v2); + BM_vert_kill(bvh->bm, v2); +} + +static int pbvh_bmesh_collapse_short_edges(PBVH *bvh, EdgeQueue *q, + BLI_mempool *pool, + BLI_Buffer *edge_faces, + BLI_Buffer *deleted_faces) +{ + float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; + GHash *deleted_verts; + int any_collapsed = FALSE; + + deleted_verts = BLI_ghash_ptr_new("deleted_verts"); + + while (!BLI_heap_is_empty(q->heap)) { + BMVert **pair = BLI_heap_popmin(q->heap); + BMEdge *e; + BMVert *v1, *v2; + + v1 = pair[0]; + v2 = pair[1]; + BLI_mempool_free(pool, pair); + pair = NULL; + + /* Check that the vertices/edge still exist */ + if (BLI_ghash_haskey(deleted_verts, v1) || + BLI_ghash_haskey(deleted_verts, v2) || + !(e = BM_edge_exists(v1, v2))) + { + continue; + } + + /* Check that the edge's vertices are still in the PBVH. It's + * possible that an edge collapse has deleted adjacent faces + * and the node has been split, thus leaving wire edges and + * associated vertices. */ + if (!BLI_ghash_haskey(bvh->bm_vert_to_node, e->v1) || + !BLI_ghash_haskey(bvh->bm_vert_to_node, e->v2)) + { + continue; + } + + if (BM_edge_calc_length_squared(e) >= min_len_squared) + continue; + + any_collapsed = TRUE; + + pbvh_bmesh_collapse_edge(bvh, e, v1, v2, + deleted_verts, edge_faces, + deleted_faces); + } + + BLI_ghash_free(deleted_verts, NULL, NULL); + + return any_collapsed; +} + +/************************* Called from pbvh.c *************************/ + +int pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3], + const float ray_normal[3], float *dist, + int use_original) +{ + GHashIterator gh_iter; + int hit = 0; + + if (use_original && node->bm_tot_ortri) { + int i; + for (i = 0; i < node->bm_tot_ortri; i++) { + const int *t = node->bm_ortri[i]; + hit |= ray_face_intersection(ray_start, ray_normal, + node->bm_orco[t[0]], + node->bm_orco[t[1]], + node->bm_orco[t[2]], + NULL, dist); + } + } + else { + GHASH_ITER (gh_iter, node->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + BLI_assert(f->len == 3); + if (f->len == 3) { + BMVert *v[3]; + + BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); + hit |= ray_face_intersection(ray_start, ray_normal, + v[0]->co, + v[1]->co, + v[2]->co, + NULL, dist); + } + } + } + + return hit; +} + +void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode) +{ + int n; + + for (n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, node->bm_faces) { + BM_face_normal_update(BLI_ghashIterator_getKey(&gh_iter)); + } + GHASH_ITER (gh_iter, node->bm_unique_verts) { + BM_vert_normal_update(BLI_ghashIterator_getKey(&gh_iter)); + } + } +} + +/***************************** Public API *****************************/ + +/* Build a PBVH from a BMesh */ +void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, int smooth_shading, + BMLog *log) +{ + BMIter iter; + BMFace *f; + PBVHNode *n; + int node_index = 0; + + bvh->bm = bm; + + BKE_pbvh_bmesh_detail_size_set(bvh, 0.75); + + bvh->type = PBVH_BMESH; + bvh->bm_face_to_node = BLI_ghash_ptr_new("bm_face_to_node"); + bvh->bm_vert_to_node = BLI_ghash_ptr_new("bm_vert_to_node"); + bvh->bm_log = log; + + /* TODO: choose leaf limit better */ + bvh->leaf_limit = 100; + + if (smooth_shading) + bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING; + + /* Start with all faces in the root node */ + n = bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode"); + bvh->totnode = 1; + n->flag = PBVH_Leaf; + n->bm_faces = BLI_ghash_ptr_new("bm_faces"); + BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) { + BLI_ghash_insert(n->bm_faces, f, NULL); + } + + /* Recursively split the node until it is under the limit; if no + * splitting occurs then finalize the existing leaf node */ + if (!pbvh_bmesh_node_limit_ensure(bvh, node_index)) + pbvh_bmesh_node_finalize(bvh, 0); +} + +/* Collapse short edges, subdivide long edges */ +int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, + const float center[3], float radius) +{ + BLI_buffer_declare_static(BMFace *, edge_faces, BLI_BUFFER_NOP, 8); + BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32); + + int modified = FALSE; + int n; + + if (mode & PBVH_Collapse) { + EdgeQueue q; + BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert) * 2, + 128, 128, 0); + short_edge_queue_create(&q, queue_pool, bvh, center, radius); + pbvh_bmesh_collapse_short_edges(bvh, &q, queue_pool, &edge_faces, + &deleted_faces); + BLI_heap_free(q.heap, NULL); + BLI_mempool_destroy(queue_pool); + } + + if (mode & PBVH_Subdivide) { + EdgeQueue q; + BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert) * 2, + 128, 128, 0); + long_edge_queue_create(&q, queue_pool, bvh, center, radius); + pbvh_bmesh_subdivide_long_edges(bvh, &q, queue_pool, &edge_faces); + BLI_heap_free(q.heap, NULL); + BLI_mempool_destroy(queue_pool); + } + + /* Unmark nodes */ + for (n = 0; n < bvh->totnode; n++) { + PBVHNode *node = &bvh->nodes[n]; + + if (node->flag & PBVH_Leaf && + node->flag & PBVH_UpdateTopology) + { + node->flag &= ~PBVH_UpdateTopology; + } + } + BLI_buffer_free(&edge_faces); + BLI_buffer_free(&deleted_faces); + + return modified; +} + +/* In order to perform operations on the original node coordinates + * (such as raycast), store the node's triangles and vertices.*/ +void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node) +{ + GHashIterator gh_iter; + int i, totvert, tottri; + + /* Skip if original coords/triangles are already saved */ + if (node->bm_orco) + return; + + totvert = (BLI_ghash_size(node->bm_unique_verts) + + BLI_ghash_size(node->bm_other_verts)); + + tottri = BLI_ghash_size(node->bm_faces); + + node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, AT); + node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, AT); + + /* Copy out the vertices and assign a temporary index */ + i = 0; + GHASH_ITER (gh_iter, node->bm_unique_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + copy_v3_v3(node->bm_orco[i], v->co); + BM_elem_index_set(v, i); /* set_dirty! */ + i++; + } + GHASH_ITER (gh_iter, node->bm_other_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + copy_v3_v3(node->bm_orco[i], v->co); + BM_elem_index_set(v, i); /* set_dirty! */ + i++; + } + + /* Copy the triangles */ + i = 0; + GHASH_ITER (gh_iter, node->bm_faces) { + BMIter bm_iter; + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BMVert *v; + int j = 0; + + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + node->bm_ortri[i][j] = BM_elem_index_get(v); + j++; + } + i++; + } + node->bm_tot_ortri = i; +} + +void BKE_pbvh_bmesh_after_stroke(PBVH *bvh) +{ + int i; + for (i = 0; i < bvh->totnode; i++) { + PBVHNode *n = &bvh->nodes[i]; + if (n->flag & PBVH_Leaf) { + /* Free orco/ortri data */ + pbvh_bmesh_node_drop_orig(n); + + /* Recursively split nodes that have gotten too many + * elements */ + pbvh_bmesh_node_limit_ensure(bvh, i); + } + } +} + +void BKE_pbvh_bmesh_detail_size_set(PBVH *bvh, float detail_size) +{ + bvh->bm_max_edge_len = detail_size; + bvh->bm_min_edge_len = bvh->bm_max_edge_len * 0.4f; +} + +void BKE_pbvh_node_mark_topology_update(PBVHNode *node) +{ + node->flag |= PBVH_UpdateTopology; +} + +GHash *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node) +{ + return node->bm_unique_verts; +} + +GHash *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node) +{ + return node->bm_other_verts; +} + +/****************************** Debugging *****************************/ + +#if 0 +void bli_ghash_duplicate_key_check(GHash *gh) +{ + GHashIterator gh_iter1, gh_iter2; + + GHASH_ITER (gh_iter1, gh) { + void *key1 = BLI_ghashIterator_getKey(&gh_iter1); + int dup = -1; + + GHASH_ITER (gh_iter2, gh) { + void *key2 = BLI_ghashIterator_getKey(&gh_iter2); + + if (key1 == key2) { + dup++; + if (dup > 0) { + BLI_assert(!"duplicate in hash"); + } + } + } + } +} + +void bmesh_print(BMesh *bm) +{ + BMIter iter, siter; + BMVert *v; + BMEdge *e; + BMFace *f; + BMLoop *l; + + fprintf(stderr, "\nbm=%p, totvert=%d, totedge=%d, " + "totloop=%d, totface=%d\n", + bm, bm->totvert, bm->totedge, + bm->totloop, bm->totface); + + fprintf(stderr, "vertices:\n"); + BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { + fprintf(stderr, " %d co=(%.3f %.3f %.3f) oflag=%x\n", + BM_elem_index_get(v), v->co[0], v->co[1], v->co[2], + v->oflags[bm->stackdepth - 1].f); + } + + fprintf(stderr, "edges:\n"); + BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { + fprintf(stderr, " %d v1=%d, v2=%d, oflag=%x\n", + BM_elem_index_get(e), + BM_elem_index_get(e->v1), + BM_elem_index_get(e->v2), + e->oflags[bm->stackdepth - 1].f); + } + + fprintf(stderr, "faces:\n"); + BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) { + fprintf(stderr, " %d len=%d, oflag=%x\n", + BM_elem_index_get(f), f->len, + f->oflags[bm->stackdepth - 1].f); + + fprintf(stderr, " v: "); + BM_ITER_ELEM(v, &siter, f, BM_VERTS_OF_FACE) { + fprintf(stderr, "%d ", BM_elem_index_get(v)); + } + fprintf(stderr, "\n"); + + fprintf(stderr, " e: "); + BM_ITER_ELEM(e, &siter, f, BM_EDGES_OF_FACE) { + fprintf(stderr, "%d ", BM_elem_index_get(e)); + } + fprintf(stderr, "\n"); + + fprintf(stderr, " l: "); + BM_ITER_ELEM(l, &siter, f, BM_LOOPS_OF_FACE) { + fprintf(stderr, "%d(v=%d, e=%d) ", + BM_elem_index_get(l), + BM_elem_index_get(l->v), + BM_elem_index_get(l->e)); + } + fprintf(stderr, "\n"); + } +} + +void pbvh_bmesh_print(PBVH *bvh) +{ + GHashIterator gh_iter; + int n; + + fprintf(stderr, "\npbvh=%p\n", bvh); + fprintf(stderr, "bm_face_to_node:\n"); + GHASH_ITER (gh_iter, bvh->bm_face_to_node) { + fprintf(stderr, " %d -> %d\n", + BM_elem_index_get((BMFace*)BLI_ghashIterator_getKey(&gh_iter)), + GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter))); + } + + fprintf(stderr, "bm_vert_to_node:\n"); + GHASH_ITER (gh_iter, bvh->bm_vert_to_node) { + fprintf(stderr, " %d -> %d\n", + BM_elem_index_get((BMVert*)BLI_ghashIterator_getKey(&gh_iter)), + GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter))); + } + + for (n = 0; n < bvh->totnode; n++) { + PBVHNode *node = &bvh->nodes[n]; + if (!(node->flag & PBVH_Leaf)) + continue; + + fprintf(stderr, "node %d\n faces:\n", n); + GHASH_ITER (gh_iter, node->bm_faces) + fprintf(stderr, " %d\n", + BM_elem_index_get((BMFace*)BLI_ghashIterator_getKey(&gh_iter))); + fprintf(stderr, " unique verts:\n"); + GHASH_ITER (gh_iter, node->bm_unique_verts) + fprintf(stderr, " %d\n", + BM_elem_index_get((BMVert*)BLI_ghashIterator_getKey(&gh_iter))); + fprintf(stderr, " other verts:\n"); + GHASH_ITER (gh_iter, node->bm_other_verts) + fprintf(stderr, " %d\n", + BM_elem_index_get((BMVert*)BLI_ghashIterator_getKey(&gh_iter))); + } +} + +void print_flag_factors(int flag) +{ + int i; + printf("flag=0x%x:\n", flag); + for (i = 0; i < 32; i++) { + if (flag & (1 << i)) { + printf(" %d (1 << %d)\n", 1 << i, i); + } + } +} + +void pbvh_bmesh_verify(PBVH *bvh) +{ + GHashIterator gh_iter; + int i; + + /* Check faces */ + BLI_assert(bvh->bm->totface == BLI_ghash_size(bvh->bm_face_to_node)); + GHASH_ITER (gh_iter, bvh->bm_face_to_node) { + BMIter bm_iter; + BMVert *v; + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + void *nip = BLI_ghashIterator_getValue(&gh_iter); + int ni = GET_INT_FROM_POINTER(nip); + PBVHNode *n = &bvh->nodes[ni]; + + /* Check that the face's node is a leaf */ + BLI_assert(n->flag & PBVH_Leaf); + + /* Check that the face's node knows it owns the face */ + BLI_assert(BLI_ghash_haskey(n->bm_faces, f)); + + /* Check the face's vertices... */ + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + PBVHNode *nv; + + /* Check that the vertex is in the node */ + BLI_assert(BLI_ghash_haskey(n->bm_unique_verts, v) ^ + BLI_ghash_haskey(n->bm_other_verts, v)); + + /* Check that the vertex has a node owner */ + nv = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v); + + /* Check that the vertex's node knows it owns the vert */ + BLI_assert(BLI_ghash_haskey(nv->bm_unique_verts, v)); + + /* Check that the vertex isn't duplicated as an 'other' vert */ + BLI_assert(!BLI_ghash_haskey(nv->bm_other_verts, v)); + } + } + + /* Check verts */ + BLI_assert(bvh->bm->totvert == BLI_ghash_size(bvh->bm_vert_to_node)); + GHASH_ITER (gh_iter, bvh->bm_vert_to_node) { + BMIter bm_iter; + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + BMFace *f; + void *nip = BLI_ghashIterator_getValue(&gh_iter); + int ni = GET_INT_FROM_POINTER(nip); + PBVHNode *n = &bvh->nodes[ni]; + int found; + + /* Check that the vert's node is a leaf */ + BLI_assert(n->flag & PBVH_Leaf); + + /* Check that the vert's node knows it owns the vert */ + BLI_assert(BLI_ghash_haskey(n->bm_unique_verts, v)); + + /* Check that the vertex isn't duplicated as an 'other' vert */ + BLI_assert(!BLI_ghash_haskey(n->bm_other_verts, v)); + + /* Check that the vert's node also contains one of the vert's + * adjacent faces */ + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + if (BLI_ghash_lookup(bvh->bm_face_to_node, f) == nip) { + found = TRUE; + break; + } + } + BLI_assert(found); + } + + /* Check that node elements are recorded in the top level */ + for (i = 0; i < bvh->totnode; i++) { + PBVHNode *n = &bvh->nodes[i]; + if (n->flag & PBVH_Leaf) { + /* Check for duplicate entries */ + /* Slow */ + #if 0 + bli_ghash_duplicate_key_check(n->bm_faces); + bli_ghash_duplicate_key_check(n->bm_unique_verts); + bli_ghash_duplicate_key_check(n->bm_other_verts); + #endif + + GHASH_ITER (gh_iter, n->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + void *nip = BLI_ghash_lookup(bvh->bm_face_to_node, f); + BLI_assert(BLI_ghash_haskey(bvh->bm_face_to_node, f)); + BLI_assert(GET_INT_FROM_POINTER(nip) == (n - bvh->nodes)); + } + + GHASH_ITER (gh_iter, n->bm_unique_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + void *nip = BLI_ghash_lookup(bvh->bm_vert_to_node, v); + BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v)); + BLI_assert(!BLI_ghash_haskey(n->bm_other_verts, v)); + BLI_assert(GET_INT_FROM_POINTER(nip) == (n - bvh->nodes)); + } + + GHASH_ITER (gh_iter, n->bm_other_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v)); + BLI_assert(BM_vert_face_count(v) > 0); + } + } + } +} + +#endif diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h new file mode 100644 index 00000000000..b3f7bf6e3d1 --- /dev/null +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -0,0 +1,186 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __PBVH_INTERN_H__ +#define __PBVH_INTERN_H__ + +/* Axis-aligned bounding box */ +typedef struct { + float bmin[3], bmax[3]; +} BB; + +/* Axis-aligned bounding box with centroid */ +typedef struct { + float bmin[3], bmax[3], bcentroid[3]; +} BBC; + +/* Note: this structure is getting large, might want to split it into + * union'd structs */ +struct PBVHNode { + /* Opaque handle for drawing code */ + struct GPU_Buffers *draw_buffers; + + /* Voxel bounds */ + BB vb; + BB orig_vb; + + /* For internal nodes, the offset of the children in the PBVH + * 'nodes' array. */ + int children_offset; + + /* Pointer into the PBVH prim_indices array and the number of + * primitives used by this leaf node. + * + * Used for leaf nodes in both mesh- and multires-based PBVHs. + */ + int *prim_indices; + unsigned int totprim; + + /* Array of indices into the mesh's MVert array. Contains the + * indices of all vertices used by faces that are within this + * node's bounding box. + * + * Note that a vertex might be used by a multiple faces, and + * these faces might be in different leaf nodes. Such a vertex + * will appear in the vert_indices array of each of those leaf + * nodes. + * + * In order to support cases where you want access to multiple + * nodes' vertices without duplication, the vert_indices array + * is ordered such that the first part of the array, up to + * index 'uniq_verts', contains "unique" vertex indices. These + * vertices might not be truly unique to this node, but if + * they appear in another node's vert_indices array, they will + * be above that node's 'uniq_verts' value. + * + * Used for leaf nodes in a mesh-based PBVH (not multires.) + */ + int *vert_indices; + unsigned int uniq_verts, face_verts; + + /* An array mapping face corners into the vert_indices + * array. The array is sized to match 'totprim', and each of + * the face's corners gets an index into the vert_indices + * array, in the same order as the corners in the original + * MFace. The fourth value should not be used if the original + * face is a triangle. + * + * Used for leaf nodes in a mesh-based PBVH (not multires.) + */ + int (*face_vert_indices)[4]; + + /* Indicates whether this node is a leaf or not; also used for + * marking various updates that need to be applied. */ + PBVHNodeFlags flag : 16; + + /* Used for raycasting: how close bb is to the ray point. */ + float tmin; + + /* Scalar displacements for sculpt mode's layer brush. */ + float *layer_disp; + + int proxy_count; + PBVHProxyNode *proxies; + + /* Dyntopo */ + GHash *bm_faces; + GHash *bm_unique_verts; + GHash *bm_other_verts; + float (*bm_orco)[3]; + int (*bm_ortri)[3]; + int bm_tot_ortri; +}; + +typedef enum { + PBVH_DYNTOPO_SMOOTH_SHADING = 1 +} PBVHFlags; + +typedef struct PBVHBMeshLog PBVHBMeshLog; + +struct PBVH { + PBVHType type; + PBVHFlags flags; + + PBVHNode *nodes; + int node_mem_count, totnode; + + int *prim_indices; + int totprim; + int totvert; + + int leaf_limit; + + /* Mesh data */ + MVert *verts; + MFace *faces; + CustomData *vdata; + + /* Grid Data */ + CCGKey gridkey; + CCGElem **grids; + DMGridAdjacency *gridadj; + void **gridfaces; + const DMFlagMat *grid_flag_mats; + int totgrid; + BLI_bitmap *grid_hidden; + + /* Only used during BVH build and update, + * don't need to remain valid after */ + BLI_bitmap vert_bitmap; + +#ifdef PERFCNTRS + int perf_modified; +#endif + + /* flag are verts/faces deformed */ + int deformed; + + int show_diffuse_color; + + /* Dynamic topology */ + BMesh *bm; + GHash *bm_face_to_node; + GHash *bm_vert_to_node; + float bm_max_edge_len; + float bm_min_edge_len; + + struct BMLog *bm_log; +}; + +/* pbvh.c */ +void BB_reset(BB *bb); +void BB_expand(BB *bb, const float co[3]); +void BB_expand_with_bb(BB *bb, BB *bb2); +void BBC_update_centroid(BBC *bbc); +int BB_widest_axis(const BB *bb); +void pbvh_grow_nodes(PBVH *bvh, int totnode); +int ray_face_intersection(const float ray_start[3], const float ray_normal[3], + const float *t0, const float *t1, const float *t2, + const float *t3, float *fdist); +void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag); + +/* pbvh_bmesh.c */ +int pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3], + const float ray_normal[3], float *dist, + int use_original); + +void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode); + +#endif diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 2eadfe73858..9c3c1b0e508 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1540,7 +1540,7 @@ void BKE_ptcache_mem_pointers_incr(PTCacheMem *pm) for (i=0; i<BPHYS_TOT_DATA; i++) { if (pm->cur[i]) - pm->cur[i] = (char*)pm->cur[i] + ptcache_data_size[i]; + pm->cur[i] = (char *)pm->cur[i] + ptcache_data_size[i]; } } int BKE_ptcache_mem_pointers_seek(int point_index, PTCacheMem *pm) @@ -1558,7 +1558,7 @@ int BKE_ptcache_mem_pointers_seek(int point_index, PTCacheMem *pm) } for (i=0; i<BPHYS_TOT_DATA; i++) - pm->cur[i] = data_types & (1<<i) ? (char*)pm->data[i] + index * ptcache_data_size[i] : NULL; + pm->cur[i] = data_types & (1<<i) ? (char *)pm->data[i] + index * ptcache_data_size[i] : NULL; return 1; } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 538f21ce20b..04e612d1a33 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -414,6 +414,7 @@ static Scene *scene_add(Main *bmain, const char *name) sce->r.im_format.planes = R_IMF_PLANES_RGB; sce->r.im_format.imtype = R_IMF_IMTYPE_PNG; + sce->r.im_format.depth = R_IMF_CHAN_DEPTH_8; sce->r.im_format.quality = 90; sce->r.im_format.compress = 90; diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 56fddfdaa2b..81bcdc4b06e 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -279,6 +279,7 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) } BLI_freelistN(&ar->panels); + BLI_freelistN(&ar->ui_lists); } /* not area itself */ diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 3bff209f53c..3ca04f235b8 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -156,42 +156,43 @@ static void init_alpha_over_or_under(Sequence *seq) seq->seq1 = seq2; } -static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, char *rect1, char *rect2, char *out) +static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int fac2, mfac, fac, fac4; - int xo, tempc; - char *rt1, *rt2, *rt; + float fac2, mfac, fac, fac4; + int xo; + unsigned char *cp1, *cp2, *rt; + float tempc[4], rt1[4], rt2[4]; xo = x; - rt1 = (char *) rect1; - rt2 = (char *) rect2; - rt = (char *) out; + cp1 = rect1; + cp2 = rect2; + rt = out; - fac2 = (int) (256.0f * facf0); - fac4 = (int) (256.0f * facf1); + fac2 = facf0; + fac4 = facf1; while (y--) { x = xo; while (x--) { - /* rt = rt1 over rt2 (alpha from rt1) */ + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); + fac = fac2; - mfac = 256 - ( (fac2 * rt1[3]) >> 8); + mfac = 1.0f - fac2 * rt1[3]; - if (fac == 0) *( (unsigned int *) rt) = *( (unsigned int *) rt2); - else if (mfac == 0) *( (unsigned int *) rt) = *( (unsigned int *) rt1); + if (fac <= 0.0f) *( (unsigned int *) rt) = *( (unsigned int *) cp2); + else if (mfac <= 0.0f) *( (unsigned int *) rt) = *( (unsigned int *) cp1); else { - tempc = (fac * rt1[0] + mfac * rt2[0]) >> 8; - if (tempc > 255) rt[0] = 255; else rt[0] = tempc; - tempc = (fac * rt1[1] + mfac * rt2[1]) >> 8; - if (tempc > 255) rt[1] = 255; else rt[1] = tempc; - tempc = (fac * rt1[2] + mfac * rt2[2]) >> 8; - if (tempc > 255) rt[2] = 255; else rt[2] = tempc; - tempc = (fac * rt1[3] + mfac * rt2[3]) >> 8; - if (tempc > 255) rt[3] = 255; else rt[3] = tempc; + tempc[0] = fac * rt1[0] + mfac * rt2[0]; + tempc[1] = fac * rt1[1] + mfac * rt2[1]; + tempc[2] = fac * rt1[2] + mfac * rt2[2]; + tempc[3] = fac * rt1[3] + mfac * rt2[3]; + + premul_float_to_straight_uchar(rt, tempc); } - rt1 += 4; rt2 += 4; rt += 4; + cp1 += 4; cp2 += 4; rt += 4; } if (y == 0) break; @@ -199,22 +200,23 @@ static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, ch x = xo; while (x--) { + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); + fac = fac4; - mfac = 256 - ( (fac4 * rt1[3]) >> 8); + mfac = 1.0f - (fac4 * rt1[3]); - if (fac == 0) *( (unsigned int *) rt) = *( (unsigned int *) rt2); - else if (mfac == 0) *( (unsigned int *) rt) = *( (unsigned int *) rt1); + if (fac <= 0.0f) *( (unsigned int *) rt) = *( (unsigned int *) cp2); + else if (mfac <= 0.0f) *( (unsigned int *) rt) = *( (unsigned int *) cp1); else { - tempc = (fac * rt1[0] + mfac * rt2[0]) >> 8; - if (tempc > 255) rt[0] = 255; else rt[0] = tempc; - tempc = (fac * rt1[1] + mfac * rt2[1]) >> 8; - if (tempc > 255) rt[1] = 255; else rt[1] = tempc; - tempc = (fac * rt1[2] + mfac * rt2[2]) >> 8; - if (tempc > 255) rt[2] = 255; else rt[2] = tempc; - tempc = (fac * rt1[3] + mfac * rt2[3]) >> 8; - if (tempc > 255) rt[3] = 255; else rt[3] = tempc; + tempc[0] = fac * rt1[0] + mfac * rt2[0]; + tempc[1] = fac * rt1[1] + mfac * rt2[1]; + tempc[2] = fac * rt1[2] + mfac * rt2[2]; + tempc[3] = fac * rt1[3] + mfac * rt2[3]; + + premul_float_to_straight_uchar(rt, tempc); } - rt1 += 4; rt2 += 4; rt += 4; + cp1 += 4; cp2 += 4; rt += 4; } } } @@ -298,17 +300,17 @@ static void do_alphaover_effect(SeqRenderData context, Sequence *UNUSED(seq), fl slice_get_byte_buffers(&context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaover_effect_byte(facf0, facf1, context.rectx, total_lines, (char *) rect1, (char *) rect2, (char *) rect_out); + do_alphaover_effect_byte(facf0, facf1, context.rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Alpha Under *************************/ -static void do_alphaunder_effect_byte(float facf0, float facf1, int x, int y, char *rect1, char *rect2, char *out) +static void do_alphaunder_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { int fac2, mfac, fac, fac4; int xo; - char *rt1, *rt2, *rt; + unsigned char *rt1, *rt2, *rt; xo = x; rt1 = rect1; @@ -460,17 +462,17 @@ static void do_alphaunder_effect(SeqRenderData context, Sequence *UNUSED(seq), f slice_get_byte_buffers(&context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaunder_effect_byte(facf0, facf1, context.rectx, total_lines, (char *) rect1, (char *) rect2, (char *) rect_out); + do_alphaunder_effect_byte(facf0, facf1, context.rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Cross *************************/ -static void do_cross_effect_byte(float facf0, float facf1, int x, int y, char *rect1, char *rect2, char *out) +static void do_cross_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { int fac1, fac2, fac3, fac4; int xo; - char *rt1, *rt2, *rt; + unsigned char *rt1, *rt2, *rt; xo = x; rt1 = rect1; @@ -570,7 +572,7 @@ static void do_cross_effect(SeqRenderData context, Sequence *UNUSED(seq), float slice_get_byte_buffers(&context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_cross_effect_byte(facf0, facf1, context.rectx, total_lines, (char *) rect1, (char *) rect2, (char *) rect_out); + do_cross_effect_byte(facf0, facf1, context.rectx, total_lines, rect1, rect2, rect_out); } } @@ -713,31 +715,32 @@ static void free_gammacross(Sequence *UNUSED(seq)) static void do_gammacross_effect_byte(float facf0, float UNUSED(facf1), int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int fac1, fac2, col; + float fac1, fac2; int xo; - unsigned char *rt1, *rt2, *rt; - + unsigned char *cp1, *cp2, *rt; + float rt1[4], rt2[4], tempc[4]; + xo = x; - rt1 = (unsigned char *) rect1; - rt2 = (unsigned char *) rect2; - rt = (unsigned char *) out; + cp1 = rect1; + cp2 = rect2; + rt = out; - fac2 = (int)(256.0f * facf0); - fac1 = 256 - fac2; + fac2 = facf0; + fac1 = 1.0f - fac2; while (y--) { x = xo; while (x--) { - col = (fac1 * igamtab1[rt1[0]] + fac2 * igamtab1[rt2[0]]) >> 8; - if (col > 65535) rt[0] = 255; else rt[0] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[1]] + fac2 * igamtab1[rt2[1]]) >> 8; - if (col > 65535) rt[1] = 255; else rt[1] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[2]] + fac2 * igamtab1[rt2[2]]) >> 8; - if (col > 65535) rt[2] = 255; else rt[2] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[3]] + fac2 * igamtab1[rt2[3]]) >> 8; - if (col > 65535) rt[3] = 255; else rt[3] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0])); + tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1])); + tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2])); + tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3])); + + premul_float_to_straight_uchar(rt, tempc); + cp1 += 4; cp2 += 4; rt += 4; } if (y == 0) @@ -746,16 +749,16 @@ static void do_gammacross_effect_byte(float facf0, float UNUSED(facf1), int x, x = xo; while (x--) { - col = (fac1 * igamtab1[rt1[0]] + fac2 * igamtab1[rt2[0]]) >> 8; - if (col > 65535) rt[0] = 255; else rt[0] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[1]] + fac2 * igamtab1[rt2[1]]) >> 8; - if (col > 65535) rt[1] = 255; else rt[1] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[2]] + fac2 * igamtab1[rt2[2]]) >> 8; - if (col > 65535) rt[2] = 255; else rt[2] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[3]] + fac2 * igamtab1[rt2[3]]) >> 8; - if (col > 65535) rt[3] = 255; else rt[3] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0])); + tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1])); + tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2])); + tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3])); + + premul_float_to_straight_uchar(rt, tempc); + cp1 += 4; cp2 += 4; rt += 4; } } } @@ -828,31 +831,34 @@ static void do_gammacross_effect(SeqRenderData context, Sequence *UNUSED(seq), f static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int col, xo, fac1, fac3; - char *rt1, *rt2, *rt; + int xo; + unsigned char *cp1, *cp2, *rt; + float fac1, fac3; + float tempc[4], rt1[4], rt2[4]; xo = x; - rt1 = (char *)rect1; - rt2 = (char *)rect2; - rt = (char *)out; + cp1 = rect1; + cp2 = rect2; + rt = out; - fac1 = (int)(256.0f * facf0); - fac3 = (int)(256.0f * facf1); + fac1 = facf0; + fac3 = facf1; while (y--) { x = xo; while (x--) { - col = rt1[0] + ((fac1 * rt2[0]) >> 8); - if (col > 255) rt[0] = 255; else rt[0] = col; - col = rt1[1] + ((fac1 * rt2[1]) >> 8); - if (col > 255) rt[1] = 255; else rt[1] = col; - col = rt1[2] + ((fac1 * rt2[2]) >> 8); - if (col > 255) rt[2] = 255; else rt[2] = col; - col = rt1[3] + ((fac1 * rt2[3]) >> 8); - if (col > 255) rt[3] = 255; else rt[3] = col; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = rt1[0] + fac1 * rt2[0]; + tempc[1] = rt1[1] + fac1 * rt2[1]; + tempc[2] = rt1[2] + fac1 * rt2[2]; + tempc[3] = min_ff(1.0f, rt1[3] + fac1 * rt2[3]); + + premul_float_to_straight_uchar(rt, tempc); + + cp1 += 4; cp2 += 4; rt += 4; } if (y == 0) @@ -861,16 +867,17 @@ static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned x = xo; while (x--) { - col = rt1[0] + ((fac3 * rt2[0]) >> 8); - if (col > 255) rt[0] = 255; else rt[0] = col; - col = rt1[1] + ((fac3 * rt2[1]) >> 8); - if (col > 255) rt[1] = 255; else rt[1] = col; - col = rt1[2] + ((fac3 * rt2[2]) >> 8); - if (col > 255) rt[2] = 255; else rt[2] = col; - col = rt1[3] + ((fac3 * rt2[3]) >> 8); - if (col > 255) rt[3] = 255; else rt[3] = col; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = rt1[0] + fac3 * rt2[0]; + tempc[1] = rt1[1] + fac3 * rt2[1]; + tempc[2] = rt1[2] + fac3 * rt2[2]; + tempc[3] = min_ff(1.0f, rt1[3] + fac3 * rt2[3]); + + premul_float_to_straight_uchar(rt, tempc); + + cp1 += 4; cp2 += 4; rt += 4; } } } @@ -890,22 +897,28 @@ static void do_add_effect_float(float facf0, float facf1, int x, int y, float *r fac3 = facf1; while (y--) { - x = xo * 4; + x = xo; while (x--) { - *rt = *rt1 + fac1 * (*rt2); + rt[0] = rt1[0] + fac1 * rt2[0]; + rt[1] = rt1[1] + fac1 * rt2[1]; + rt[2] = rt1[2] + fac1 * rt2[2]; + rt[3] = min_ff(1.0f, rt1[3] + fac1 * rt2[3]); - rt1++; rt2++; rt++; + rt1 += 4; rt2 += 4; rt += 4; } if (y == 0) break; y--; - x = xo * 4; + x = xo; while (x--) { - *rt = *rt1 + fac3 * (*rt2); + rt[0] = rt1[0] + fac1 * rt2[0]; + rt[1] = rt1[1] + fac1 * rt2[1]; + rt[2] = rt1[2] + fac1 * rt2[2]; + rt[3] = min_ff(1.0f, rt1[3] + fac3 * rt2[3]); - rt1++; rt2++; rt++; + rt1 += 4; rt2 += 4; rt += 4; } } } @@ -931,32 +944,35 @@ static void do_add_effect(SeqRenderData context, Sequence *UNUSED(seq), float UN /*********************** Sub *************************/ -static void do_sub_effect_byte(float facf0, float facf1, int x, int y, char *rect1, char *rect2, char *out) +static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int col, xo, fac1, fac3; - char *rt1, *rt2, *rt; + int xo; + unsigned char *cp1, *cp2, *rt; + float fac1, fac3; + float tempc[4], rt1[4], rt2[4]; xo = x; - rt1 = (char *) rect1; - rt2 = (char *) rect2; - rt = (char *) out; + cp1 = rect1; + cp2 = rect2; + rt = out; - fac1 = (int) (256.0f * facf0); - fac3 = (int) (256.0f * facf1); + fac1 = facf0; + fac3 = facf1; while (y--) { x = xo; while (x--) { - col = rt1[0] - ((fac1 * rt2[0]) >> 8); - if (col < 0) rt[0] = 0; else rt[0] = col; - col = rt1[1] - ((fac1 * rt2[1]) >> 8); - if (col < 0) rt[1] = 0; else rt[1] = col; - col = rt1[2] - ((fac1 * rt2[2]) >> 8); - if (col < 0) rt[2] = 0; else rt[2] = col; - col = rt1[3] - ((fac1 * rt2[3]) >> 8); - if (col < 0) rt[3] = 0; else rt[3] = col; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = rt1[0] - fac1 * rt2[0]; + tempc[1] = rt1[1] - fac1 * rt2[1]; + tempc[2] = rt1[2] - fac1 * rt2[2]; + tempc[3] = rt1[3] - fac1 * rt2[3]; + + premul_float_to_straight_uchar(rt, tempc); + + cp1 += 4; cp2 += 4; rt += 4; } if (y == 0) @@ -965,16 +981,17 @@ static void do_sub_effect_byte(float facf0, float facf1, int x, int y, char *rec x = xo; while (x--) { - col = rt1[0] - ((fac3 * rt2[0]) >> 8); - if (col < 0) rt[0] = 0; else rt[0] = col; - col = rt1[1] - ((fac3 * rt2[1]) >> 8); - if (col < 0) rt[1] = 0; else rt[1] = col; - col = rt1[2] - ((fac3 * rt2[2]) >> 8); - if (col < 0) rt[2] = 0; else rt[2] = col; - col = rt1[3] - ((fac3 * rt2[3]) >> 8); - if (col < 0) rt[3] = 0; else rt[3] = col; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = rt1[0] - fac3 * rt2[0]; + tempc[1] = rt1[1] - fac3 * rt2[1]; + tempc[2] = rt1[2] - fac3 * rt2[2]; + tempc[3] = rt1[3] - fac3 * rt2[3]; + + premul_float_to_straight_uchar(rt, tempc); + + cp1 += 4; cp2 += 4; rt += 4; } } } @@ -1029,7 +1046,7 @@ static void do_sub_effect(SeqRenderData context, Sequence *UNUSED(seq), float UN slice_get_byte_buffers(&context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_sub_effect_byte(facf0, facf1, context.rectx, total_lines, (char *) rect1, (char *) rect2, (char *) rect_out); + do_sub_effect_byte(facf0, facf1, context.rectx, total_lines, rect1, rect2, rect_out); } } @@ -1039,10 +1056,10 @@ static void do_sub_effect(SeqRenderData context, Sequence *UNUSED(seq), float UN #define XOFF 8 #define YOFF 8 -static void do_drop_effect_byte(float facf0, float facf1, int x, int y, char *rect2i, char *rect1i, char *outi) +static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi) { int height, width, temp, fac, fac1, fac2; - char *rt1, *rt2, *out; + unsigned char *rt1, *rt2, *out; int field = 1; width = x; @@ -1051,9 +1068,9 @@ static void do_drop_effect_byte(float facf0, float facf1, int x, int y, char *re fac1 = (int) (70.0f * facf0); fac2 = (int) (70.0f * facf1); - rt2 = (char *) (rect2i + YOFF * width); - rt1 = (char *) rect1i; - out = (char *) outi; + rt2 = (unsigned char *) (rect2i + YOFF * width); + rt1 = (unsigned char *) rect1i; + out = (unsigned char *) outi; for (y = 0; y < height - YOFF; y++) { if (field) fac = fac1; else fac = fac2; @@ -1122,12 +1139,12 @@ static void do_mul_effect_byte(float facf0, float facf1, int x, int y, unsigned unsigned char *out) { int xo, fac1, fac3; - char *rt1, *rt2, *rt; + unsigned char *rt1, *rt2, *rt; xo = x; - rt1 = (char *)rect1; - rt2 = (char *)rect2; - rt = (char *)out; + rt1 = rect1; + rt2 = rect2; + rt = out; fac1 = (int)(256.0f * facf0); fac3 = (int)(256.0f * facf1); @@ -1539,13 +1556,13 @@ static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), WipeZone wipezone; WipeVars *wipe = (WipeVars *)seq->effectdata; int xo, yo; - char *rt1, *rt2, *rt; + unsigned char *cp1, *cp2, *rt; precalc_wipe_zone(&wipezone, wipe, x, y); - rt1 = (char *)rect1; - rt2 = (char *)rect2; - rt = (char *)out; + cp1 = rect1; + cp2 = rect2; + rt = out; xo = x; yo = y; @@ -1553,11 +1570,18 @@ static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), for (x = 0; x < xo; x++) { float check = check_zone(&wipezone, x, y, seq, facf0); if (check) { - if (rt1) { - rt[0] = (int)(rt1[0] * check) + (int)(rt2[0] * (1 - check)); - rt[1] = (int)(rt1[1] * check) + (int)(rt2[1] * (1 - check)); - rt[2] = (int)(rt1[2] * check) + (int)(rt2[2] * (1 - check)); - rt[3] = (int)(rt1[3] * check) + (int)(rt2[3] * (1 - check)); + if (cp1) { + float rt1[4], rt2[4], tempc[4]; + + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); + + tempc[0] = rt1[0] * check + rt2[0] * (1 - check); + tempc[1] = rt1[1] * check + rt2[1] * (1 - check); + tempc[2] = rt1[2] * check + rt2[2] * (1 - check); + tempc[3] = rt1[3] * check + rt2[3] * (1 - check); + + premul_float_to_straight_uchar(rt, tempc); } else { rt[0] = 0; @@ -1567,11 +1591,11 @@ static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), } } else { - if (rt2) { - rt[0] = rt2[0]; - rt[1] = rt2[1]; - rt[2] = rt2[2]; - rt[3] = rt2[3]; + if (cp2) { + rt[0] = cp2[0]; + rt[1] = cp2[1]; + rt[2] = cp2[2]; + rt[3] = cp2[3]; } else { rt[0] = 0; @@ -1582,11 +1606,11 @@ static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), } rt += 4; - if (rt1 != NULL) { - rt1 += 4; + if (cp1 != NULL) { + cp1 += 4; } - if (rt2 != NULL) { - rt2 += 4; + if (cp2 != NULL) { + cp2 += 4; } } } @@ -1803,166 +1827,6 @@ static ImBuf *do_transform_effect(SeqRenderData context, Sequence *seq, float UN /*********************** Glow *************************/ -static void RVBlurBitmap2_byte(unsigned char *map, int width, int height, float blur, int quality) -/* MUUUCCH better than the previous blur. */ -/* We do the blurring in two passes which is a whole lot faster. */ -/* I changed the math arount to implement an actual Gaussian */ -/* distribution. */ -/* */ -/* Watch out though, it tends to misbehaven with large blur values on */ -/* a small bitmap. Avoid avoid avoid. */ -/*=============================== */ -{ - unsigned char *temp = NULL, *swap; - float *filter = NULL; - int x, y, i, fx, fy; - int index, ix, halfWidth; - float fval, k, curColor[3], curColor2[3], weight = 0; - - /* If we're not really blurring, bail out */ - if (blur <= 0) - return; - - /*Allocate memory for the tempmap and the blur filter matrix */ - temp = MEM_mallocN((width * height * 4), "blurbitmaptemp"); - if (!temp) - return; - - /*Allocate memory for the filter elements */ - halfWidth = ((quality + 1) * blur); - filter = (float *)MEM_mallocN(sizeof(float) * halfWidth * 2, "blurbitmapfilter"); - if (!filter) { - MEM_freeN(temp); - return; - } - - /* Apparently we're calculating a bell curve based on the standard deviation (or radius) - * This code is based on an example posted to comp.graphics.algorithms by - * Blancmange (bmange@airdmhor.gen.nz) - */ - - k = -1.0f / (2.0f * (float)M_PI * blur * blur); - for (ix = 0; ix < halfWidth; ix++) { - weight = (float)exp(k * (ix * ix)); - filter[halfWidth - ix] = weight; - filter[halfWidth + ix] = weight; - } - filter[0] = weight; - - /* Normalize the array */ - fval = 0; - for (ix = 0; ix < halfWidth * 2; ix++) - fval += filter[ix]; - - for (ix = 0; ix < halfWidth * 2; ix++) - filter[ix] /= fval; - - /* Blur the rows */ - for (y = 0; y < height; y++) { - /* Do the left & right strips */ - for (x = 0; x < halfWidth; x++) { - index = (x + y * width) * 4; - fx = 0; - zero_v3(curColor); - zero_v3(curColor2); - - for (i = x - halfWidth; i < x + halfWidth; i++) { - if ((i >= 0) && (i < width)) { - curColor[0] += map[(i + y * width) * 4 + GlowR] * filter[fx]; - curColor[1] += map[(i + y * width) * 4 + GlowG] * filter[fx]; - curColor[2] += map[(i + y * width) * 4 + GlowB] * filter[fx]; - - curColor2[0] += map[(width - 1 - i + y * width) * 4 + GlowR] * filter[fx]; - curColor2[1] += map[(width - 1 - i + y * width) * 4 + GlowG] * filter[fx]; - curColor2[2] += map[(width - 1 - i + y * width) * 4 + GlowB] * filter[fx]; - } - fx++; - } - temp[index + GlowR] = curColor[0]; - temp[index + GlowG] = curColor[1]; - temp[index + GlowB] = curColor[2]; - - temp[((width - 1 - x + y * width) * 4) + GlowR] = curColor2[0]; - temp[((width - 1 - x + y * width) * 4) + GlowG] = curColor2[1]; - temp[((width - 1 - x + y * width) * 4) + GlowB] = curColor2[2]; - - } - - /* Do the main body */ - for (x = halfWidth; x < width - halfWidth; x++) { - index = (x + y * width) * 4; - fx = 0; - zero_v3(curColor); - for (i = x - halfWidth; i < x + halfWidth; i++) { - curColor[0] += map[(i + y * width) * 4 + GlowR] * filter[fx]; - curColor[1] += map[(i + y * width) * 4 + GlowG] * filter[fx]; - curColor[2] += map[(i + y * width) * 4 + GlowB] * filter[fx]; - fx++; - } - temp[index + GlowR] = curColor[0]; - temp[index + GlowG] = curColor[1]; - temp[index + GlowB] = curColor[2]; - } - } - - /* Swap buffers */ - swap = temp; temp = map; map = swap; - - /* Blur the columns */ - for (x = 0; x < width; x++) { - /* Do the top & bottom strips */ - for (y = 0; y < halfWidth; y++) { - index = (x + y * width) * 4; - fy = 0; - zero_v3(curColor); - zero_v3(curColor2); - for (i = y - halfWidth; i < y + halfWidth; i++) { - if ((i >= 0) && (i < height)) { - /* Bottom */ - curColor[0] += map[(x + i * width) * 4 + GlowR] * filter[fy]; - curColor[1] += map[(x + i * width) * 4 + GlowG] * filter[fy]; - curColor[2] += map[(x + i * width) * 4 + GlowB] * filter[fy]; - - /* Top */ - curColor2[0] += map[(x + (height - 1 - i) * width) * 4 + GlowR] * filter[fy]; - curColor2[1] += map[(x + (height - 1 - i) * width) * 4 + GlowG] * filter[fy]; - curColor2[2] += map[(x + (height - 1 - i) * width) * 4 + GlowB] * filter[fy]; - } - fy++; - } - temp[index + GlowR] = curColor[0]; - temp[index + GlowG] = curColor[1]; - temp[index + GlowB] = curColor[2]; - temp[((x + (height - 1 - y) * width) * 4) + GlowR] = curColor2[0]; - temp[((x + (height - 1 - y) * width) * 4) + GlowG] = curColor2[1]; - temp[((x + (height - 1 - y) * width) * 4) + GlowB] = curColor2[2]; - } - - /* Do the main body */ - for (y = halfWidth; y < height - halfWidth; y++) { - index = (x + y * width) * 4; - fy = 0; - zero_v3(curColor); - for (i = y - halfWidth; i < y + halfWidth; i++) { - curColor[0] += map[(x + i * width) * 4 + GlowR] * filter[fy]; - curColor[1] += map[(x + i * width) * 4 + GlowG] * filter[fy]; - curColor[2] += map[(x + i * width) * 4 + GlowB] * filter[fy]; - fy++; - } - temp[index + GlowR] = curColor[0]; - temp[index + GlowG] = curColor[1]; - temp[index + GlowB] = curColor[2]; - } - } - - /* Swap buffers */ - swap = temp; temp = map; /* map = swap; */ /* UNUSED */ - - /* Tidy up */ - MEM_freeN(filter); - MEM_freeN(temp); -} - static void RVBlurBitmap2_float(float *map, int width, int height, float blur, int quality) /* MUUUCCH better than the previous blur. */ /* We do the blurring in two passes which is a whole lot faster. */ @@ -2124,26 +1988,6 @@ static void RVBlurBitmap2_float(float *map, int width, int height, float blur, i MEM_freeN(temp); } - -/* Adds two bitmaps and puts the results into a third map. */ -/* C must have been previously allocated but it may be A or B. */ -/* We clamp values to 255 to prevent weirdness */ -/*=============================== */ -static void RVAddBitmaps_byte(unsigned char *a, unsigned char *b, unsigned char *c, int width, int height) -{ - int x, y, index; - - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - index = (x + y * width) * 4; - c[index + GlowR] = MIN2(255, a[index + GlowR] + b[index + GlowR]); - c[index + GlowG] = MIN2(255, a[index + GlowG] + b[index + GlowG]); - c[index + GlowB] = MIN2(255, a[index + GlowB] + b[index + GlowB]); - c[index + GlowA] = MIN2(255, a[index + GlowA] + b[index + GlowA]); - } - } -} - static void RVAddBitmaps_float(float *a, float *b, float *c, int width, int height) { int x, y, index; @@ -2159,37 +2003,6 @@ static void RVAddBitmaps_float(float *a, float *b, float *c, int width, int heig } } -/* For each pixel whose total luminance exceeds the threshold, - * Multiply it's value by BOOST and add it to the output map - */ -static void RVIsolateHighlights_byte(unsigned char *in, unsigned char *out, int width, int height, int threshold, - float boost, float clamp) -{ - int x, y, index; - int intensity; - - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - index = (x + y * width) * 4; - - /* Isolate the intensity */ - intensity = (in[index + GlowR] + in[index + GlowG] + in[index + GlowB] - threshold); - if (intensity > 0) { - out[index + GlowR] = MIN2(255 * clamp, (in[index + GlowR] * boost * intensity) / 255); - out[index + GlowG] = MIN2(255 * clamp, (in[index + GlowG] * boost * intensity) / 255); - out[index + GlowB] = MIN2(255 * clamp, (in[index + GlowB] * boost * intensity) / 255); - out[index + GlowA] = MIN2(255 * clamp, (in[index + GlowA] * boost * intensity) / 255); - } - else { - out[index + GlowR] = 0; - out[index + GlowG] = 0; - out[index + GlowB] = 0; - out[index + GlowA] = 0; - } - } - } -} - static void RVIsolateHighlights_float(float *in, float *out, int width, int height, float threshold, float boost, float clamp) { int x, y, index; @@ -2254,16 +2067,27 @@ static void copy_glow_effect(Sequence *dst, Sequence *src) } static void do_glow_effect_byte(Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y, - char *rect1, char *UNUSED(rect2), char *out) + unsigned char *rect1, unsigned char *UNUSED(rect2), unsigned char *out) { - unsigned char *outbuf = (unsigned char *)out; - unsigned char *inbuf = (unsigned char *)rect1; + float *outbuf, *inbuf; GlowVars *glow = (GlowVars *)seq->effectdata; - - RVIsolateHighlights_byte(inbuf, outbuf, x, y, glow->fMini * 765, glow->fBoost * facf0, glow->fClamp); - RVBlurBitmap2_byte(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality); + + inbuf = MEM_mallocN(4 * sizeof(float) * x * y, "glow effect input"); + outbuf = MEM_mallocN(4 * sizeof(float) * x * y, "glow effect output"); + + IMB_buffer_float_from_byte(inbuf, rect1, IB_PROFILE_SRGB, IB_PROFILE_SRGB, FALSE, x, y, x, x); + IMB_buffer_float_premultiply(inbuf, x, y); + + RVIsolateHighlights_float(inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp); + RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality); if (!glow->bNoComp) - RVAddBitmaps_byte(inbuf, outbuf, outbuf, x, y); + RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y); + + IMB_buffer_float_unpremultiply(outbuf, x, y); + IMB_buffer_byte_from_float(out, outbuf, 4, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_SRGB, FALSE, x, y, x, x); + + MEM_freeN(inbuf); + MEM_freeN(outbuf); } static void do_glow_effect_float(Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y, @@ -2292,7 +2116,7 @@ static ImBuf *do_glow_effect(SeqRenderData context, Sequence *seq, float UNUSED( } else { do_glow_effect_byte(seq, render_size, facf0, facf1, context.rectx, context.recty, - (char *) ibuf1->rect, (char *) ibuf2->rect, (char *) out->rect); + (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect); } return out; @@ -2735,7 +2559,7 @@ static ImBuf *do_speed_effect(SeqRenderData context, Sequence *UNUSED(seq), floa } else { do_cross_effect_byte(facf0, facf1, context.rectx, context.recty, - (char *) ibuf1->rect, (char *) ibuf2->rect, (char *) out->rect); + (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect); } return out; } @@ -2761,8 +2585,8 @@ static void do_overdrop_effect(SeqRenderData context, Sequence *UNUSED(seq), flo slice_get_byte_buffers(&context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_drop_effect_byte(facf0, facf1, x, y, (char *) rect1, (char *) rect2, (char *) rect_out); - do_alphaover_effect_byte(facf0, facf1, x, y, (char *) rect1, (char *) rect2, (char *) rect_out); + do_drop_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out); + do_alphaover_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out); } } diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c index 5b2e9f2bf23..3d8a2f7cddf 100644 --- a/source/blender/blenkernel/intern/seqmodifier.c +++ b/source/blender/blenkernel/intern/seqmodifier.c @@ -226,24 +226,28 @@ static void curves_apply_threaded(int width, int height, unsigned char *rect, fl } if (rect) { unsigned char *pixel = rect + pixel_index; - unsigned char result[3]; + float result[3], tempc[4]; - curvemapping_evaluate_premulRGB(curve_mapping, result, pixel); + straight_uchar_to_premul_float(tempc, pixel); + + curvemapping_evaluate_premulRGBF(curve_mapping, result, tempc); if (mask_rect) { float t[3]; rgb_uchar_to_float(t, mask_rect + pixel_index); - pixel[0] = pixel[0] * (1.0f - t[0]) + result[0] * t[0]; - pixel[1] = pixel[1] * (1.0f - t[1]) + result[1] * t[1]; - pixel[2] = pixel[2] * (1.0f - t[2]) + result[2] * t[2]; + tempc[0] = pixel[0] * (1.0f - t[0]) + result[0] * t[0]; + tempc[1] = pixel[1] * (1.0f - t[1]) + result[1] * t[1]; + tempc[2] = pixel[2] * (1.0f - t[2]) + result[2] * t[2]; } else { - pixel[0] = result[0]; - pixel[1] = result[1]; - pixel[2] = result[2]; + tempc[0] = result[0]; + tempc[1] = result[1]; + tempc[2] = result[2]; } + + premul_float_to_straight_uchar(pixel, tempc); } } } diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 5e44f2d6d9e..8d010de408a 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -324,7 +324,6 @@ void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, int make_ { const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); const char *to_colorspace = scene->sequencer_colorspace_settings.name; - int predivide = ibuf->flags & IB_cm_predivide; if (!ibuf->rect_float) { if (make_float && ibuf->rect) { @@ -354,7 +353,7 @@ void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, int make_ imb_freerectImBuf(ibuf); IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, predivide); + from_colorspace, to_colorspace, TRUE); } } @@ -367,10 +366,8 @@ void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf) return; if (to_colorspace && to_colorspace[0] != '\0') { - int predivide = ibuf->flags & IB_cm_predivide; - IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, predivide); + from_colorspace, to_colorspace, TRUE); } } @@ -636,7 +633,7 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq) } } -/* note: caller should run calc_sequence(scene, seq) after */ +/* note: caller should run BKE_sequence_calc(scene, seq) after */ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, int lock_range) { char str[FILE_MAX]; @@ -1517,18 +1514,6 @@ MINLINE float color_balance_fl(float in, const float lift, const float gain, con return powf(x, gamma) * mul; } -static void make_cb_table_byte(float lift, float gain, float gamma, - unsigned char *table, float mul) -{ - int y; - - for (y = 0; y < 256; y++) { - float v = color_balance_fl((float)y * (1.0f / 255.0f), lift, gain, gamma, mul); - - table[y] = FTOCHAR(v); - } -} - static void make_cb_table_float(float lift, float gain, float gamma, float *table, float mul) { @@ -1543,35 +1528,33 @@ static void make_cb_table_float(float lift, float gain, float gamma, static void color_balance_byte_byte(StripColorBalance *cb_, unsigned char *rect, unsigned char *mask_rect, int width, int height, float mul) { - unsigned char cb_tab[3][256]; - int c; - unsigned char *p = rect; - unsigned char *e = p + width * 4 * height; + //unsigned char cb_tab[3][256]; + unsigned char *cp = rect; + unsigned char *e = cp + width * 4 * height; unsigned char *m = mask_rect; StripColorBalance cb = calc_cb(cb_); - for (c = 0; c < 3; c++) { - make_cb_table_byte(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul); - } + while (cp < e) { + float p[4]; + int c; - while (p < e) { - if (m) { - float t[3] = {m[0] / 255.0f, m[1] / 255.0f, m[2] / 255.0f}; + straight_uchar_to_premul_float(p, cp); - p[0] = p[0] * (1.0f - t[0]) + t[0] * cb_tab[0][p[0]]; - p[1] = p[1] * (1.0f - t[1]) + t[1] * cb_tab[1][p[1]]; - p[2] = p[2] * (1.0f - t[2]) + t[2] * cb_tab[2][p[2]]; + for (c = 0; c < 3; c++) { + float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul); - m += 4; - } - else { - p[0] = cb_tab[0][p[0]]; - p[1] = cb_tab[1][p[1]]; - p[2] = cb_tab[2][p[2]]; + if (m) + p[c] = p[c] * (1.0f - (float)m[c] / 255.0f) + t * m[c]; + else + p[c] = t; } - p += 4; + premul_float_to_straight_uchar(cp, p); + + cp += 4; + if (m) + m += 4; } } @@ -1795,7 +1778,7 @@ int BKE_sequencer_input_have_to_preprocess(SeqRenderData UNUSED(context), Sequen { float mul; - if (seq->flag & (SEQ_FILTERY | SEQ_USE_CROP | SEQ_USE_TRANSFORM | SEQ_FLIPX | SEQ_FLIPY | SEQ_MAKE_PREMUL | SEQ_MAKE_FLOAT)) { + if (seq->flag & (SEQ_FILTERY | SEQ_USE_CROP | SEQ_USE_TRANSFORM | SEQ_FLIPX | SEQ_FLIPY | SEQ_MAKE_FLOAT)) { return TRUE; } @@ -1892,7 +1875,8 @@ static ImBuf *input_preprocess(SeqRenderData context, Sequence *seq, float cfra, ImBuf *i = IMB_allocImBuf(dx, dy, 32, ibuf->rect_float ? IB_rectfloat : IB_rect); IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy); - + sequencer_imbuf_assign_spaces(context.scene, i); + IMB_freeImBuf(ibuf); ibuf = i; @@ -1931,12 +1915,6 @@ static ImBuf *input_preprocess(SeqRenderData context, Sequence *seq, float cfra, multibuf(ibuf, mul); } - if (seq->flag & SEQ_MAKE_PREMUL) { - if (ibuf->planes == 32 && ibuf->zbuf == NULL) { - IMB_premultiply_alpha(ibuf); - } - } - if (ibuf->x != context.rectx || ibuf->y != context.recty) { if (context.scene->r.mode & R_OSA) { IMB_scaleImBuf(ibuf, (short)context.rectx, (short)context.recty); @@ -2546,13 +2524,18 @@ static ImBuf *do_render_strip_uncached(SeqRenderData context, Sequence *seq, flo case SEQ_TYPE_IMAGE: { StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra); + int flag; if (s_elem) { BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name); BLI_path_abs(name, G.main->name); } - if (s_elem && (ibuf = IMB_loadiffname(name, IB_rect, seq->strip->colorspace_settings.name))) { + flag = IB_rect; + if (seq->alpha_mode == SEQ_ALPHA_PREMUL) + flag |= IB_alphamode_premul; + + if (s_elem && (ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) { /* we don't need both (speed reasons)! */ if (ibuf->rect_float && ibuf->rect) imb_freerectImBuf(ibuf); @@ -2641,7 +2624,7 @@ static ImBuf *do_render_strip_uncached(SeqRenderData context, Sequence *seq, flo static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) { ImBuf *ibuf = NULL; - int use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra); + int use_preprocess = FALSE; int is_proxy_image = FALSE; float nr = give_stripelem_index(seq, cfra); /* all effects are handled similarly with the exception of speed effect */ @@ -2650,30 +2633,36 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF); - /* currently, we cache preprocessed images in SEQ_STRIPELEM_IBUF, - * but not(!) on SEQ_STRIPELEM_IBUF_ENDSTILL and ..._STARTSTILL */ - if (ibuf) - use_preprocess = FALSE; - - if (ibuf == NULL) - ibuf = copy_from_ibuf_still(context, seq, nr); - if (ibuf == NULL) { - ibuf = BKE_sequencer_preprocessed_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF); + if (ibuf == NULL) + ibuf = copy_from_ibuf_still(context, seq, nr); if (ibuf == NULL) { - /* MOVIECLIPs have their own proxy management */ - if (ibuf == NULL && seq->type != SEQ_TYPE_MOVIECLIP) { - ibuf = seq_proxy_fetch(context, seq, cfra); - is_proxy_image = (ibuf != NULL); - } + ibuf = BKE_sequencer_preprocessed_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF); + + if (ibuf == NULL) { + /* MOVIECLIPs have their own proxy management */ + if (ibuf == NULL && seq->type != SEQ_TYPE_MOVIECLIP) { + ibuf = seq_proxy_fetch(context, seq, cfra); + is_proxy_image = (ibuf != NULL); + } - if (ibuf == NULL) - ibuf = do_render_strip_uncached(context, seq, cfra); + if (ibuf == NULL) + ibuf = do_render_strip_uncached(context, seq, cfra); - if (ibuf) - BKE_sequencer_preprocessed_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf); + if (ibuf) + BKE_sequencer_preprocessed_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf); + } } + + if (ibuf) + use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra); + } + else { + /* currently, we cache preprocessed images in SEQ_STRIPELEM_IBUF, + * but not(!) on SEQ_STRIPELEM_IBUF_ENDSTILL and ..._STARTSTILL + * so, no need in check for preprocess here + */ } if (ibuf == NULL) { @@ -3973,10 +3962,18 @@ void BKE_sequence_init_colorspace(Sequence *seq) /* initialize input color space */ if (seq->type == SEQ_TYPE_IMAGE) { - ibuf = IMB_loadiffname(name, IB_rect, seq->strip->colorspace_settings.name); + ibuf = IMB_loadiffname(name, IB_test | IB_alphamode_detect, seq->strip->colorspace_settings.name); + + /* byte images are default to straight alpha, however sequencer + * works in premul space, so mark strip to be premultiplied first + */ + seq->alpha_mode = SEQ_ALPHA_STRAIGHT; + if (ibuf) { + if (ibuf->flags & IB_alphamode_premul) + seq->alpha_mode = IMA_ALPHA_PREMUL; - if (ibuf) IMB_freeImBuf(ibuf); + } } } } @@ -4176,7 +4173,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup seqn->seqbase.first = seqn->seqbase.last = NULL; /* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */ - /* - seq_dupli_recursive(&seq->seqbase,&seqn->seqbase);*/ + /* - seq_dupli_recursive(&seq->seqbase, &seqn->seqbase);*/ } else if (seq->type == SEQ_TYPE_SCENE) { seqn->strip->stripdata = NULL; diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 629b2c989d3..2563fc268b1 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -2407,7 +2407,7 @@ static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene) bv[3] = (float)sds->res[1]; // y bv[5] = (float)sds->res[2]; // z -// #pragma omp parallel for schedule(static,1) +// #pragma omp parallel for schedule(static, 1) for (z = 0; z < sds->res[2]; z++) { size_t index = z * slabsize; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 37c9c1dd84e..b1917c6091d 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -1577,7 +1577,7 @@ static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm) CCGFace **faces; int totface; - BLI_pbvh_get_grid_updates(ccgdm->pbvh, 1, (void ***)&faces, &totface); + BKE_pbvh_get_grid_updates(ccgdm->pbvh, 1, (void ***)&faces, &totface); if (totface) { ccgSubSurf_updateFromFaces(ccgdm->ss, 0, faces, totface); ccgSubSurf_updateNormals(ccgdm->ss, faces, totface); @@ -1715,7 +1715,8 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes) if (ccgdm->pbvh && ccgdm->multires.mmd && !fast) { if (dm->numTessFaceData) { - BLI_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL, setMaterial); + BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL, + setMaterial, FALSE); glShadeModel(GL_FLAT); } @@ -3033,7 +3034,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) * when the ccgdm gets remade, the assumption is that the topology * does not change. */ ccgdm_create_grids(dm); - BLI_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void **)ccgdm->gridFaces, + BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void **)ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } @@ -3051,15 +3052,15 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) numGrids = ccgDM_getNumGrids(dm); - ob->sculpt->pbvh = ccgdm->pbvh = BLI_pbvh_new(); - BLI_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, + ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new(); + BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } else if (ob->type == OB_MESH) { Mesh *me = ob->data; - ob->sculpt->pbvh = ccgdm->pbvh = BLI_pbvh_new(); + ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new(); BLI_assert(!(me->mface == NULL && me->mpoly != NULL)); /* BMESH ONLY complain if mpoly is valid but not mface */ - BLI_pbvh_build_mesh(ccgdm->pbvh, me->mface, me->mvert, + BKE_pbvh_build_mesh(ccgdm->pbvh, me->mface, me->mvert, me->totface, me->totvert, &me->vdata); } diff --git a/source/blender/blenkernel/intern/suggestions.c b/source/blender/blenkernel/intern/suggestions.c index ff9774f85af..6f9736df683 100644 --- a/source/blender/blenkernel/intern/suggestions.c +++ b/source/blender/blenkernel/intern/suggestions.c @@ -163,13 +163,13 @@ void texttool_suggest_add(const char *name, char type) suggestions.top = 0; } -void texttool_suggest_prefix(const char *prefix) +void texttool_suggest_prefix(const char *prefix, const int prefix_len) { SuggItem *match, *first, *last; - int cmp, len = strlen(prefix), top = 0; + int cmp, top = 0; if (!suggestions.first) return; - if (len == 0) { + if (prefix_len == 0) { suggestions.selected = suggestions.firstmatch = suggestions.first; suggestions.lastmatch = suggestions.last; return; @@ -177,7 +177,7 @@ void texttool_suggest_prefix(const char *prefix) first = last = NULL; for (match = suggestions.first; match; match = match->next) { - cmp = txttl_cmp(prefix, match->name, len); + cmp = txttl_cmp(prefix, match->name, prefix_len); if (cmp == 0) { if (!first) { first = match; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 322b77e0462..c337e339ebf 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -2936,3 +2936,18 @@ int text_check_whitespace(const char ch) return 1; return 0; } + +int text_find_identifier_start(const char *str, int i) +{ + if (UNLIKELY(i <= 0)) { + return 0; + } + + while (i--) { + if (!text_check_identifier(str[i])) { + break; + } + } + i++; + return i; +} diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 149842bc038..fbaf6f70fbc 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -440,7 +440,7 @@ void default_tex(Tex *tex) tex->type = TEX_CLOUDS; tex->stype = 0; tex->flag = TEX_CHECKER_ODD; - tex->imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA; + tex->imaflag = TEX_INTERPOL | TEX_MIPMAP; tex->extend = TEX_REPEAT; tex->cropxmin = tex->cropymin = 0.0; tex->cropxmax = tex->cropymax = 1.0; diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h new file mode 100644 index 00000000000..880a97acb80 --- /dev/null +++ b/source/blender/blenlib/BLI_buffer.h @@ -0,0 +1,90 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_BUFFER_H__ +#define __BLI_BUFFER_H__ + +/* Note: this more or less fills same purpose as BLI_array, but makes + * it much easier to resize the array outside of the function it was + * declared in since */ + +/* Usage examples: + * + * { + * BLI_buffer_declare_static(int, my_int_array, BLI_BUFFER_NOP, 32); + * + * BLI_buffer_append(my_int_array, int, 42); + * assert(my_int_array.count == 1); + * assert(BLI_buffer_at(my_int_array, int, 0) == 42); + * + * BLI_buffer_free(&my_int_array); + * } + */ + +typedef struct { + void *data; + const int elem_size; + int count, alloc_count; + int flag; +} BLI_Buffer; + +enum { + BLI_BUFFER_NOP = 0, + BLI_BUFFER_USE_STATIC = (1 << 0), + BLI_BUFFER_USE_CALLOC = (1 << 1), /* ensure the array is always calloc'd */ +}; + +#define BLI_buffer_declare_static(type_, name_, flag_, static_count_) \ + type_ *name_ ## _static_[static_count_]; \ + BLI_Buffer name_ = { \ + /* clear the static memory if this is a calloc'd array */ \ + ((void)((flag_ & BLI_BUFFER_USE_CALLOC) ? \ + memset(name_ ## _static_, 0, sizeof(name_ ## _static_)) : 0\ + ), /* memset-end */ \ + name_ ## _static_), \ + sizeof(type_), \ + 0, \ + static_count_, \ + BLI_BUFFER_USE_STATIC | flag_} + +/* never use static*/ +#define BLI_buffer_declare(type_, name_, flag_) \ + BLI_Buffer name_ = {NULL, \ + sizeof(type_), \ + 0, \ + 0, \ + flag_} + + +#define BLI_buffer_at(buffer_, type_, index_) ( \ + (((type_ *)(buffer_)->data)[(BLI_assert(sizeof(type_) == (buffer_)->elem_size)), index_])) + +#define BLI_buffer_append(buffer_, type_, val_) ( \ + BLI_buffer_resize(buffer_, (buffer_)->count + 1), \ + (BLI_buffer_at(buffer_, type_, (buffer_)->count - 1) = val_) \ +) + +/* Never decreases the amount of memory allocated */ +void BLI_buffer_resize(BLI_Buffer *buffer, int new_count); + +/* Does not free the buffer structure itself */ +void BLI_buffer_free(BLI_Buffer *buffer); + +#endif /* __BLI_BUFFER_H__ */ diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h index c71463da61d..3831ec3cbb4 100644 --- a/source/blender/blenlib/BLI_math_color.h +++ b/source/blender/blenlib/BLI_math_color.h @@ -100,6 +100,13 @@ MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[ void BLI_init_srgb_conversion(void); +/**************** Alpha Transformations *****************/ + +MINLINE void premul_to_straight_v4(float straight[4], const float premul[4]); +MINLINE void straight_to_premul_v4(float straight[4], const float premul[4]); +MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]); +MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4]); + /************************** Other *************************/ int constrain_rgb(float *r, float *g, float *b); diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 423765bad3d..b322d9d7aef 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -72,6 +72,9 @@ float closest_to_line_v2(float r[2], const float p[2], const float l1[2], const void closest_to_line_segment_v3(float r[3], const float p[3], const float l1[3], const float l2[3]); void closest_to_plane_v3(float r[3], const float plane_co[3], const float plane_no_unit[3], const float pt[3]); +/* Set 'r' to the point in triangle (t1, t2, t3) closest to point 'p' */ +void closest_on_tri_to_point_v3(float r[3], const float p[3], const float t1[3], const float t2[3], const float t3[3]); + float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3]); float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]); @@ -262,6 +265,8 @@ void axis_dominant_v3(int *axis_a, int *axis_b, const float axis[3]); MINLINE int max_axis_v3(const float vec[3]); MINLINE int min_axis_v3(const float vec[3]); +MINLINE int poly_to_tri_count(const int poly_count, const int corner_count); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 557ecb3dd0c..8c51c925d97 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -120,7 +120,11 @@ int BLI_split_name_num(char *left, int *nr, const char *name, const char delim); void BLI_splitdirstring(char *di, char *fi); /* make sure path separators conform to system one */ -void BLI_clean(char *path); +void BLI_clean(char *path) +#ifdef __GNUC__ +__attribute__((nonnull(1))) +#endif +; /** * dir can be any input, like from buttons, and this function @@ -173,7 +177,11 @@ int BLI_path_is_rel(const char *path); * \a from The character to replace * \a to The character to replace with */ -void BLI_char_switch(char *string, char from, char to); +void BLI_char_switch(char *string, char from, char to) +#ifdef __GNUC__ +__attribute__((nonnull(1))) +#endif +; /* Initialize path to program executable */ void BLI_init_program_path(const char *argv0); diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h index c8fd72bbbd2..5204e0dd718 100644 --- a/source/blender/blenlib/BLI_scanfill.h +++ b/source/blender/blenlib/BLI_scanfill.h @@ -101,6 +101,10 @@ enum { * Assumes ordered edges, otherwise we risk an eternal loop * removing double verts. - campbell */ BLI_SCANFILL_CALC_REMOVE_DOUBLES = (1 << 1), + + /* note: This flag removes checks for overlapping polygons. + * when this flag is set, we'll never get back more faces then (totvert - 2)*/ + BLI_SCANFILL_CALC_HOLES = (1 << 2) }; int BLI_scanfill_begin(ScanFillContext *sf_ctx); diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index 7c3b70545d6..cb30138c4f9 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -32,12 +32,37 @@ * \ingroup bli */ -#ifndef FALSE -# define FALSE 0 +/* note: use of (int, TRUE / FALSE) is deprecated, + * use (bool, true / false) instead */ +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# ifndef HAVE__BOOL +# ifdef __cplusplus +typedef bool _BLI_Bool; +# else +# define _BLI_Bool signed char +# endif +# else +# define _BLI_Bool _Bool +# endif +# define bool _BLI_Bool +# define false 0 +# define true 1 +# define __bool_true_false_are_defined 1 #endif -#ifndef TRUE -# define TRUE 1 +/* remove this when we're ready to remove TRUE/FALSE completely */ +#ifdef WITH_BOOL_COMPAT +/* interim until all occurrences of these can be updated to stdbool */ +/* XXX Why not use the true/false velues here? */ +# ifndef FALSE +# define FALSE 0 +# endif + +# ifndef TRUE +# define TRUE 1 +# endif #endif /* useful for finding bad use of min/max */ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index fe954fb10ac..f438e6bdec3 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -48,6 +48,7 @@ set(SRC intern/BLI_mempool.c intern/DLRB_tree.c intern/boxpack2d.c + intern/buffer.c intern/callbacks.c intern/cpu.c intern/dynlib.c @@ -96,6 +97,7 @@ set(SRC BLI_array.h BLI_bitmap.h BLI_blenlib.h + BLI_buffer.h BLI_boxpack2d.h BLI_callbacks.h BLI_cpu.h diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 55f67cedfc6..b2d07b9ee4d 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -1554,7 +1554,7 @@ int BLI_bvhtree_ray_cast(BVHTree *tree, const float co[3], const float dir[3], f float BLI_bvhtree_bb_raycast(const float bv[6], const float light_start[3], const float light_end[3], float pos[3]) { BVHRayCastData data; - float dist = 0.0; + float dist; data.hit.dist = FLT_MAX; diff --git a/source/blender/blenlib/intern/buffer.c b/source/blender/blenlib/intern/buffer.c new file mode 100644 index 00000000000..b2280b9a0d1 --- /dev/null +++ b/source/blender/blenlib/intern/buffer.c @@ -0,0 +1,81 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_buffer.h" +#include "BLI_utildefines.h" + +#include <string.h> + +static void *buffer_alloc(BLI_Buffer *buffer, int len) +{ + return ((buffer->flag & BLI_BUFFER_USE_CALLOC) ? + MEM_callocN : MEM_mallocN) + (buffer->elem_size * len, "BLI_Buffer.data"); +} + +static void *buffer_realloc(BLI_Buffer *buffer, int len) +{ + return ((buffer->flag & BLI_BUFFER_USE_CALLOC) ? + MEM_recallocN : MEM_reallocN) + (buffer->data, (buffer->elem_size * len)); +} + +void BLI_buffer_resize(BLI_Buffer *buffer, int new_count) +{ + if (new_count > buffer->alloc_count) { + if (buffer->flag & BLI_BUFFER_USE_STATIC) { + void *orig = buffer->data; + + buffer->data = buffer_alloc(buffer, new_count); + memcpy(buffer->data, orig, buffer->elem_size * buffer->count); + buffer->alloc_count = new_count; + buffer->flag &= ~BLI_BUFFER_USE_STATIC; + } + else { + if (buffer->alloc_count && (new_count < buffer->alloc_count * 2)) { + buffer->alloc_count *= 2; + } + else { + buffer->alloc_count = new_count; + } + + if (buffer->data) { + buffer->data = buffer_realloc(buffer, buffer->alloc_count); + } + else { + buffer->data = buffer_alloc(buffer, buffer->alloc_count); + } + } + } + + buffer->count = new_count; +} + +void BLI_buffer_free(BLI_Buffer *buffer) +{ + if ((buffer->flag & BLI_BUFFER_USE_STATIC) == 0) { + if (buffer->data) { + MEM_freeN(buffer->data); + } + } + memset(buffer, 0, sizeof(*buffer)); +} diff --git a/source/blender/blenlib/intern/jitter.c b/source/blender/blenlib/intern/jitter.c index 6203a98828b..3fe0ef158df 100644 --- a/source/blender/blenlib/intern/jitter.c +++ b/source/blender/blenlib/intern/jitter.c @@ -165,7 +165,7 @@ void BLI_jitter_init(float *jitarr, int num) MEM_freeN(jit2); - /* finally, move jittertab to be centered around (0,0) */ + /* finally, move jittertab to be centered around (0, 0) */ for (i = 0; i < 2 * num; i += 2) { jitarr[i] -= 0.5f; jitarr[i + 1] -= 0.5f; diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index 4c8bd43ef73..b8eeca50db6 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -149,31 +149,6 @@ MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linea srgb[3] = FTOUSHORT(linear[3]); } -MINLINE void linearrgb_to_srgb_ushort4_predivide(unsigned short srgb[4], const float linear[4]) -{ - float alpha, inv_alpha, t; - int i; - - if (linear[3] == 1.0f || linear[3] == 0.0f) { - linearrgb_to_srgb_ushort4(srgb, linear); - return; - } - - alpha = linear[3]; - inv_alpha = 1.0f / alpha; - - for (i = 0; i < 3; ++i) { - t = linear[i] * inv_alpha; - srgb[i] = (t <= 1.0f) ? - /* warning - converts: float -> short -> float -> short */ - (unsigned short) (to_srgb_table_lookup(t) * alpha) : - /* if FTOUSHORT was an inline function this could be done less confusingly */ - ((t = linearrgb_to_srgb(t) * alpha), FTOUSHORT(t)); - } - - srgb[3] = FTOUSHORT(linear[3]); -} - MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4]) { linear[0] = BLI_color_from_srgb_table[srgb[0]]; @@ -293,4 +268,62 @@ MINLINE int compare_rgb_uchar(const unsigned char col_a[3], const unsigned char return 0; } +/**************** Alpha Transformations *****************/ + +MINLINE void premul_to_straight_v4(float straight[4], const float premul[4]) +{ + if (premul[3] == 0.0f || premul[3] == 1.0f) { + straight[0] = premul[0]; + straight[1] = premul[1]; + straight[2] = premul[2]; + straight[3] = premul[3]; + } + else { + float alpha_inv = 1.0f / premul[3]; + straight[0] = premul[0] * alpha_inv; + straight[1] = premul[1] * alpha_inv; + straight[2] = premul[2] * alpha_inv; + straight[3] = premul[3]; + } +} + +MINLINE void straight_to_premul_v4(float premul[4], const float straight[4]) +{ + float alpha = straight[3]; + premul[0] = straight[0] * alpha; + premul[1] = straight[1] * alpha; + premul[2] = straight[2] * alpha; + premul[3] = straight[3]; +} + +MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]) +{ + float alpha = color[3] / 255.0f; + float fac = alpha / 255.0f; + + result[0] = color[0] * fac; + result[1] = color[1] * fac; + result[2] = color[2] * fac; + result[3] = alpha; +} + +MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4]) +{ + if (color[3] == 0.0f || color[3] == 1.0f) { + result[0] = FTOCHAR(color[0]); + result[1] = FTOCHAR(color[1]); + result[2] = FTOCHAR(color[2]); + result[3] = FTOCHAR(color[3]); + } + else { + float alpha_inv = 1.0f / color[3]; + + /* hopefully this would be optimized */ + result[0] = FTOCHAR(color[0] * alpha_inv); + result[1] = FTOCHAR(color[1] * alpha_inv); + result[2] = FTOCHAR(color[2] * alpha_inv); + result[3] = FTOCHAR(color[3]); + } +} + #endif /* __MATH_COLOR_INLINE_C__ */ diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 10a9a2df9f5..3527af365ec 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -296,6 +296,88 @@ float dist_to_line_segment_v3(const float v1[3], const float v2[3], const float return len_v3v3(closest, v1); } +/* Adapted from "Real-Time Collision Detection" by Christer Ericson, + * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. + * + * Set 'r' to the point in triangle (a, b, c) closest to point 'p' */ +void closest_on_tri_to_point_v3(float r[3], const float p[3], + const float a[3], const float b[3], const float c[3]) +{ + float ab[3], ac[3], ap[3], d1, d2; + float bp[3], d3, d4, vc, cp[3], d5, d6, vb, va; + float denom, v, w; + + /* Check if P in vertex region outside A */ + sub_v3_v3v3(ab, b, a); + sub_v3_v3v3(ac, c, a); + sub_v3_v3v3(ap, p, a); + d1 = dot_v3v3(ab, ap); + d2 = dot_v3v3(ac, ap); + if (d1 <= 0.0f && d2 <= 0.0f) { + /* barycentric coordinates (1,0,0) */ + copy_v3_v3(r, a); + return; + } + + /* Check if P in vertex region outside B */ + sub_v3_v3v3(bp, p, b); + d3 = dot_v3v3(ab, bp); + d4 = dot_v3v3(ac, bp); + if (d3 >= 0.0f && d4 <= d3) { + /* barycentric coordinates (0,1,0) */ + copy_v3_v3(r, b); + return; + } + /* Check if P in edge region of AB, if so return projection of P onto AB */ + vc = d1*d4 - d3*d2; + if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) { + float v = d1 / (d1 - d3); + /* barycentric coordinates (1-v,v,0) */ + madd_v3_v3v3fl(r, a, ab, v); + return; + } + /* Check if P in vertex region outside C */ + sub_v3_v3v3(cp, p, c); + d5 = dot_v3v3(ab, cp); + d6 = dot_v3v3(ac, cp); + if (d6 >= 0.0f && d5 <= d6) { + /* barycentric coordinates (0,0,1) */ + copy_v3_v3(r, c); + return; + } + /* Check if P in edge region of AC, if so return projection of P onto AC */ + vb = d5*d2 - d1*d6; + if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) { + float w = d2 / (d2 - d6); + /* barycentric coordinates (1-w,0,w) */ + madd_v3_v3v3fl(r, a, ac, w); + return; + } + /* Check if P in edge region of BC, if so return projection of P onto BC */ + va = d3*d6 - d5*d4; + if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) { + float w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); + /* barycentric coordinates (0,1-w,w) */ + sub_v3_v3v3(r, c, b); + mul_v3_fl(r, w); + add_v3_v3(r, b); + return; + } + + /* P inside face region. Compute Q through its barycentric coordinates (u,v,w) */ + denom = 1.0f / (va + vb + vc); + v = vb * denom; + w = vc * denom; + + /* = u*a + v*b + w*c, u = va * denom = 1.0f - v - w */ + /* ac * w */ + mul_v3_fl(ac, w); + /* a + ab * v */ + madd_v3_v3v3fl(r, a, ab, v); + /* a + ab * v + ac * w */ + add_v3_v3(r, ac); +} + /******************************* Intersection ********************************/ /* intersect Line-Line, shorts */ @@ -1037,7 +1119,7 @@ int isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const flo if (t0 > 1.0f || t1 < 0.0f) return 0; - /* clamp to [0,1] */ + /* clamp to [0, 1] */ CLAMP(t0, 0.0f, 1.0f); CLAMP(t1, 0.0f, 1.0f); @@ -1157,10 +1239,10 @@ int isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const flo } /*e3*/ - /* sub_v3_v3v3(bv,v0,p1); */ /* UNUSED */ - /* elen2 = dot_v3v3(e1,e1); */ /* UNUSED */ - /* edotv = dot_v3v3(e1,vel); */ /* UNUSED */ - /* edotbv = dot_v3v3(e1,bv); */ /* UNUSED */ + /* sub_v3_v3v3(bv, v0, p1); */ /* UNUSED */ + /* elen2 = dot_v3v3(e1, e1); */ /* UNUSED */ + /* edotv = dot_v3v3(e1, vel); */ /* UNUSED */ + /* edotbv = dot_v3v3(e1, bv); */ /* UNUSED */ sub_v3_v3v3(bv, v1, p1); elen2 = dot_v3v3(e3, e3); @@ -1195,7 +1277,7 @@ int isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3] int a0 = axis, a1 = (axis + 1) % 3, a2 = (axis + 2) % 3; #if 0 - return isect_line_tri_v3(p1,p2,v0,v1,v2,lambda); + return isect_line_tri_v3(p1, p2, v0, v1, v2, lambda); /* first a simple bounding box test */ if (min_fff(v0[a1], v1[a1], v2[a1]) > p1[a1]) return 0; @@ -1415,8 +1497,8 @@ int isect_ray_aabb(const IsectRayAABBData *data, const float bb_min[3], return TRUE; } -/* find closest point to p on line through l1,l2 and return lambda, - * where (0 <= lambda <= 1) when cp is in the line segment l1,l2 +/* find closest point to p on line through (l1, l2) and return lambda, + * where (0 <= lambda <= 1) when cp is in the line segment (l1, l2) */ float closest_to_line_v3(float cp[3], const float p[3], const float l1[3], const float l2[3]) { @@ -1702,9 +1784,9 @@ static int point_in_slice(const float p[3], const float v1[3], const float l1[3] /* * what is a slice ? * some maths: - * a line including l1,l2 and a point not on the line + * a line including (l1, l2) and a point not on the line * define a subset of R3 delimited by planes parallel to the line and orthogonal - * to the (point --> line) distance vector,one plane on the line one on the point, + * to the (point --> line) distance vector, one plane on the line one on the point, * the room inside usually is rather small compared to R3 though still infinite * useful for restricting (speeding up) searches * e.g. all points of triangular prism are within the intersection of 3 'slices' @@ -2304,7 +2386,7 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ } } -/* (x1,v1)(t1=0)------(x2,v2)(t2=1), 0<t<1 --> (x,v)(t) */ +/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */ void interp_cubic_v3(float x[3], float v[3], const float x1[3], const float v1[3], const float x2[3], const float v2[3], const float t) { float a[3], b[3]; @@ -2791,8 +2873,8 @@ void tangent_from_uv(float uv1[2], float uv2[2], float uv3[3], float co1[3], flo /****************************** Vector Clouds ********************************/ /* vector clouds */ -/* void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight,float (*rpos)[3], float *rweight, - * float lloc[3],float rloc[3],float lrot[3][3],float lscale[3][3]) +/* void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, float (*rpos)[3], float *rweight, + * float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3]) * * input * ( @@ -2881,9 +2963,9 @@ void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, fl /* build 'projection' matrix */ for (a = 0; a < list_size; a++) { sub_v3_v3v3(va, rpos[a], accu_rcom); - /* mul_v3_fl(va,bp->mass); mass needs renormalzation here ?? */ + /* mul_v3_fl(va, bp->mass); mass needs renormalzation here ?? */ sub_v3_v3v3(vb, pos[a], accu_com); - /* mul_v3_fl(va,rp->mass); */ + /* mul_v3_fl(va, rp->mass); */ m[0][0] += va[0] * vb[0]; m[0][1] += va[0] * vb[1]; m[0][2] += va[0] * vb[2]; diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c index ba9770e1bd1..f32b477787b 100644 --- a/source/blender/blenlib/intern/math_geom_inline.c +++ b/source/blender/blenlib/intern/math_geom_inline.c @@ -158,4 +158,31 @@ MINLINE int min_axis_v3(const float vec[3]) ((y < z) ? 1 : 2)); } +/** + * Simple method to find how many tri's we need when we already know the corner+poly count. + * + * Formula is: + * + * tri = ((corner_count / poly_count) - 2) * poly_count; + * + * Use doubles since this is used for allocating and we + * don't want float precision to give incorrect results. + * + * \param poly_count The number of ngon's/tris (1-2 sided faces will give incorrect results) + * \param corner_count - also known as loops in BMesh/DNA + */ +MINLINE int poly_to_tri_count(const int poly_count, const int corner_count) +{ + if (poly_count != 0) { + const double poly_count_d = (double)poly_count; + const double corner_count_d = (double)corner_count; + BLI_assert(poly_count > 0); + BLI_assert(corner_count > 0); + return (int)((((corner_count_d / poly_count_d) - 2.0) * poly_count_d) + 0.5); + } + else { + return 0; + } +} + #endif /* __MATH_GEOM_INLINE_C__ */ diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 3a294769eb3..02fc5b07d6d 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -990,7 +990,7 @@ void normalize_m4_m4(float rmat[4][4], float mat[4][4]) if (len != 0.0f) rmat[2][3] = mat[2][3] / len; } -void adjoint_m2_m2(float m1[][2], float m[][2]) +void adjoint_m2_m2(float m1[2][2], float m[2][2]) { BLI_assert(m1 != m); m1[0][0] = m[1][1]; diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 04b9d574347..8c62fdf81a7 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -461,7 +461,7 @@ MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3]) r[2] = v1[2] * v2[2]; } -MINLINE void negate_v2(float r[3]) +MINLINE void negate_v2(float r[2]) { r[0] = -r[0]; r[1] = -r[1]; diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 7c1842b10f2..06b1f1f09b1 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1212,8 +1212,6 @@ void BLI_setenv_if_new(const char *env, const char *val) void BLI_clean(char *path) { - if (path == NULL) return; - #ifdef WIN32 if (path && BLI_strnlen(path, 3) > 2) { BLI_char_switch(path + 2, '/', '\\'); @@ -1225,7 +1223,6 @@ void BLI_clean(char *path) void BLI_char_switch(char *string, char from, char to) { - if (string == NULL) return; while (*string != 0) { if (*string == from) *string = to; string++; @@ -1622,7 +1619,7 @@ int BLI_rebase_path(char *abs, size_t abs_len, char *rel, size_t rel_len, const rel_dir[0] = 0; /* if image is "below" current .blend file directory */ - if (!strncmp(path, blend_dir, len)) { + if (!BLI_path_ncmp(path, blend_dir, len)) { /* if image is _in_ current .blend file directory */ if (BLI_path_cmp(dir, blend_dir) == 0) { diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c index defe500cb21..771295b4b78 100644 --- a/source/blender/blenlib/intern/scanfill.c +++ b/source/blender/blenlib/intern/scanfill.c @@ -459,7 +459,7 @@ static void testvertexnearedge(ScanFillContext *sf_ctx) /* new edge */ ed1 = BLI_scanfill_edge_add(sf_ctx, eed->v1, eve); - /* printf("fill: vertex near edge %x\n",eve); */ + /* printf("fill: vertex near edge %x\n", eve); */ ed1->f = 0; ed1->poly_nr = eed->poly_nr; eed->v1 = eve; @@ -630,11 +630,16 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) /* (temporal) security: never much more faces than vertices */ totface = 0; - maxface = 2 * verts; /* 2*verts: based at a filled circle within a triangle */ + if (flag & BLI_SCANFILL_CALC_HOLES) { + maxface = 2 * verts; /* 2*verts: based at a filled circle within a triangle */ + } + else { + maxface = verts - 2; /* when we don't calc any holes, we assume face is a non overlapping loop */ + } sc = sf_ctx->_scdata; for (a = 0; a < verts; a++) { - /* printf("VERTEX %d %x\n",a,sc->v1); */ + /* printf("VERTEX %d %x\n", a, sc->v1); */ ed1 = sc->edge_first; while (ed1) { /* set connectflags */ nexted = ed1->next; @@ -654,7 +659,7 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) /* commented out... the ESC here delivers corrupted memory (and doesnt work during grab) */ /* if (callLocalInterruptCallBack()) break; */ - if (totface > maxface) { + if (totface >= maxface) { /* printf("Fill error: endless loop. Escaped at vert %d, tot: %d.\n", a, verts); */ a = verts; break; @@ -675,30 +680,31 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) v3 = ed2->v2; /* this happens with a serial of overlapping edges */ if (v1 == v2 || v2 == v3) break; - /* printf("test verts %x %x %x\n",v1,v2,v3); */ + /* printf("test verts %x %x %x\n", v1, v2, v3); */ miny = min_ff(v1->xy[1], v3->xy[1]); - /* miny = min_ff(v1->xy[1],v3->xy[1]); */ + /* miny = min_ff(v1->xy[1], v3->xy[1]); */ sc1 = sc + 1; test = 0; for (b = a + 1; b < verts; b++) { if (sc1->vert->f == 0) { if (sc1->vert->xy[1] <= miny) break; - - if (testedgeside(v1->xy, v2->xy, sc1->vert->xy)) - if (testedgeside(v2->xy, v3->xy, sc1->vert->xy)) + if (testedgeside(v1->xy, v2->xy, sc1->vert->xy)) { + if (testedgeside(v2->xy, v3->xy, sc1->vert->xy)) { if (testedgeside(v3->xy, v1->xy, sc1->vert->xy)) { /* point in triangle */ - + test = 1; break; } + } + } } sc1++; } if (test) { /* make new edge, and start over */ - /* printf("add new edge %x %x and start again\n",v2,sc1->vert); */ + /* printf("add new edge %x %x and start again\n", v2, sc1->vert); */ ed3 = BLI_scanfill_edge_add(sf_ctx, v2, sc1->vert); BLI_remlink(&sf_ctx->filledgebase, ed3); @@ -710,7 +716,7 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) } else { /* new triangle */ - /* printf("add face %x %x %x\n",v1,v2,v3); */ + /* printf("add face %x %x %x\n", v1, v2, v3); */ addfillface(sf_ctx, v1, v2, v3); totface++; BLI_remlink((ListBase *)&(sc->edge_first), ed1); @@ -734,7 +740,7 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) ed3->v1->h++; ed3->v2->h++; - /* printf("add new edge %x %x\n",v1,v3); */ + /* printf("add new edge %x %x\n", v1, v3); */ sc1 = addedgetoscanlist(sf_ctx, ed3, verts); if (sc1) { /* ed3 already exists: remove if a boundary */ @@ -773,12 +779,15 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) ed1 = nexted; } } + sc++; } MEM_freeN(sf_ctx->_scdata); sf_ctx->_scdata = NULL; + BLI_assert(totface <= maxface); + return totface; } @@ -910,50 +919,68 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float no /* STEP 1: COUNT POLYS */ - eve = sf_ctx->fillvertbase.first; - while (eve) { - eve->xy[0] = eve->co[co_x]; - eve->xy[1] = eve->co[co_y]; + if (flag & BLI_SCANFILL_CALC_HOLES) { + eve = sf_ctx->fillvertbase.first; + while (eve) { + eve->xy[0] = eve->co[co_x]; + eve->xy[1] = eve->co[co_y]; + + /* get first vertex with no poly number */ + if (eve->poly_nr == 0) { + poly++; + /* now a sort of select connected */ + ok = 1; + eve->poly_nr = poly; - /* get first vertex with no poly number */ - if (eve->poly_nr == 0) { - poly++; - /* now a sort of select connected */ - ok = 1; - eve->poly_nr = poly; - - while (ok) { - - ok = 0; - toggle++; - if (toggle & 1) eed = sf_ctx->filledgebase.first; - else eed = sf_ctx->filledgebase.last; - - while (eed) { - if (eed->v1->poly_nr == 0 && eed->v2->poly_nr == poly) { - eed->v1->poly_nr = poly; - eed->poly_nr = poly; - ok = 1; - } - else if (eed->v2->poly_nr == 0 && eed->v1->poly_nr == poly) { - eed->v2->poly_nr = poly; - eed->poly_nr = poly; - ok = 1; - } - else if (eed->poly_nr == 0) { - if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) { + while (ok) { + + ok = 0; + toggle++; + if (toggle & 1) eed = sf_ctx->filledgebase.first; + else eed = sf_ctx->filledgebase.last; + + while (eed) { + if (eed->v1->poly_nr == 0 && eed->v2->poly_nr == poly) { + eed->v1->poly_nr = poly; eed->poly_nr = poly; ok = 1; } + else if (eed->v2->poly_nr == 0 && eed->v1->poly_nr == poly) { + eed->v2->poly_nr = poly; + eed->poly_nr = poly; + ok = 1; + } + else if (eed->poly_nr == 0) { + if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) { + eed->poly_nr = poly; + ok = 1; + } + } + if (toggle & 1) eed = eed->next; + else eed = eed->prev; } - if (toggle & 1) eed = eed->next; - else eed = eed->prev; } } + eve = eve->next; + } + /* printf("amount of poly's: %d\n", poly); */ + } + else { + poly = 1; + + eve = sf_ctx->fillvertbase.first; + while (eve) { + eve->xy[0] = eve->co[co_x]; + eve->xy[1] = eve->co[co_y]; + eve->poly_nr = poly; + eve = eve->next; + } + eed = sf_ctx->filledgebase.first; + while (eed) { + eed->poly_nr = poly; + eed = eed->next; } - eve = eve->next; } - /* printf("amount of poly's: %d\n",poly); */ /* STEP 2: remove loose edges and strings of edges */ eed = sf_ctx->filledgebase.first; diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index e9caa337129..b2d37e36004 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -311,6 +311,9 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil /* makes lookup of existing video clips in old main */ blo_make_movieclip_pointer_map(fd, oldmain); + /* makes lookup of existing video clips in old main */ + blo_make_packed_pointer_map(fd, oldmain); + bfd = blo_read_file_internal(fd, filename); /* ensures relinked images are not freed */ @@ -319,6 +322,9 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil /* ensures relinked movie clips are not freed */ blo_end_movieclip_pointer_map(fd, oldmain); + /* ensures relinked packed data is not freed */ + blo_end_packed_pointer_map(fd, oldmain); + /* move libraries from old main to new main */ if (bfd && mainlist.first != mainlist.last) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 4c3ba747906..151a929a445 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -546,7 +546,9 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab BLI_strncpy(name1, filepath, sizeof(name1)); cleanup_path(relabase, name1); -// printf("blo_find_main: original in %s\n", name); + +// printf("blo_find_main: relabase %s\n", relabase); +// printf("blo_find_main: original in %s\n", filepath); // printf("blo_find_main: converted to %s\n", name1); for (m = mainlist->first; m; m = m->next) { @@ -1023,6 +1025,46 @@ FileData *blo_openblenderfile(const char *filepath, ReportList *reports) } } +static int fd_read_gzip_from_memory(FileData *filedata, void *buffer, unsigned int size) +{ + int err; + + filedata->strm.next_out = (Bytef *) buffer; + filedata->strm.avail_out = size; + + // Inflate another chunk. + err = inflate (&filedata->strm, Z_SYNC_FLUSH); + + if (err == Z_STREAM_END) { + return 0; + } + else if (err != Z_OK) { + printf("fd_read_gzip_from_memory: zlib error\n"); + return 0; + } + + filedata->seek += size; + + return (size); +} + +static int fd_read_gzip_from_memory_init(FileData *fd) +{ + + fd->strm.next_in = (Bytef *) fd->buffer; + fd->strm.avail_in = fd->buffersize; + fd->strm.total_out = 0; + fd->strm.zalloc = Z_NULL; + fd->strm.zfree = Z_NULL; + + if (inflateInit2(&fd->strm, (16+MAX_WBITS)) != Z_OK) + return 0; + + fd->read = fd_read_gzip_from_memory; + + return 1; +} + FileData *blo_openblendermemory(void *mem, int memsize, ReportList *reports) { if (!mem || memsize<SIZEOFBLENDERHEADER) { @@ -1031,9 +1073,21 @@ FileData *blo_openblendermemory(void *mem, int memsize, ReportList *reports) } else { FileData *fd = filedata_new(); + char *cp = mem; + fd->buffer = mem; fd->buffersize = memsize; + + /* test if gzip */ + if (cp[0] == 0x1f && cp[1] == 0x8b) { + if (0 == fd_read_gzip_from_memory_init(fd)) { + blo_freefiledata(fd); + return NULL; + } + } + else fd->read = fd_read_from_memory; + fd->flags |= FD_FLAGS_NOT_MY_BUFFER; return blo_decode_and_check(fd, reports); @@ -1069,6 +1123,12 @@ void blo_freefiledata(FileData *fd) gzclose(fd->gzfiledes); } + if (fd->strm.next_in) { + if (inflateEnd (&fd->strm) != Z_OK) { + printf("close gzip stream error\n"); + } + } + if (fd->buffer && !(fd->flags & FD_FLAGS_NOT_MY_BUFFER)) { MEM_freeN(fd->buffer); fd->buffer = NULL; @@ -1092,6 +1152,8 @@ void blo_freefiledata(FileData *fd) oldnewmap_free(fd->imamap); if (fd->movieclipmap) oldnewmap_free(fd->movieclipmap); + if (fd->packedmap) + oldnewmap_free(fd->packedmap); if (fd->libmap && !(fd->flags & FD_FLAGS_NOT_MY_LIBMAP)) oldnewmap_free(fd->libmap); if (fd->bheadmap) @@ -1176,6 +1238,14 @@ static void *newmclipadr(FileData *fd, void *adr) /* used to restor return NULL; } +static void *newpackedadr(FileData *fd, void *adr) /* used to restore packed data after undo */ +{ + if (fd->packedmap && adr) + return oldnewmap_lookup_and_inc(fd->packedmap, adr); + + return oldnewmap_lookup_and_inc(fd->datamap, adr); +} + static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */ { @@ -1372,6 +1442,69 @@ void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain) } } +static void insert_packedmap(FileData *fd, PackedFile *pf) +{ + oldnewmap_insert(fd->packedmap, pf, pf, 0); + oldnewmap_insert(fd->packedmap, pf->data, pf->data, 0); +} + +void blo_make_packed_pointer_map(FileData *fd, Main *oldmain) +{ + Image *ima; + VFont *vfont; + bSound *sound; + Library *lib; + + fd->packedmap = oldnewmap_new(); + + for (ima = oldmain->image.first; ima; ima = ima->id.next) + if (ima->packedfile) + insert_packedmap(fd, ima->packedfile); + + for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next) + if (vfont->packedfile) + insert_packedmap(fd, vfont->packedfile); + + for (sound = oldmain->sound.first; sound; sound = sound->id.next) + if (sound->packedfile) + insert_packedmap(fd, sound->packedfile); + + for (lib = oldmain->library.first; lib; lib = lib->id.next) + if (lib->packedfile) + insert_packedmap(fd, lib->packedfile); + +} + +/* set old main packed data to zero if it has been restored */ +/* this works because freeing old main only happens after this call */ +void blo_end_packed_pointer_map(FileData *fd, Main *oldmain) +{ + Image *ima; + VFont *vfont; + bSound *sound; + Library *lib; + OldNew *entry = fd->packedmap->entries; + int i; + + /* used entries were restored, so we put them to zero */ + for (i=0; i < fd->packedmap->nentries; i++, entry++) { + if (entry->nr > 0) + entry->newp = NULL; + } + + for (ima = oldmain->image.first; ima; ima = ima->id.next) + ima->packedfile = newpackedadr(fd, ima->packedfile); + + for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next) + vfont->packedfile = newpackedadr(fd, vfont->packedfile); + + for (sound = oldmain->sound.first; sound; sound = sound->id.next) + sound->packedfile = newpackedadr(fd, sound->packedfile); + + for (lib = oldmain->library.first; lib; lib = lib->id.next) + lib->packedfile = newpackedadr(fd, lib->packedfile); +} + /* undo file support: add all library pointers in lookup */ void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd) @@ -1711,10 +1844,10 @@ static void direct_link_script(FileData *UNUSED(fd), Script *script) static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf) { - PackedFile *pf = newdataadr(fd, oldpf); + PackedFile *pf = newpackedadr(fd, oldpf); if (pf) { - pf->data = newdataadr(fd, pf->data); + pf->data = newpackedadr(fd, pf->data); } return pf; @@ -2538,7 +2671,7 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) cld.fd = fd; cld.id = id; - id_loop_constraints(conlist, lib_link_constraint_cb, &cld); + BKE_id_loop_constraints(conlist, lib_link_constraint_cb, &cld); } static void direct_link_constraints(FileData *fd, ListBase *lb) @@ -5725,6 +5858,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) { Panel *pa; + uiList *ui_list; link_list(fd, &ar->panels); @@ -5735,6 +5869,12 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) pa->type = NULL; } + link_list(fd, &ar->ui_lists); + + for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) { + ui_list->type = NULL; + } + ar->regiondata = newdataadr(fd, ar->regiondata); if (ar->regiondata) { if (spacetype == SPACE_VIEW3D) { @@ -6057,6 +6197,7 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) { Main *newmain; + /* check if the library was already read */ for (newmain = fd->mainlist->first; newmain; newmain = newmain->next) { if (newmain->curlib) { if (BLI_path_cmp(newmain->curlib->filepath, lib->filepath) == 0) { @@ -6075,14 +6216,14 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) } } } - /* make sure we have full path in lib->filename */ + /* make sure we have full path in lib->filepath */ BLI_strncpy(lib->filepath, lib->name, sizeof(lib->name)); cleanup_path(fd->relabase, lib->filepath); -#if 0 - printf("direct_link_library: name %s\n", lib->name); - printf("direct_link_library: filename %s\n", lib->filename); -#endif +// printf("direct_link_library: name %s\n", lib->name); +// printf("direct_link_library: filepath %s\n", lib->filepath); + + lib->packedfile = direct_link_packedfile(fd, lib->packedfile); /* new main */ newmain= MEM_callocN(sizeof(Main), "directlink"); @@ -7713,7 +7854,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) for (ob = main->object.first; ob; ob = ob->id.next) { bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (!cti) continue; @@ -8636,15 +8777,41 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } - { + if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 5)) { Scene *scene; + Image *image; + Tex *tex; for (scene = main->scene.first; scene; scene = scene->id.next) { + Sequence *seq; + + SEQ_BEGIN (scene->ed, seq) + { + if (seq->flag & SEQ_MAKE_PREMUL) + seq->alpha_mode = SEQ_ALPHA_STRAIGHT; + } + SEQ_END + if (scene->r.bake_samples == 0) scene->r.bake_samples = 256; } + + for (image = main->image.first; image; image = image->id.next) { + if (image->flag & IMA_DO_PREMUL) + image->alpha_mode = IMA_ALPHA_STRAIGHT; } + for (tex = main->tex.first; tex; tex = tex->id.next) { + if (tex->type == TEX_IMAGE && (tex->imaflag & TEX_USEALPHA) == 0) { + image = blo_do_versions_newlibadr(fd, tex->id.lib, tex->ima); + + if (image) + image->flag |= IMA_IGNORE_ALPHA; + } + } + } + + #ifdef WITH_FREESTYLE /* default values in Freestyle settings */ { @@ -8759,6 +8926,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) wmKeyMap *keymap; wmKeyMapItem *kmi; wmKeyMapDiffItem *kmdi; + bAddon *addon; bfd->user = user= read_struct(fd, bhead, "user def"); @@ -8797,6 +8965,13 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) direct_link_keymapitem(fd, kmi); } + for (addon = user->addons.first; addon; addon = addon->next) { + addon->prop = newdataadr(fd, addon->prop); + if (addon->prop) { + IDP_DirectLinkProperty(addon->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + } + } + // XXX user->uifonts.first = user->uifonts.last= NULL; @@ -9001,6 +9176,14 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) Library *lib = read_struct(fd, bheadlib, "Library"); Main *ptr = blo_find_main(fd, lib->name, fd->relabase); + if (ptr->curlib == NULL) { + const char *idname= bhead_id_name(fd, bhead); + + BKE_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB ERROR: Data refers to main .blend file: '%s' from %s"), + idname, mainvar->curlib->filepath); + return; + } + else id = is_yet_read(fd, ptr, bhead); if (id == NULL) { @@ -9440,7 +9623,7 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb) ced.fd = fd; ced.mainvar = mainvar; - id_loop_constraints(lb, expand_constraint_cb, &ced); + BKE_id_loop_constraints(lb, expand_constraint_cb, &ced); /* deprecated manual expansion stuff */ for (curcon = lb->first; curcon; curcon = curcon->next) { @@ -10299,12 +10482,26 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) FileData *fd = mainptr->curlib->filedata; if (fd == NULL) { + /* printf and reports for now... its important users know this */ + + /* if packed file... */ + if (mainptr->curlib->packedfile) { + PackedFile *pf = mainptr->curlib->packedfile; + + BKE_reportf_wrap(basefd->reports, RPT_INFO, TIP_("Read packed library: '%s'"), + mainptr->curlib->name); + fd = blo_openblendermemory(pf->data, pf->size, basefd->reports); + + + /* needed for library_append and read_libraries */ + BLI_strncpy(fd->relabase, mainptr->curlib->filepath, sizeof(fd->relabase)); + } + else { BKE_reportf_wrap(basefd->reports, RPT_INFO, TIP_("Read library: '%s', '%s'"), mainptr->curlib->filepath, mainptr->curlib->name); - fd = blo_openblenderfile(mainptr->curlib->filepath, basefd->reports); - + } /* allow typing in a new lib path */ if (G.debug_value == -666) { while (fd == NULL) { diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index a979a16220d..a0895c92b24 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -69,6 +69,9 @@ typedef struct FileData { char headerdone; int inbuffer; + // gzip stream for memory decompression + z_stream strm; + // general reading variables struct SDNA *filesdna; struct SDNA *memsdna; @@ -83,6 +86,7 @@ typedef struct FileData { struct OldNewMap *libmap; struct OldNewMap *imamap; struct OldNewMap *movieclipmap; + struct OldNewMap *packedmap; struct BHeadSort *bheadmap; int tot_bheadmap; @@ -127,6 +131,8 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain); void blo_end_image_pointer_map(FileData *fd, Main *oldmain); void blo_make_movieclip_pointer_map(FileData *fd, Main *oldmain); void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain); +void blo_make_packed_pointer_map(FileData *fd, Main *oldmain); +void blo_end_packed_pointer_map(FileData *fd, Main *oldmain); void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd); void blo_freefiledata(FileData *fd); diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 1521739258e..f4d841fd22a 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -292,7 +292,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb) memcpy(&ar->v2d, &soops->v2d, sizeof(View2D)); ar->v2d.scroll &= ~V2D_SCROLL_LEFT; - ar->v2d.scroll |= (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM_O); + ar->v2d.scroll |= (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM); ar->v2d.align = (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_POS_Y); ar->v2d.keepzoom |= (V2D_LOCKZOOM_X|V2D_LOCKZOOM_Y|V2D_KEEPASPECT); ar->v2d.keeptot = V2D_KEEPTOT_STRICT; @@ -415,7 +415,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb) ar->v2d.tot.ymax = ar->winy; ar->v2d.cur = ar->v2d.tot; ar->regiontype = RGN_TYPE_WINDOW; - ar->v2d.scroll = (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM_O); + ar->v2d.scroll = (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM); ar->v2d.align = (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_POS_Y); ar->v2d.keepzoom = (V2D_LOCKZOOM_X|V2D_LOCKZOOM_Y|V2D_LIMITZOOM|V2D_KEEPASPECT); break; diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 8a56e3c2ab8..65a60e11ab3 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -289,11 +289,10 @@ static void ntree_version_245(FileData *fd, Library *lib, bNodeTree *ntree) iuser = node->storage; if (iuser->flag & IMA_OLD_PREMUL) { iuser->flag &= ~IMA_OLD_PREMUL; - iuser->flag |= IMA_DO_PREMUL; } if (iuser->flag & IMA_DO_PREMUL) { image->flag &= ~IMA_OLD_PREMUL; - image->flag |= IMA_DO_PREMUL; + image->alpha_mode = IMA_ALPHA_STRAIGHT; } } } @@ -545,7 +544,7 @@ void blo_do_version_old_trackto_to_constraints(Object *ob) { /* create new trackto constraint from the relationship */ if (ob->track) { - bConstraint *con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO); + bConstraint *con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO); bTrackToConstraint *data = con->data; /* copy tracking settings from the object */ @@ -1840,7 +1839,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) SEQ_BEGIN (sce->ed, seq) { if (seq->type == SEQ_TYPE_IMAGE || seq->type == SEQ_TYPE_MOVIE) - seq->flag |= SEQ_MAKE_PREMUL; + seq->alpha_mode = SEQ_ALPHA_STRAIGHT; } SEQ_END } @@ -2901,20 +2900,19 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) for (ima = main->image.first; ima; ima = ima->id.next) { if (ima->flag & IMA_OLD_PREMUL) { ima->flag &= ~IMA_OLD_PREMUL; - ima->flag |= IMA_DO_PREMUL; + ima->alpha_mode = IMA_ALPHA_STRAIGHT; } } for (tex = main->tex.first; tex; tex = tex->id.next) { if (tex->iuser.flag & IMA_OLD_PREMUL) { tex->iuser.flag &= ~IMA_OLD_PREMUL; - tex->iuser.flag |= IMA_DO_PREMUL; } ima = blo_do_versions_newlibadr(fd, lib, tex->ima); if (ima && (tex->iuser.flag & IMA_DO_PREMUL)) { ima->flag &= ~IMA_OLD_PREMUL; - ima->flag |= IMA_DO_PREMUL; + ima->alpha_mode = IMA_ALPHA_STRAIGHT; } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 3f80674bf60..b1aee9f498a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -853,8 +853,12 @@ static void write_userdef(WriteData *wd) write_keymapitem(wd, kmi); } - for (bext= U.addons.first; bext; bext=bext->next) + for (bext= U.addons.first; bext; bext=bext->next) { writestruct(wd, DATA, "bAddon", 1, bext); + if (bext->prop) { + IDP_WriteProperty(bext->prop, wd); + } + } for (style= U.uistyles.first; style; style= style->next) { writestruct(wd, DATA, "uiStyle", 1, style); @@ -1231,7 +1235,7 @@ static void write_constraints(WriteData *wd, ListBase *conlist) bConstraint *con; for (con=conlist->first; con; con=con->next) { - bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + bConstraintTypeInfo *cti= BKE_constraint_get_typeinfo(con); /* Write the specific data */ if (cti && con->data) { @@ -1511,7 +1515,7 @@ static void write_vfonts(WriteData *wd, ListBase *idbase) /* direct data */ - if (vf->packedfile) { + if (vf->packedfile && !wd->current) { pf = vf->packedfile; writestruct(wd, DATA, "PackedFile", 1, pf); writedata(wd, DATA, pf->size, pf->data); @@ -1961,7 +1965,7 @@ static void write_images(WriteData *wd, ListBase *idbase) writestruct(wd, ID_IM, "Image", 1, ima); if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd); - if (ima->packedfile) { + if (ima->packedfile && !wd->current) { pf = ima->packedfile; writestruct(wd, DATA, "PackedFile", 1, pf); writedata(wd, DATA, pf->size, pf->data); @@ -2415,6 +2419,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase) for (sa= sc->areabase.first; sa; sa= sa->next) { SpaceLink *sl; Panel *pa; + uiList *ui_list; ARegion *ar; writestruct(wd, DATA, "ScrArea", 1, sa); @@ -2424,6 +2429,9 @@ static void write_screens(WriteData *wd, ListBase *scrbase) for (pa= ar->panels.first; pa; pa= pa->next) writestruct(wd, DATA, "Panel", 1, pa); + + for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) + writestruct(wd, DATA, "uiList", 1, ui_list); } sl= sa->spacedata.first; @@ -2551,20 +2559,31 @@ static void write_libraries(WriteData *wd, Main *main) a=tot= set_listbasepointers(main, lbarray); /* test: is lib being used */ - foundone = FALSE; - while (tot--) { - for (id= lbarray[tot]->first; id; id= id->next) { - if (id->us>0 && (id->flag & LIB_EXTERN)) { - foundone = TRUE; - break; + if (main->curlib && main->curlib->packedfile) + foundone = TRUE; + else { + foundone = FALSE; + while (tot--) { + for (id= lbarray[tot]->first; id; id= id->next) { + if (id->us>0 && (id->flag & LIB_EXTERN)) { + foundone = TRUE; + break; + } } + if (foundone) break; } - if (foundone) break; } - + if (foundone) { writestruct(wd, ID_LI, "Library", 1, main->curlib); + if (main->curlib->packedfile && !wd->current) { + PackedFile *pf = main->curlib->packedfile; + writestruct(wd, DATA, "PackedFile", 1, pf); + writedata(wd, DATA, pf->size, pf->data); + printf("write packed .blend: %s\n", main->curlib->name); + } + while (a--) { for (id= lbarray[a]->first; id; id= id->next) { if (id->us>0 && (id->flag & LIB_EXTERN)) { @@ -2693,7 +2712,7 @@ static void write_sounds(WriteData *wd, ListBase *idbase) writestruct(wd, ID_SO, "bSound", 1, sound); if (sound->id.properties) IDP_WriteProperty(sound->id.properties, wd); - if (sound->packedfile) { + if (sound->packedfile && !wd->current) { pf = sound->packedfile; writestruct(wd, DATA, "PackedFile", 1, pf); writedata(wd, DATA, pf->size, pf->data); diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index f80dbc45926..0606222bb17 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -30,7 +30,7 @@ set(INC ../blenlib ../makesdna ../../../intern/guardedalloc - ../../../extern/bullet2/src + ../../../extern/rangetree ../../../intern/opennl/extern ) @@ -74,6 +74,8 @@ set(SRC intern/bmesh_iterators.c intern/bmesh_iterators.h intern/bmesh_iterators_inline.h + intern/bmesh_log.c + intern/bmesh_log.h intern/bmesh_marking.c intern/bmesh_marking.h intern/bmesh_mesh.c @@ -124,6 +126,9 @@ endif() if(WITH_BULLET) add_definitions(-DWITH_BULLET) + list(APPEND INC_SYS + ${BULLET_INCLUDE_DIRS} + ) endif() if(WITH_INTERNATIONAL) diff --git a/source/blender/bmesh/SConscript b/source/blender/bmesh/SConscript index ee2380084ca..fa6bdbcf26f 100644 --- a/source/blender/bmesh/SConscript +++ b/source/blender/bmesh/SConscript @@ -41,7 +41,9 @@ incs = [ '../blenkernel', '#/intern/guardedalloc', '#/extern/bullet2/src', - '#/intern/opennl/extern', ] + '#/extern/rangetree', + '#/intern/opennl/extern' + ] defs = [] diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index 6257aa4bf3e..60d38719ddb 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -254,6 +254,7 @@ extern "C" { #include "intern/bmesh_core.h" #include "intern/bmesh_interp.h" #include "intern/bmesh_iterators.h" +#include "intern/bmesh_log.h" #include "intern/bmesh_marking.h" #include "intern/bmesh_mesh.h" #include "intern/bmesh_mesh_conv.h" diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 2362ae7237a..5eeee45e7a9 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -173,15 +173,16 @@ void BM_face_copy_shared(BMesh *bm, BMFace *f) */ BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, const int create_flag) { - BMEdge **edges2 = BLI_array_alloca(edges2, len); - BMVert **verts = BLI_array_alloca(verts, len + 1); - int e2_index = 0; - int v_index = 0; + BMEdge **edges_sort = BLI_array_alloca(edges_sort, len); + BMVert **verts_sort = BLI_array_alloca(verts_sort, len + 1); + int esort_index = 0; + int vsort_index = 0; BMFace *f = NULL; BMEdge *e; BMVert *v, *ev1, *ev2; - int i, /* j, */ v1found, reverse; + int i; + bool is_v1_found, is_reverse; /* this code is hideous, yeek. I'll have to think about ways of @@ -189,10 +190,7 @@ BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, i * _and_ the old bmesh_mf functions, so its kindof smashed together * - joeedh */ - if (!len || !v1 || !v2 || !edges || !bm) { - BLI_assert(0); - return NULL; - } + BLI_assert(len && v1 && v2 && edges && bm); /* put edges in correct order */ for (i = 0; i < len; i++) { @@ -209,14 +207,19 @@ BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, i SWAP(BMVert *, ev1, ev2); } - verts[v_index++] = ev1; + verts_sort[vsort_index++] = ev1; v = ev2; e = edges[0]; do { BMEdge *e2 = e; - verts[v_index++] = v; - edges2[e2_index++] = e; + /* vertex array is (len + 1) */ + if (UNLIKELY(vsort_index > len)) { + goto err; /* vertex in loop twice */ + } + + verts_sort[vsort_index++] = v; + edges_sort[esort_index++] = e; /* we only flag the verts to check if they are in the face more then once */ BM_ELEM_API_FLAG_ENABLE(v, _FLAG_MV); @@ -229,66 +232,67 @@ BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, i } } while (e2 != e); - if (e2 == e) + if (UNLIKELY(e2 == e)) { goto err; /* the edges do not form a closed loop */ + } e = e2; } while (e != edges[0]); - if (e2_index != len) { + if (UNLIKELY(esort_index != len)) { goto err; /* we didn't use all edges in forming the boundary loop */ } /* ok, edges are in correct order, now ensure they are going * in the correct direction */ - v1found = reverse = FALSE; + is_v1_found = is_reverse = false; for (i = 0; i < len; i++) { - if (BM_vert_in_edge(edges2[i], v1)) { + if (BM_vert_in_edge(edges_sort[i], v1)) { /* see if v1 and v2 are in the same edge */ - if (BM_vert_in_edge(edges2[i], v2)) { + if (BM_vert_in_edge(edges_sort[i], v2)) { /* if v1 is shared by the *next* edge, then the winding * is incorrect */ - if (BM_vert_in_edge(edges2[(i + 1) % len], v1)) { - reverse = TRUE; + if (BM_vert_in_edge(edges_sort[(i + 1) % len], v1)) { + is_reverse = true; break; } } - v1found = TRUE; + is_v1_found = true; } - if ((v1found == FALSE) && BM_vert_in_edge(edges2[i], v2)) { - reverse = TRUE; + if ((is_v1_found == false) && BM_vert_in_edge(edges_sort[i], v2)) { + is_reverse = true; break; } } - if (reverse) { + if (is_reverse) { for (i = 0; i < len / 2; i++) { - v = verts[i]; - verts[i] = verts[len - i - 1]; - verts[len - i - 1] = v; + v = verts_sort[i]; + verts_sort[i] = verts_sort[len - i - 1]; + verts_sort[len - i - 1] = v; } } for (i = 0; i < len; i++) { - edges2[i] = BM_edge_exists(verts[i], verts[(i + 1) % len]); - if (!edges2[i]) { + edges_sort[i] = BM_edge_exists(verts_sort[i], verts_sort[(i + 1) % len]); + if (UNLIKELY(edges_sort[i] == NULL)) { goto err; } /* check if vert is in face more then once. if the flag is disabled. we've already visited */ - if (!BM_ELEM_API_FLAG_TEST(verts[i], _FLAG_MV)) { + if (UNLIKELY(!BM_ELEM_API_FLAG_TEST(verts_sort[i], _FLAG_MV))) { goto err; } - BM_ELEM_API_FLAG_DISABLE(verts[i], _FLAG_MV); + BM_ELEM_API_FLAG_DISABLE(verts_sort[i], _FLAG_MV); } - f = BM_face_create(bm, verts, edges2, len, create_flag); + f = BM_face_create(bm, verts_sort, edges_sort, len, create_flag); /* clean up flags */ for (i = 0; i < len; i++) { - BM_ELEM_API_FLAG_DISABLE(edges2[i], _FLAG_MF); + BM_ELEM_API_FLAG_DISABLE(edges_sort[i], _FLAG_MF); } return f; @@ -297,8 +301,8 @@ err: for (i = 0; i < len; i++) { BM_ELEM_API_FLAG_DISABLE(edges[i], _FLAG_MF); } - for (i = 0; i < v_index; i++) { - BM_ELEM_API_FLAG_DISABLE(verts[i], _FLAG_MV); + for (i = 0; i < vsort_index; i++) { + BM_ELEM_API_FLAG_DISABLE(verts_sort[i], _FLAG_MV); } return NULL; diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index df58b90bc03..4ec91b8d8d7 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -603,7 +603,7 @@ void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source, { BMLoop *l_iter; BMLoop *l_first; - void **vblocks = BLI_array_alloca(vblocks, do_vertex ? source->len : 0); + void **vblocks = do_vertex ? BLI_array_alloca(vblocks, source->len) : NULL; void **blocks = BLI_array_alloca(blocks, source->len); float (*cos)[3] = BLI_array_alloca(cos, source->len); float *w = BLI_array_alloca(w, source->len); diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c new file mode 100644 index 00000000000..b821c9875db --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_log.c @@ -0,0 +1,962 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_ghash.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_mempool.h" +#include "BLI_utildefines.h" + +#include "BKE_customdata.h" + +#include "bmesh.h" +#include "bmesh_log.h" +#include "range_tree_c_api.h" + +struct BMLogEntry { + struct BMLogEntry *next, *prev; + + /* The following GHashes map from an element ID to one of the log + * types above */ + + /* Elements that were in the previous entry, but have been + * deleted */ + GHash *deleted_verts; + GHash *deleted_faces; + /* Elements that were not in the previous entry, but are in the + * result of this entry */ + GHash *added_verts; + GHash *added_faces; + + /* Vertices whose coordinates, mask value, or hflag have changed */ + GHash *modified_verts; + + BLI_mempool *pool_verts; + BLI_mempool *pool_faces; + + /* This is only needed for dropping BMLogEntries while still in + * dynamic-topology mode, as that should release vert/face IDs + * back to the BMLog but no BMLog pointer is available at that + * time. + * + * This field is not guaranteed to be valid, any use of it should + * check for NULL. */ + BMLog *log; +}; + +struct BMLog { + /* Tree of free IDs */ + struct RangeTreeUInt *unused_ids; + + /* Mapping from unique IDs to vertices and faces + * + * Each vertex and face in the log gets a unique unsigned integer + * assigned. That ID is taken from the set managed by the + * unused_ids range tree. + * + * The ID is needed because element pointers will change as they + * are created and deleted. + */ + GHash *id_to_elem; + GHash *elem_to_id; + + /* All BMLogEntrys, ordered from earliest to most recent */ + ListBase entries; + + /* The current log entry from entries list + * + * If null, then the original mesh from before any of the log + * entries is current (i.e. there is nothing left to undo.) + * + * If equal to the last entry in the entries list, then all log + * entries have been applied (i.e. there is nothing left to redo.) + */ + BMLogEntry *current_entry; +}; + +typedef struct { + float co[3]; + float mask; + char hflag; +} BMLogVert; + +typedef struct { + unsigned int v_ids[3]; +} BMLogFace; + +/************************* Get/set element IDs ************************/ + +/* Get the vertex's unique ID from the log */ +static unsigned int bm_log_vert_id_get(BMLog *log, BMVert *v) +{ + BLI_assert(BLI_ghash_haskey(log->elem_to_id, v)); + return GET_INT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, v)); +} + +/* Set the vertex's unique ID in the log */ +static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id) +{ + void *vid = SET_INT_IN_POINTER(id); + + BLI_ghash_remove(log->id_to_elem, vid, NULL, NULL); + BLI_ghash_insert(log->id_to_elem, vid, v); + BLI_ghash_remove(log->elem_to_id, v, NULL, NULL); + BLI_ghash_insert(log->elem_to_id, v, vid); +} + +/* Get a vertex from its unique ID */ +static BMVert *bm_log_vert_from_id(BMLog *log, unsigned int id) +{ + void *key = SET_INT_IN_POINTER(id); + BLI_assert(BLI_ghash_haskey(log->id_to_elem, key)); + return BLI_ghash_lookup(log->id_to_elem, key); +} + +/* Get the face's unique ID from the log */ +static unsigned int bm_log_face_id_get(BMLog *log, BMFace *f) +{ + BLI_assert(BLI_ghash_haskey(log->elem_to_id, f)); + return GET_INT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, f)); +} + +/* Set the face's unique ID in the log */ +static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id) +{ + void *fid = SET_INT_IN_POINTER(id); + + BLI_ghash_remove(log->id_to_elem, fid, NULL, NULL); + BLI_ghash_insert(log->id_to_elem, fid, f); + BLI_ghash_remove(log->elem_to_id, f, NULL, NULL); + BLI_ghash_insert(log->elem_to_id, f, fid); +} + +/* Get a face from its unique ID */ +static BMFace *bm_log_face_from_id(BMLog *log, unsigned int id) +{ + void *key = SET_INT_IN_POINTER(id); + BLI_assert(BLI_ghash_haskey(log->id_to_elem, key)); + return BLI_ghash_lookup(log->id_to_elem, key); +} + + +/************************ BMLogVert / BMLogFace ***********************/ + +/* Get a vertex's paint-mask value + * + * Returns zero if no paint-mask layer is present */ +static float vert_mask_get(BMesh *bm, BMVert *v) +{ + CustomData *cd = &bm->vdata; + if (CustomData_has_layer(&bm->vdata, CD_PAINT_MASK)) { + float *mask = CustomData_bmesh_get(cd, v->head.data, CD_PAINT_MASK); + return *mask; + } + else { + return 0; + } +} + +/* Set a vertex's paint-mask value + * + * Has no effect is no paint-mask layer is present */ +static void vert_mask_set(BMesh *bm, BMVert *v, float new_mask) +{ + CustomData *cd = &bm->vdata; + if (CustomData_has_layer(cd, CD_PAINT_MASK)) { + float *mask = CustomData_bmesh_get(cd, v->head.data, CD_PAINT_MASK); + (*mask) = new_mask; + } +} + +/* Update a BMLogVert with data from a BMVert */ +static void bm_log_vert_bmvert_copy(BMesh *bm, BMLogVert *lv, BMVert *v) +{ + copy_v3_v3(lv->co, v->co); + lv->mask = vert_mask_get(bm, v); + lv->hflag = v->head.hflag; +} + +/* Allocate and initialize a BMLogVert */ +static BMLogVert *bm_log_vert_alloc(BMesh *bm, BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + BMLogVert *lv = BLI_mempool_alloc(entry->pool_verts); + + bm_log_vert_bmvert_copy(bm, lv, v); + + return lv; +} + +/* Allocate and initialize a BMLogFace */ +static BMLogFace *bm_log_face_alloc(BMLog *log, BMFace *f) +{ + BMLogEntry *entry = log->current_entry; + BMLogFace *lf = BLI_mempool_alloc(entry->pool_faces); + BMVert *v[3]; + + BLI_assert(f->len == 3); + + BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); + + lf->v_ids[0] = bm_log_vert_id_get(log, v[0]); + lf->v_ids[1] = bm_log_vert_id_get(log, v[1]); + lf->v_ids[2] = bm_log_vert_id_get(log, v[2]); + + return lf; +} + + +/************************ Helpers for undo/redo ***********************/ + +static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts) +{ + GHashIterator gh_iter; + GHASH_ITER (gh_iter, verts) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter); + unsigned int id = GET_INT_FROM_POINTER(key); + BMVert *v = bm_log_vert_from_id(log, id); + + /* Ensure the log has the final values of the vertex before + * deleting it */ + bm_log_vert_bmvert_copy(bm, lv, v); + + BM_vert_kill(bm, v); + } +} + +static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces) +{ + GHashIterator gh_iter; + GHASH_ITER (gh_iter, faces) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + unsigned int id = GET_INT_FROM_POINTER(key); + BMFace *f = bm_log_face_from_id(log, id); + + BM_face_kill(bm, f); + } +} + +static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts) +{ + GHashIterator gh_iter; + GHASH_ITER (gh_iter, verts) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter); + BMVert *v = BM_vert_create(bm, lv->co, NULL, 0); + v->head.hflag = lv->hflag; + vert_mask_set(bm, v, lv->mask); + bm_log_vert_id_set(log, v, GET_INT_FROM_POINTER(key)); + } +} + +static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces) +{ + GHashIterator gh_iter; + GHASH_ITER (gh_iter, faces) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter); + BMVert *v[3] = {bm_log_vert_from_id(log, lf->v_ids[0]), + bm_log_vert_from_id(log, lf->v_ids[1]), + bm_log_vert_from_id(log, lf->v_ids[2])}; + BMFace *f; + + f = BM_face_create_quad_tri_v(bm, v, 3, NULL, FALSE); + bm_log_face_id_set(log, f, GET_INT_FROM_POINTER(key)); + } +} + +static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts) +{ + GHashIterator gh_iter; + GHASH_ITER (gh_iter, verts) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter); + unsigned int id = GET_INT_FROM_POINTER(key); + BMVert *v = bm_log_vert_from_id(log, id); + float mask; + + swap_v3_v3(v->co, lv->co); + SWAP(char, v->head.hflag, lv->hflag); + mask = lv->mask; + lv->mask = vert_mask_get(bm, v); + vert_mask_set(bm, v, mask); + } +} + + +/**********************************************************************/ + +/* Assign unique IDs to all vertices and faces already in the BMesh */ +static void bm_log_assign_ids(BMesh *bm, BMLog *log) +{ + BMIter iter; + BMVert *v; + BMFace *f; + + /* Generate vertex IDs */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + unsigned int id = range_tree_uint_take_any(log->unused_ids); + bm_log_vert_id_set(log, v, id); + } + + /* Generate face IDs */ + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + unsigned int id = range_tree_uint_take_any(log->unused_ids); + bm_log_face_id_set(log, f, id); + } +} + +/* Allocate an empty log entry */ +static BMLogEntry *bm_log_entry_create(void) +{ + BMLogEntry *entry = MEM_callocN(sizeof(BMLogEntry), AT); + + entry->deleted_verts = BLI_ghash_ptr_new(AT); + entry->deleted_faces = BLI_ghash_ptr_new(AT); + entry->added_verts = BLI_ghash_ptr_new(AT); + entry->added_faces = BLI_ghash_ptr_new(AT); + entry->modified_verts = BLI_ghash_ptr_new(AT); + + entry->pool_verts = BLI_mempool_create(sizeof(BMLogVert), 1, 64, 0); + entry->pool_faces = BLI_mempool_create(sizeof(BMLogFace), 1, 64, 0); + + return entry; +} + +/* Free the data in a log entry + * + * Note: does not free the log entry itself */ +static void bm_log_entry_free(BMLogEntry *entry) +{ + BLI_ghash_free(entry->deleted_verts, NULL, NULL); + BLI_ghash_free(entry->deleted_faces, NULL, NULL); + BLI_ghash_free(entry->added_verts, NULL, NULL); + BLI_ghash_free(entry->added_faces, NULL, NULL); + BLI_ghash_free(entry->modified_verts, NULL, NULL); + + BLI_mempool_destroy(entry->pool_verts); + BLI_mempool_destroy(entry->pool_faces); +} + +static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash) +{ + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, id_ghash) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + unsigned int id = GET_INT_FROM_POINTER(key); + + if (range_tree_uint_has(unused_ids, id)) { + range_tree_uint_take(unused_ids, id); + } + } +} + +static int uint_compare(const void *a_v, const void *b_v) +{ + const unsigned int *a = a_v; + const unsigned int *b = b_v; + return (*a) < (*b); +} + +/* Remap IDs to contiguous indices + * + * E.g. if the vertex IDs are (4, 1, 10, 3), the mapping will be: + * 4 -> 2 + * 1 -> 0 + * 10 -> 3 + * 3 -> 1 + */ +static GHash *bm_log_compress_ids_to_indices(unsigned int *ids, int totid) +{ + GHash *map = BLI_ghash_int_new(AT); + int i; + + qsort(ids, totid, sizeof(*ids), uint_compare); + + for (i = 0; i < totid; i++) { + void *key = SET_INT_IN_POINTER(ids[i]); + void *val = SET_INT_IN_POINTER(i); + BLI_ghash_insert(map, key, val); + } + + return map; +} + +/* Release all ID keys in id_ghash */ +static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash) +{ + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, id_ghash) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + unsigned int id = GET_INT_FROM_POINTER(key); + range_tree_uint_release(log->unused_ids, id); + } +} + +/***************************** Public API *****************************/ + +/* Allocate, initialize, and assign a new BMLog */ +BMLog *BM_log_create(BMesh *bm) +{ + BMLog *log = MEM_callocN(sizeof(*log), AT); + + log->unused_ids = range_tree_uint_alloc(0, (unsigned)-1); + log->id_to_elem = BLI_ghash_ptr_new(AT); + log->elem_to_id = BLI_ghash_ptr_new(AT); + + /* Assign IDs to all existing vertices and faces */ + bm_log_assign_ids(bm, log); + + return log; +} + +/* Allocate and initialize a new BMLog using existing BMLogEntries + * + * The 'entry' should be the last entry in the BMLog. Its prev pointer + * will be followed back to find the first entry. + * + * The unused IDs field of the log will be initialized by taking all + * keys from all GHashes in the log entry. + */ +BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry) +{ + BMLog *log = BM_log_create(bm); + + if (entry->prev) + log->current_entry = entry; + else + log->current_entry = NULL; + + /* Let BMLog manage the entry list again */ + log->entries.first = log->entries.last = entry; + if (entry) { + while (entry->prev) { + entry = entry->prev; + log->entries.first = entry; + } + entry = log->entries.last; + while (entry->next) { + entry = entry->next; + log->entries.last = entry; + } + } + + for (entry = log->entries.first; entry; entry = entry->next) { + entry->log = log; + + /* Take all used IDs */ + bm_log_id_ghash_retake(log->unused_ids, entry->deleted_verts); + bm_log_id_ghash_retake(log->unused_ids, entry->deleted_faces); + bm_log_id_ghash_retake(log->unused_ids, entry->added_verts); + bm_log_id_ghash_retake(log->unused_ids, entry->added_faces); + bm_log_id_ghash_retake(log->unused_ids, entry->modified_verts); + } + + return log; +} + +/* Free all the data in a BMLog including the log itself */ +void BM_log_free(BMLog *log) +{ + BMLogEntry *entry; + + if (log->unused_ids) + range_tree_uint_free(log->unused_ids); + + if (log->id_to_elem) + BLI_ghash_free(log->id_to_elem, NULL, NULL); + + if (log->elem_to_id) + BLI_ghash_free(log->elem_to_id, NULL, NULL); + + /* Clear the BMLog references within each entry, but do not free + * the entries themselves */ + for (entry = log->entries.first; entry; entry = entry->next) + entry->log = NULL; + + MEM_freeN(log); +} + +/* Get the number of log entries */ +int BM_log_length(const BMLog *log) +{ + return BLI_countlist(&log->entries); +} + +/* Apply a consistent ordering to BMesh vertices */ +void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log) +{ + void *varr; + void *farr; + + GHash *id_to_idx; + + BMIter bm_iter; + BMVert *v; + BMFace *f; + + int i; + + /* Put all vertex IDs into an array */ + i = 0; + varr = MEM_mallocN(sizeof(int) * bm->totvert, AT); + BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) { + ((unsigned int*)varr)[i++] = bm_log_vert_id_get(log, v); + } + + /* Put all face IDs into an array */ + i = 0; + farr = MEM_mallocN(sizeof(int) * bm->totface, AT); + BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) { + ((unsigned int*)farr)[i++] = bm_log_face_id_get(log, f); + } + + /* Create BMVert index remap array */ + id_to_idx = bm_log_compress_ids_to_indices(varr, bm->totvert); + i = 0; + BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) { + const unsigned id = bm_log_vert_id_get(log, v); + const void *key = SET_INT_IN_POINTER(id); + const void *val = BLI_ghash_lookup(id_to_idx, key); + ((int *)varr)[i++] = GET_INT_FROM_POINTER(val); + } + BLI_ghash_free(id_to_idx, NULL, NULL); + + /* Create BMFace index remap array */ + id_to_idx = bm_log_compress_ids_to_indices(farr, bm->totface); + i = 0; + BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) { + const unsigned id = bm_log_face_id_get(log, f); + const void *key = SET_INT_IN_POINTER(id); + const void *val = BLI_ghash_lookup(id_to_idx, key); + ((int *)farr)[i++] = GET_INT_FROM_POINTER(val); + } + BLI_ghash_free(id_to_idx, NULL, NULL); + + BM_mesh_remap(bm, varr, NULL, farr); + + MEM_freeN(varr); + MEM_freeN(farr); +} + +/* Start a new log entry and update the log entry list + * + * If the log entry list is empty, or if the current log entry is the + * last entry, the new entry is simply appended to the end. + * + * Otherwise, the new entry is added after the current entry and all + * following entries are deleted. + * + * In either case, the new entry is set as the current log entry. + */ +BMLogEntry *BM_log_entry_add(BMLog *log) +{ + BMLogEntry *entry, *next; + + /* Delete any entries after the current one */ + entry = log->current_entry; + if (entry) { + for (entry = entry->next; entry; entry = next) { + next = entry->next; + bm_log_entry_free(entry); + BLI_freelinkN(&log->entries, entry); + } + } + + /* Create and append the new entry */ + entry = bm_log_entry_create(); + BLI_addtail(&log->entries, entry); + entry->log = log; + log->current_entry = entry; + + return entry; +} + +/* Remove an entry from the log + * + * Uses entry->log as the log. If the log is NULL, the entry will be + * free'd but not removed from any list, nor shall its IDs be + * released. + * + * This operation is only valid on the first and last entries in the + * log. Deleting from the middle will assert. + */ +void BM_log_entry_drop(BMLogEntry *entry) +{ + BMLog *log = entry->log; + + if (!log) { + /* Unlink */ + BLI_assert(!(entry->prev && entry->next)); + if (entry->prev) + entry->prev->next = NULL; + else if (entry->next) + entry->next->prev = NULL; + + bm_log_entry_free(entry); + MEM_freeN(entry); + return; + } + + if (!entry->prev) { + /* Release IDs of elements that are deleted by this + * entry. Since the entry is at the beginning of the undo + * stack, and it's being deleted, those elements can never be + * restored. Their IDs can go back into the pool. */ + bm_log_id_ghash_release(log, entry->deleted_faces); + bm_log_id_ghash_release(log, entry->deleted_verts); + } + else if (!entry->next) { + /* Release IDs of elements that are added by this entry. Since + * the entry is at the end of the undo stack, and it's being + * deleted, those elements can never be restored. Their IDs + * can go back into the pool. */ + bm_log_id_ghash_release(log, entry->added_faces); + bm_log_id_ghash_release(log, entry->added_verts); + } + else { + BLI_assert(!"Cannot drop BMLogEntry from middle"); + } + + if (log->current_entry == entry) + log->current_entry = entry->prev; + + bm_log_entry_free(entry); + BLI_freelinkN(&log->entries, entry); +} + +/* Undo one BMLogEntry + * + * Has no effect if there's nothing left to undo */ +void BM_log_undo(BMesh *bm, BMLog *log) +{ + BMLogEntry *entry = log->current_entry; + + if (entry) { + log->current_entry = entry->prev; + + /* Delete added faces and verts */ + bm_log_faces_unmake(bm, log, entry->added_faces); + bm_log_verts_unmake(bm, log, entry->added_verts); + + /* Restore deleted verts and faces */ + bm_log_verts_restore(bm, log, entry->deleted_verts); + bm_log_faces_restore(bm, log, entry->deleted_faces); + + /* Restore vertex coordinates, mask, and hflag */ + bm_log_vert_values_swap(bm, log, entry->modified_verts); + } +} + +/* Redo one BMLogEntry + * + * Has no effect if there's nothing left to redo */ +void BM_log_redo(BMesh *bm, BMLog *log) +{ + BMLogEntry *entry = log->current_entry; + + if (!entry) { + /* Currently at the beginning of the undo stack, move to first entry */ + entry = log->entries.first; + } + else if (entry && entry->next) { + /* Move to next undo entry */ + entry = entry->next; + } + else { + /* Currently at the end of the undo stack, nothing left to redo */ + return; + } + + log->current_entry = entry; + + if (entry) { + /* Re-delete previously deleted faces and verts */ + bm_log_faces_unmake(bm, log, entry->deleted_faces); + bm_log_verts_unmake(bm, log, entry->deleted_verts); + + /* Restore previously added verts and faces */ + bm_log_verts_restore(bm, log, entry->added_verts); + bm_log_faces_restore(bm, log, entry->added_faces); + + /* Restore vertex coordinates, mask, and hflag */ + bm_log_vert_values_swap(bm, log, entry->modified_verts); + } +} + +/* Log a vertex before it is modified + * + * Before modifying vertex coordinates, masks, or hflags, call this + * function to log it's current values. This is better than logging + * after the coordinates have been modified, because only those + * vertices that are modified need to have their original values + * stored. + * + * Handles two separate cases: + * + * If the vertex was added in the current log entry, update the + * vertex in the map of added vertices. + * + * If the vertex already existed prior to the current log entry, a + * seperate key/value map of modified vertices is used (using the + * vertex's ID as the key). The values stored in that case are + * the vertex's original state so that an undo can restore the + * previous state. + * + * On undo, the current vertex state will be swapped with the stored + * state so that a subsequent redo operation will restore the newer + * vertex state. + */ +void BM_log_vert_before_modified(BMesh *bm, BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + BMLogVert *lv; + unsigned int v_id = bm_log_vert_id_get(log, v); + void *key = SET_INT_IN_POINTER(v_id); + + /* Find or create the BMLogVert entry */ + if ((lv = BLI_ghash_lookup(entry->added_verts, key))) { + bm_log_vert_bmvert_copy(bm, lv, v); + } + else if (!BLI_ghash_haskey(entry->modified_verts, key)) { + lv = bm_log_vert_alloc(bm, log, v); + BLI_ghash_insert(entry->modified_verts, key, lv); + } +} + +/* Log a new vertex as added to the BMesh + * + * The new vertex gets a unique ID assigned. It is then added to a map + * of added vertices, with the key being its ID and the value + * containing everything needed to reconstruct that vertex. + */ +void BM_log_vert_added(BMesh *bm, BMLog *log, BMVert *v) +{ + BMLogVert *lv; + unsigned int v_id = range_tree_uint_take_any(log->unused_ids); + void *key = SET_INT_IN_POINTER(v_id); + + bm_log_vert_id_set(log, v, v_id); + lv = bm_log_vert_alloc(bm, log, v); + BLI_ghash_insert(log->current_entry->added_verts, key, lv); +} + +/* Log a new face as added to the BMesh + * + * The new face gets a unique ID assigned. It is then added to a map + * of added faces, with the key being its ID and the value containing + * everything needed to reconstruct that face. + */ +void BM_log_face_added(BMLog *log, BMFace *f) +{ + BMLogFace *lf; + unsigned int f_id = range_tree_uint_take_any(log->unused_ids); + void *key = SET_INT_IN_POINTER(f_id); + + /* Only triangles are supported for now */ + BLI_assert(f->len == 3); + + bm_log_face_id_set(log, f, f_id); + lf = bm_log_face_alloc(log, f); + BLI_ghash_insert(log->current_entry->added_faces, key, lf); +} + +/* Log a vertex as removed from the BMesh + * + * A couple things can happen here: + * + * If the vertex was added as part of the current log entry, then it's + * deleted and forgotten about entirely. Its unique ID is returned to + * the unused pool. + * + * If the vertex was already part of the BMesh before the current log + * entry, it is added to a map of deleted vertices, with the key being + * its ID and the value containing everything needed to reconstruct + * that vertex. + * + * If there's a move record for the vertex, that's used as the + * vertices original location, then the move record is deleted. + */ +void BM_log_vert_removed(BMesh *bm, BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + unsigned int v_id = bm_log_vert_id_get(log, v); + void *key = SET_INT_IN_POINTER(v_id); + + if (BLI_ghash_lookup(entry->added_verts, key)) { + BLI_ghash_remove(entry->added_verts, key, NULL, NULL); + range_tree_uint_release(log->unused_ids, v_id); + } + else { + BMLogVert *lv, *lv_mod; + + lv = bm_log_vert_alloc(bm, log, v); + BLI_ghash_insert(entry->deleted_verts, key, lv); + + /* If the vertex was modified before deletion, ensure that the + * original vertex values are stored */ + if ((lv_mod = BLI_ghash_lookup(entry->modified_verts, key))) { + (*lv) = (*lv_mod); + BLI_ghash_remove(entry->modified_verts, key, NULL, NULL); + } + } +} + +/* Log a face as removed from the BMesh + * + * A couple things can happen here: + * + * If the face was added as part of the current log entry, then it's + * deleted and forgotten about entirely. Its unique ID is returned to + * the unused pool. + * + * If the face was already part of the BMesh before the current log + * entry, it is added to a map of deleted faces, with the key being + * its ID and the value containing everything needed to reconstruct + * that face. + */ +void BM_log_face_removed(BMLog *log, BMFace *f) +{ + BMLogEntry *entry = log->current_entry; + unsigned int f_id = bm_log_face_id_get(log, f); + void *key = SET_INT_IN_POINTER(f_id); + + if (BLI_ghash_lookup(entry->added_faces, key)) { + BLI_ghash_remove(entry->added_faces, key, NULL, NULL); + range_tree_uint_release(log->unused_ids, f_id); + } + else { + BMLogFace *lf; + + lf = bm_log_face_alloc(log, f); + BLI_ghash_insert(entry->deleted_faces, key, lf); + } +} + +/* Log all vertices/faces in the BMesh as added */ +void BM_log_all_added(BMesh *bm, BMLog *log) +{ + BMIter bm_iter; + BMVert *v; + BMFace *f; + + /* Log all vertices as newly created */ + BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) { + BM_log_vert_added(bm, log, v); + } + + /* Log all faces as newly created */ + BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) { + BM_log_face_added(log, f); + } +} + +/* Log all vertices/faces in the BMesh as removed */ +void BM_log_before_all_removed(BMesh *bm, BMLog *log) +{ + BMIter bm_iter; + BMVert *v; + BMFace *f; + + /* Log deletion of all faces */ + BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) { + BM_log_face_removed(log, f); + } + + /* Log deletion of all vertices */ + BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) { + BM_log_vert_removed(bm, log, v); + } +} + +/* Get the logged coordinates of a vertex + * + * Does not modify the log or the vertex */ +const float *BM_log_original_vert_co(BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + const BMLogVert *lv; + unsigned v_id = bm_log_vert_id_get(log, v); + void *key = SET_INT_IN_POINTER(v_id); + + BLI_assert(entry); + + BLI_assert(BLI_ghash_haskey(entry->modified_verts, key)); + + lv = BLI_ghash_lookup(entry->modified_verts, key); + return lv->co; +} + +/* Get the logged mask of a vertex + * + * Does not modify the log or the vertex */ +float BM_log_original_mask(BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + const BMLogVert *lv; + unsigned v_id = bm_log_vert_id_get(log, v); + void *key = SET_INT_IN_POINTER(v_id); + + BLI_assert(entry); + + BLI_assert(BLI_ghash_haskey(entry->modified_verts, key)); + + lv = BLI_ghash_lookup(entry->modified_verts, key); + return lv->mask; +} + +/************************ Debugging and Testing ***********************/ + +/* For internal use only (unit testing) */ +BMLogEntry *BM_log_current_entry(BMLog *log) +{ + return log->current_entry; +} + +/* For internal use only (unit testing) */ +RangeTreeUInt *BM_log_unused_ids(BMLog *log) +{ + return log->unused_ids; +} + +#if 0 +/* Print the list of entries, marking the current one + * + * Keep around for debugging */ +void bm_log_print(const BMLog *log, const char *description) +{ + const BMLogEntry *entry; + const char *current = " <-- current"; + int i; + + printf("%s:\n", description); + printf(" % 2d: [ initial ]%s\n", 0, + (!log->current_entry) ? current : ""); + for (entry = log->entries.first, i = 1; entry; entry = entry->next, i++) { + printf(" % 2d: [%p]%s\n", i, entry, + (entry == log->current_entry) ? current : ""); + } +} +#endif diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h new file mode 100644 index 00000000000..958ff340b43 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_log.h @@ -0,0 +1,102 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BMESH_LOG_H__ +#define __BMESH_LOG_H__ + +/* The BMLog is an interface for storing undo/redo steps as a BMesh is + * modified. It only stores changes to the BMesh, not full copies. + * + * Currently it supports the following types of changes: + * + * - Adding and removing vertices + * - Adding and removing faces + * - Moving vertices + * - Setting vertex paint-mask values + * - Setting vertex hflags + */ + +struct BMFace; +struct BMVert; +struct BMesh; +struct RangeTreeUInt; + +typedef struct BMLog BMLog; +typedef struct BMLogEntry BMLogEntry; + +/* Allocate and initialize a new BMLog */ +BMLog *BM_log_create(BMesh *bm); + +/* Allocate and initialize a new BMLog using existing BMLogEntries */ +BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry); + +/* Free all the data in a BMLog including the log itself */ +void BM_log_free(BMLog *log); + +/* Get the number of log entries */ +int BM_log_length(const BMLog *log); + +/* Apply a consistent ordering to BMesh vertices and faces */ +void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log); + +/* Start a new log entry and update the log entry list */ +BMLogEntry *BM_log_entry_add(BMLog *log); + +/* Remove an entry from the log */ +void BM_log_entry_drop(BMLogEntry *entry); + +/* Undo one BMLogEntry */ +void BM_log_undo(BMesh *bm, BMLog *log); + +/* Redo one BMLogEntry */ +void BM_log_redo(BMesh *bm, BMLog *log); + +/* Log a vertex before it is modified */ +void BM_log_vert_before_modified(BMesh *bm, BMLog *log, struct BMVert *v); + +/* Log a new vertex as added to the BMesh */ +void BM_log_vert_added(BMesh *bm, BMLog *log, struct BMVert *v); + +/* Log a new face as added to the BMesh */ +void BM_log_face_added(BMLog *log, struct BMFace *f); + +/* Log a vertex as removed from the BMesh */ +void BM_log_vert_removed(BMesh *bm, BMLog *log, struct BMVert *v); + +/* Log a face as removed from the BMesh */ +void BM_log_face_removed(BMLog *log, struct BMFace *f); + +/* Log all vertices/faces in the BMesh as added */ +void BM_log_all_added(BMesh *bm, BMLog *log); + +/* Log all vertices/faces in the BMesh as removed */ +void BM_log_before_all_removed(BMesh *bm, BMLog *log); + +/* Get the logged coordinates of a vertex */ +const float *BM_log_original_vert_co(BMLog *log, BMVert *v); + +/* Get the logged mask of a vertex */ +float BM_log_original_mask(BMLog *log, BMVert *v); + +/* For internal use only (unit testing) */ +BMLogEntry *BM_log_current_entry(BMLog *log); +struct RangeTreeUInt *BM_log_unused_ids(BMLog *log); + +#endif diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 3a7a1c4eaaa..8461ec6fe08 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -128,7 +128,7 @@ static BMOpDefine bmo_smooth_laplacian_vert_def = { "smooth_laplacian_vert", /* slots_in */ {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */ - {"lambda", BMO_OP_SLOT_FLT}, /* lambda param */ + {"lambda_factor", BMO_OP_SLOT_FLT}, /* lambda param */ {"lambda_border", BMO_OP_SLOT_FLT}, /* lambda param in border */ {"use_x", BMO_OP_SLOT_BOOL}, /* Smooth object along X axis */ {"use_y", BMO_OP_SLOT_BOOL}, /* Smooth object along Y axis */ @@ -1403,6 +1403,7 @@ static BMOpDefine bmo_bevel_def = { {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input edges and vertices */ {"offset", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */ {"segments", BMO_OP_SLOT_INT}, /* number of segments in bevel */ + {"vertex_only", BMO_OP_SLOT_BOOL}, /* only bevel vertices, not edges */ {{'\0'}}, }, /* slots_out */ diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h index 7df9c94a2f1..b8fbfbee37f 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api.h +++ b/source/blender/bmesh/intern/bmesh_operator_api.h @@ -435,7 +435,7 @@ void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_ * //whether it's a float, pointer, whatever. * // * // so to get a pointer, for example, use: - * // *((void**)BMO_iter_map_value(&oiter)); + * // *((void **)BMO_iter_map_value(&oiter)); * //or something like that. * } * \endcode diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 5f5c60dde3f..b5b6c69bd7e 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -468,7 +468,7 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first) } /** - * Returms edge length + * Returns edge length */ float BM_edge_calc_length(BMEdge *e) { @@ -476,6 +476,14 @@ float BM_edge_calc_length(BMEdge *e) } /** + * Returns edge length squared (for comparisons) + */ +float BM_edge_calc_length_squared(BMEdge *e) +{ + return len_squared_v3v3(e->v1->co, e->v2->co); +} + +/** * Utility function, since enough times we have an edge * and want to access 2 connected faces. * diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 9af792417bf..a9d6719c491 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -37,6 +37,7 @@ int BM_vert_in_edge(BMEdge *e, BMVert *v); int BM_verts_in_edge(BMVert *v1, BMVert *v2, BMEdge *e); float BM_edge_calc_length(BMEdge *e); +float BM_edge_calc_length_squared(BMEdge *e); int BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb); int BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb); BMVert *BM_edge_other_vert(BMEdge *e, BMVert *v); diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 126d0f46119..eb8e84da63f 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -34,6 +34,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) { const float offset = BMO_slot_float_get(op->slots_in, "offset"); const int seg = BMO_slot_int_get(op->slots_in, "segments"); + const int vonly = BMO_slot_bool_get(op->slots_in, "vertex_only"); if (offset > 0) { BMOIter siter; @@ -54,7 +55,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) } } - BM_mesh_bevel(bm, offset, seg); + BM_mesh_bevel(bm, offset, seg, vonly); BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); } diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index 9a58d7acfb9..f288901c272 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -483,7 +483,7 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op) { BMOperator dupop, extop; float cent[3], dvec[3]; - float axis[3] = {0.0f, 0.0f, 1.0f}; + float axis[3]; float rmat[3][3]; float phi; int steps, do_dupli, a, usedvec; diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index 956d9e5767e..2cca3fcb24a 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -315,27 +315,29 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) /* calculate verts to delete */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - found = FALSE; + if (v->e) { /* only deal with verts attached to geometry [#33651] */ + found = FALSE; - BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, EXT_INPUT) || !BMO_elem_flag_test(bm, e, EXT_DEL)) { - found = TRUE; - break; - } - } - - /* avoid an extra loop */ - if (found == TRUE) { - BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) { + BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) { + if (!BMO_elem_flag_test(bm, e, EXT_INPUT) || !BMO_elem_flag_test(bm, e, EXT_DEL)) { found = TRUE; break; } } - } - if (found == FALSE) { - BMO_elem_flag_enable(bm, v, EXT_DEL); + /* avoid an extra loop */ + if (found == TRUE) { + BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) { + if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) { + found = TRUE; + break; + } + } + } + + if (found == FALSE) { + BMO_elem_flag_enable(bm, v, EXT_DEL); + } } } diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c index 4a367a8fd6f..ce584686757 100644 --- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c +++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c @@ -538,7 +538,7 @@ void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) int i; int m_vertex_id; int usex, usey, usez, preserve_volume; - float lambda, lambda_border; + float lambda_factor, lambda_border; float w; BMOIter siter; BMVert *v; @@ -553,7 +553,7 @@ void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) memset_laplacian_system(sys, 0); BM_mesh_elem_index_ensure(bm, BM_VERT); - lambda = BMO_slot_float_get(op->slots_in, "lambda"); + lambda_factor = BMO_slot_float_get(op->slots_in, "lambda_factor"); lambda_border = BMO_slot_float_get(op->slots_in, "lambda_border"); sys->min_area = 0.00001f; usex = BMO_slot_bool_get(op->slots_in, "use_x"); @@ -592,12 +592,12 @@ void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) i = m_vertex_id; if (sys->zerola[i] == 0) { w = sys->vweights[i] * sys->ring_areas[i]; - sys->vweights[i] = (w == 0.0f) ? 0.0f : -lambda / (4.0f * w); + sys->vweights[i] = (w == 0.0f) ? 0.0f : -lambda_factor / (4.0f * w); w = sys->vlengths[i]; sys->vlengths[i] = (w == 0.0f) ? 0.0f : -lambda_border * 2.0f / w; if (!vert_is_boundary(v)) { - nlMatrixAdd(i, i, 1.0f + lambda / (4.0f * sys->ring_areas[i])); + nlMatrixAdd(i, i, 1.0f + lambda_factor / (4.0f * sys->ring_areas[i])); } else { nlMatrixAdd(i, i, 1.0f + lambda_border * 2.0f); diff --git a/source/blender/bmesh/operators/bmo_symmetrize.c b/source/blender/bmesh/operators/bmo_symmetrize.c index 248c7268ac6..172f0d40b27 100644 --- a/source/blender/bmesh/operators/bmo_symmetrize.c +++ b/source/blender/bmesh/operators/bmo_symmetrize.c @@ -361,6 +361,12 @@ static BMFace *symm_face_create_v(BMesh *bm, BMFace *example, BMFace *f_new; int i; + /* TODO: calling symmetrize in dynamic-topology sculpt mode + * frequently tries to create faces of length less than two, + * should investigate further */ + if (len < 3) + return NULL; + for (i = 0; i < len; i++) { int j = (i + 1) % len; fe[i] = BM_edge_exists(fv[i], fv[j]); @@ -374,6 +380,7 @@ static BMFace *symm_face_create_v(BMesh *bm, BMFace *example, BM_elem_attrs_copy(bm, bm, example, f_new); BM_face_select_set(bm, f_new, TRUE); BMO_elem_flag_enable(bm, f_new, SYMM_OUTPUT_GEOM); + return f_new; } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index fbac538eb7f..759246c38e0 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -119,6 +119,7 @@ typedef struct BevelParams { float offset; /* blender units to offset each side of a beveled edge */ int seg; /* number of segments in beveled edge profile */ + int vertex_only; /* bevel vertices only */ } BevelParams; // #pragma GCC diagnostic ignored "-Wpadded" @@ -166,6 +167,7 @@ static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert { NewVert *nv = mesh_vert(vm, i, j, k); nv->v = BM_vert_create(bm, nv->co, eg, 0); + BM_elem_flag_disable(nv->v, BM_ELEM_TAG); } static void copy_mesh_vert(VMesh *vm, int ito, int jto, int kto, @@ -698,8 +700,9 @@ static void snap_to_edge_profile(EdgeHalf *e, const float va[3], const float vb[ * of a vertex on the the boundary of the beveled vertex bv->v. * Also decide on the mesh pattern that will be used inside the boundary. * Doesn't make the actual BMVerts */ -static void build_boundary(MemArena *mem_arena, BevVert *bv) +static void build_boundary(BevelParams *bp, BevVert *bv) { + MemArena *mem_arena = bp->mem_arena; EdgeHalf *efirst, *e; BoundVert *v; VMesh *vm; @@ -707,9 +710,13 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv) const float *no; float lastd; - e = efirst = next_bev(bv, NULL); vm = bv->vmesh; + if (bp->vertex_only) + e = efirst = &bv->edges[0]; + else + e = efirst = next_bev(bv, NULL); + BLI_assert(bv->edgecount >= 2); /* since bevel edges incident to 2 faces */ if (bv->edgecount == 2 && bv->selcount == 1) { @@ -734,7 +741,7 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv) return; } - lastd = e->offset; + lastd = bp->vertex_only ? bp->offset : e->offset; vm->boundstart = NULL; do { if (e->is_bev) { @@ -1276,7 +1283,7 @@ static void bevel_build_trifan(BMesh *bm, BevVert *bv) else { BLI_assert(0); } } else { - if (l_fan->v == v_fan) { l_fan = l_fan; } + if (l_fan->v == v_fan) { /* l_fan = l_fan; */ } else if (l_fan->next->v == v_fan) { l_fan = l_fan->next; } else if (l_fan->prev->v == v_fan) { l_fan = l_fan->prev; } else { BLI_assert(0); } @@ -1325,8 +1332,9 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) /* Given that the boundary is built, now make the actual BMVerts * for the boundary and the interior of the vertex mesh. */ -static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) +static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) { + MemArena *mem_arena = bp->mem_arena; VMesh *vm = bv->vmesh; BoundVert *v, *weld1, *weld2; int n, ns, ns2, i, k, weld; @@ -1504,7 +1512,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) */ BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(bme, BM_ELEM_TAG)) { + if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) { BLI_assert(BM_edge_is_manifold(bme)); nsel++; } @@ -1513,7 +1521,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) BM_BEVEL_EDGE_TAG_DISABLE(bme); } - if (nsel == 0) { + if ((nsel == 0 && !bp->vertex_only) || (ntot < 3 && bp->vertex_only)) { /* signal this vert isn't being beveled */ BM_elem_flag_disable(v, BM_ELEM_TAG); return; @@ -1570,7 +1578,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) } bme = e->e; BM_BEVEL_EDGE_TAG_ENABLE(bme); - if (BM_elem_flag_test(bme, BM_ELEM_TAG)) { + if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) { e->is_bev = TRUE; e->seg = bp->seg; } @@ -1626,8 +1634,8 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) BM_BEVEL_EDGE_TAG_DISABLE(e->e); } - build_boundary(bp->mem_arena, bv); - build_vmesh(bp->mem_arena, bm, bv); + build_boundary(bp, bv); + build_vmesh(bp, bm, bv); } /* Face f has at least one beveled vertex. Rebuild f */ @@ -1790,7 +1798,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) * * \warning all tagged edges _must_ be manifold. */ -void BM_mesh_bevel(BMesh *bm, const float offset, const float segments) +void BM_mesh_bevel(BMesh *bm, const float offset, const float segments, const int vertex_only) { BMIter iter; BMVert *v; @@ -1799,6 +1807,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const float segments) bp.offset = offset; bp.seg = segments; + bp.vertex_only = vertex_only; if (bp.offset > 0) { /* primary alloc */ @@ -1814,9 +1823,11 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const float segments) } /* Build polygons for edges */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - bevel_build_edge_polygons(bm, &bp, e); + if (!bp.vertex_only) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + bevel_build_edge_polygons(bm, &bp, e); + } } } diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h index a80e4f3a4a2..d56aa13c984 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.h +++ b/source/blender/bmesh/tools/bmesh_bevel.h @@ -27,6 +27,6 @@ * \ingroup bmesh */ -void BM_mesh_bevel(BMesh *bm, const float offset, const float segments); +void BM_mesh_bevel(BMesh *bm, const float offset, const float segments, const int vertex_only); #endif /* __BMESH_BEVEL_H__ */ diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c index acdab2510a4..71c1cedbd5e 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c +++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c @@ -268,7 +268,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const int BMW_end(&walker); #else - BM_elem_index_set(v_first, (offset + depth) % nth ? VERT_INDEX_IGNORE : VERT_INDEX_DO_COLLAPSE); /* set_dirty! */ + BM_elem_index_set(v_first, ((offset + depth) % nth) ? VERT_INDEX_IGNORE : VERT_INDEX_DO_COLLAPSE); /* set_dirty! */ vert_seek_b_tot = 0; vert_seek_b[vert_seek_b_tot++] = v_first; diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 44e74e320cc..3d0ceb560ed 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -1194,7 +1194,7 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurv calc_joint_parent_mat_rest(par, NULL, root, node); mult_m4_m4m4(temp, par, matfra); - // evaluate_joint_world_transform_at_frame(temp, NULL,, node, fra); + // evaluate_joint_world_transform_at_frame(temp, NULL, node, fra); // calc special matrix mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); @@ -1529,7 +1529,7 @@ Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node, calc_joint_parent_mat_rest(par, NULL, root, node); mult_m4_m4m4(temp, par, matfra); - // evaluate_joint_world_transform_at_frame(temp, NULL,, node, fra); + // evaluate_joint_world_transform_at_frame(temp, NULL, node, fra); // calc special matrix mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 084f71e0afc..b7797b51252 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -614,7 +614,6 @@ MTex *DocumentImporter::create_texture(COLLADAFW::EffectCommon *ef, COLLADAFW::T ma->mtex[i]->texco = TEXCO_UV; ma->mtex[i]->tex = add_texture("Texture"); ma->mtex[i]->tex->type = TEX_IMAGE; - ma->mtex[i]->tex->imaflag &= ~TEX_USEALPHA; ma->mtex[i]->tex->ima = uid_image_map[ima_uid]; texindex_texarray_map[ctex.getTextureMapId()].push_back(ma->mtex[i]); @@ -745,7 +744,6 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); if (mtex != NULL) { mtex->mapto = MAP_ALPHA; - mtex->tex->imaflag |= TEX_USEALPHA; i++; ma->spectra = ma->alpha = 0; ma->mode |= MA_ZTRANSP | MA_TRANSP; diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp index aba290f5ce4..55fe2034869 100644 --- a/source/blender/collada/ImageExporter.cpp +++ b/source/blender/collada/ImageExporter.cpp @@ -89,7 +89,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) // make absolute destination path BLI_strncpy(export_file, name.c_str(), sizeof(export_file)); - BKE_add_image_extension(export_file, imageFormat.imtype); + BKE_add_image_extension(export_file, &imageFormat); BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file); diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index de8d1e85eb9..8256618bfa3 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -1083,8 +1083,8 @@ void MeshImporter::optimize_material_assignments() Object *ob = (*it); Mesh *me = (Mesh *) ob->data; if (me->id.us==1) { - bc_copy_materials_to_data(ob,me); - bc_remove_materials_from_object(ob,me); + bc_copy_materials_to_data(ob, me); + bc_remove_materials_from_object(ob, me); bc_remove_mark(ob); } else if (me->id.us > 1) @@ -1101,10 +1101,10 @@ void MeshImporter::optimize_material_assignments() } } if (can_move) { - bc_copy_materials_to_data(ref_ob,me); + bc_copy_materials_to_data(ref_ob, me); for (int index = 0; index < mesh_users.size(); index++) { Object *object = mesh_users[index]; - bc_remove_materials_from_object(object,me); + bc_remove_materials_from_object(object, me); bc_remove_mark(object); } } diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 8259cb6f297..0e8ddf4068c 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -491,10 +491,10 @@ set(SRC operations/COM_ColorMatteOperation.h operations/COM_ChannelMatteOperation.cpp operations/COM_ChannelMatteOperation.h - operations/COM_ConvertPremulToKeyOperation.cpp - operations/COM_ConvertPremulToKeyOperation.h - operations/COM_ConvertKeyToPremulOperation.cpp - operations/COM_ConvertKeyToPremulOperation.h + operations/COM_ConvertPremulToStraightOperation.cpp + operations/COM_ConvertPremulToStraightOperation.h + operations/COM_ConvertStraightToPremulOperation.cpp + operations/COM_ConvertStraightToPremulOperation.h operations/COM_ReadBufferOperation.cpp operations/COM_ReadBufferOperation.h diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index 25f06108d96..9beccba0c73 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -41,7 +41,8 @@ using namespace std; * In order to get to an efficient model for execution, several steps are being done. these steps are explained below. * * @section EM_Step1 Step 1: translating blender node system to the new compsitor system - * Blenders node structure is based on C structs (DNA). These structs are not efficient in the new architecture. We want to use classes in order to simplify the system. + * Blenders node structure is based on C structs (DNA). These structs are not efficient in the new architecture. + * We want to use classes in order to simplify the system. * during this step the blender node_tree is evaluated and converted to a CPP node system. * * @see ExecutionSystem @@ -49,13 +50,17 @@ using namespace std; * @see Node * * @section EM_Step2 Step2: translating nodes to operations - * Ungrouping the GroupNodes. Group nodes are node_tree's in node_tree's. The new system only supports a single level of node_tree. We will 'flatten' the system in a single level. + * Ungrouping the GroupNodes. Group nodes are node_tree's in node_tree's. + * The new system only supports a single level of node_tree. We will 'flatten' the system in a single level. * @see GroupNode * @see ExecutionSystemHelper.ungroup * - * Every node has the ability to convert itself to operations. The node itself is responsible to create a correct NodeOperation setup based on its internal settings. - * Most Node only need to convert it to its NodeOperation. Like a ColorToBWNode doesn't check anything, but replaces itself with a ConvertColorToBWOperation. - * More complex nodes can use different NodeOperation based on settings; like MixNode. based on the selected Mixtype a different operation will be used. + * Every node has the ability to convert itself to operations. The node itself is responsible to create a correct + * NodeOperation setup based on its internal settings. + * Most Node only need to convert it to its NodeOperation. Like a ColorToBWNode doesn't check anything, + * but replaces itself with a ConvertColorToBWOperation. + * More complex nodes can use different NodeOperation based on settings; like MixNode. + * based on the selected Mixtype a different operation will be used. * for more information see the page about creating new Nodes. [@subpage newnode] * * @see ExecutionSystem.convertToOperations @@ -63,9 +68,12 @@ using namespace std; * @see NodeOperation base class for all operations in the system * * @section EM_Step3 Step3: add additional conversions to the operation system - * - Data type conversions: the system has 3 data types COM_DT_VALUE, COM_DT_VECTOR, COM_DT_COLOR. The user can connect a Value socket to a color socket. As values are ordered differently than colors a conversion happens. + * - Data type conversions: the system has 3 data types COM_DT_VALUE, COM_DT_VECTOR, COM_DT_COLOR. + * The user can connect a Value socket to a color socket. + * As values are ordered differently than colors a conversion happens. * - * - Image size conversions: the system can automatically convert when resolutions do not match. An InputSocket has a resize mode. This can be any of the following settings. + * - Image size conversions: the system can automatically convert when resolutions do not match. + * An InputSocket has a resize mode. This can be any of the following settings. * - [@ref InputSocketResizeMode.COM_SC_CENTER]: The center of both images are aligned * - [@ref InputSocketResizeMode.COM_SC_FIT_WIDTH]: The width of both images are aligned * - [@ref InputSocketResizeMode.COM_SC_FIT_HEIGHT]: the height of both images are aligned @@ -77,8 +85,10 @@ using namespace std; * @see Converter.convertResolution Image size conversions * * @section EM_Step4 Step4: group operations in executions groups - * ExecutionGroup are groups of operations that are calculated as being one bigger operation. All operations will be part of an ExecutionGroup. - * Complex nodes will be added to separate groups. Between ExecutionGroup's the data will be stored in MemoryBuffers. ReadBufferOperations and WriteBufferOperations are added where needed. + * ExecutionGroup are groups of operations that are calculated as being one bigger operation. + * All operations will be part of an ExecutionGroup. + * Complex nodes will be added to separate groups. Between ExecutionGroup's the data will be stored in MemoryBuffers. + * ReadBufferOperations and WriteBufferOperations are added where needed. * * <pre> * diff --git a/source/blender/compositor/intern/COM_NodeOperation.cpp b/source/blender/compositor/intern/COM_NodeOperation.cpp index a05c37e1b09..d33b8085022 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.cpp +++ b/source/blender/compositor/intern/COM_NodeOperation.cpp @@ -34,6 +34,7 @@ NodeOperation::NodeOperation() : NodeBase() this->m_complex = false; this->m_width = 0; this->m_height = 0; + this->m_isResolutionSet = false; this->m_openCL = false; this->m_btree = NULL; } diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index f856d8e6a11..60ffadf60f7 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -81,6 +81,7 @@ private: */ const bNodeTree *m_btree; + bool m_isResolutionSet; public: /** * @brief is this node an operation? @@ -170,7 +171,7 @@ public: virtual void deinitExecution(); bool isResolutionSet() { - return this->m_width != 0 && this->m_height != 0; + return this->m_isResolutionSet; } /** @@ -181,6 +182,7 @@ public: if (!isResolutionSet()) { this->m_width = resolution[0]; this->m_height = resolution[1]; + this->m_isResolutionSet = true; } } @@ -254,8 +256,8 @@ public: protected: NodeOperation(); - void setWidth(unsigned int width) { this->m_width = width; } - void setHeight(unsigned int height) { this->m_height = height; } + void setWidth(unsigned int width) { this->m_width = width; this->m_isResolutionSet = true; } + void setHeight(unsigned int height) { this->m_height = height; this->m_isResolutionSet = true; } SocketReader *getInputSocketReader(unsigned int inputSocketindex); NodeOperation *getInputOperation(unsigned int inputSocketindex); diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp index d5da079c9fd..bb60a629812 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp +++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp @@ -65,12 +65,16 @@ void OpenCLDevice::execute(WorkPackage *work) executionGroup->finalizeChunkExecution(chunkNumber, inputBuffers); } -cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, SocketReader *reader) +cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, + list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, + SocketReader *reader) { return COM_clAttachMemoryBufferToKernelParameter(kernel, parameterIndex, offsetIndex, cleanup, inputMemoryBuffers, (ReadBufferOperation *)reader); } -cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, ReadBufferOperation *reader) +cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, + list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, + ReadBufferOperation *reader) { cl_int error; diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp index 254dfb7b9c7..a7149cc63b2 100644 --- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp +++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp @@ -20,8 +20,8 @@ */ #include "COM_ConvertAlphaNode.h" -#include "COM_ConvertPremulToKeyOperation.h" -#include "COM_ConvertKeyToPremulOperation.h" +#include "COM_ConvertPremulToStraightOperation.h" +#include "COM_ConvertStraightToPremulOperation.h" #include "COM_ExecutionSystem.h" void ConvertAlphaNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) @@ -31,10 +31,10 @@ void ConvertAlphaNode::convertToOperations(ExecutionSystem *graph, CompositorCon /* value hardcoded in rna_nodetree.c */ if (node->custom1 == 1) { - operation = new ConvertPremulToKeyOperation(); + operation = new ConvertPremulToStraightOperation(); } else { - operation = new ConvertKeyToPremulOperation(); + operation = new ConvertStraightToPremulOperation(); } this->getInputSocket(0)->relinkConnections(operation->getInputSocket(0), 0, graph); diff --git a/source/blender/compositor/operations/COM_ConvertPremulToKeyOperation.cpp b/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.cpp index b92da4c324f..2af4b55de1a 100644 --- a/source/blender/compositor/operations/COM_ConvertPremulToKeyOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.cpp @@ -19,10 +19,10 @@ * Dalai Felinto */ -#include "COM_ConvertPremulToKeyOperation.h" +#include "COM_ConvertPremulToStraightOperation.h" #include "BLI_math.h" -ConvertPremulToKeyOperation::ConvertPremulToKeyOperation() : NodeOperation() +ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : NodeOperation() { this->addInputSocket(COM_DT_COLOR); this->addOutputSocket(COM_DT_COLOR); @@ -30,12 +30,12 @@ ConvertPremulToKeyOperation::ConvertPremulToKeyOperation() : NodeOperation() this->m_inputColor = NULL; } -void ConvertPremulToKeyOperation::initExecution() +void ConvertPremulToStraightOperation::initExecution() { this->m_inputColor = getInputSocketReader(0); } -void ConvertPremulToKeyOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +void ConvertPremulToStraightOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) { float inputValue[4]; float alpha; @@ -54,7 +54,7 @@ void ConvertPremulToKeyOperation::executePixel(float output[4], float x, float y output[3] = alpha; } -void ConvertPremulToKeyOperation::deinitExecution() +void ConvertPremulToStraightOperation::deinitExecution() { this->m_inputColor = NULL; } diff --git a/source/blender/compositor/operations/COM_ConvertPremulToKeyOperation.h b/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.h index 04a9965858d..9d3ab156555 100644 --- a/source/blender/compositor/operations/COM_ConvertPremulToKeyOperation.h +++ b/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.h @@ -19,8 +19,8 @@ * Dalai Felinto */ -#ifndef _COM_ConvertPremulToKeyOperation_h -#define _COM_ConvertPremulToKeyOperation_h +#ifndef _COM_ConvertPremulToStraightOperation_h +#define _COM_ConvertPremulToStraightOperation_h #include "COM_NodeOperation.h" @@ -28,14 +28,14 @@ * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class ConvertPremulToKeyOperation : public NodeOperation { +class ConvertPremulToStraightOperation : public NodeOperation { private: SocketReader *m_inputColor; public: /** * Default constructor */ - ConvertPremulToKeyOperation(); + ConvertPremulToStraightOperation(); /** * the inner loop of this program diff --git a/source/blender/compositor/operations/COM_ConvertKeyToPremulOperation.cpp b/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.cpp index 4497db52a0f..ae55d949ff2 100644 --- a/source/blender/compositor/operations/COM_ConvertKeyToPremulOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.cpp @@ -19,10 +19,10 @@ * Dalai Felinto */ -#include "COM_ConvertKeyToPremulOperation.h" +#include "COM_ConvertStraightToPremulOperation.h" #include "BLI_math.h" -ConvertKeyToPremulOperation::ConvertKeyToPremulOperation() : NodeOperation() +ConvertStraightToPremulOperation::ConvertStraightToPremulOperation() : NodeOperation() { this->addInputSocket(COM_DT_COLOR); this->addOutputSocket(COM_DT_COLOR); @@ -30,12 +30,12 @@ ConvertKeyToPremulOperation::ConvertKeyToPremulOperation() : NodeOperation() this->m_inputColor = NULL; } -void ConvertKeyToPremulOperation::initExecution() +void ConvertStraightToPremulOperation::initExecution() { this->m_inputColor = getInputSocketReader(0); } -void ConvertKeyToPremulOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +void ConvertStraightToPremulOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) { float inputValue[4]; float alpha; @@ -49,7 +49,7 @@ void ConvertKeyToPremulOperation::executePixel(float output[4], float x, float y output[3] = alpha; } -void ConvertKeyToPremulOperation::deinitExecution() +void ConvertStraightToPremulOperation::deinitExecution() { this->m_inputColor = NULL; } diff --git a/source/blender/compositor/operations/COM_ConvertKeyToPremulOperation.h b/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.h index 502674e26db..d0191f292d2 100644 --- a/source/blender/compositor/operations/COM_ConvertKeyToPremulOperation.h +++ b/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.h @@ -19,8 +19,8 @@ * Dalai Felinto */ -#ifndef _COM_ConvertKeyToPremulOperation_h -#define _COM_ConvertKeyToPremulOperation_h +#ifndef _COM_ConvertStraightToPremulOperation_h +#define _COM_ConvertStraightToPremulOperation_h #include "COM_NodeOperation.h" @@ -28,14 +28,14 @@ * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class ConvertKeyToPremulOperation : public NodeOperation { +class ConvertStraightToPremulOperation : public NodeOperation { private: SocketReader *m_inputColor; public: /** * Default constructor */ - ConvertKeyToPremulOperation(); + ConvertStraightToPremulOperation(); /** * the inner loop of this program diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp index 7d05202df96..47b69ec87f9 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp @@ -141,7 +141,7 @@ void OutputSingleLayerOperation::deinitExecution() IMB_colormanagement_imbuf_for_write(ibuf, TRUE, FALSE, m_viewSettings, m_displaySettings, this->m_format); - BKE_makepicstring(filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format->imtype, + BKE_makepicstring(filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format, (this->m_rd->scemode & R_EXTENSION), true); if (0 == BKE_imbuf_write(ibuf, filename, this->m_format)) @@ -205,7 +205,7 @@ void OutputOpenExrMultiLayerOperation::deinitExecution() char filename[FILE_MAX]; void *exrhandle = IMB_exr_get_handle(); - BKE_makepicstring(filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER, + BKE_makepicstring_from_type(filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER, (this->m_rd->scemode & R_EXTENSION), true); BLI_make_existing_file(filename); diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index ca036a8540e..6687cce88cd 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -62,16 +62,28 @@ /* Check if the operator can be run from the current context */ static int change_frame_poll(bContext *C) { - ScrArea *curarea = CTX_wm_area(C); + ScrArea *sa = CTX_wm_area(C); /* XXX temp? prevent changes during render */ - if (G.is_rendering) return 0; + if (G.is_rendering) return FALSE; - /* as long as there is an active area, and it isn't a Graph Editor - * (since the Graph Editor has its own version which does extra stuff), - * we're fine + /* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION, + * this shouldn't show up in 3D editor (or others without 2D timeline view) via search */ - return ((curarea) && (curarea->spacetype != SPACE_IPO)); + if (sa) { + if (ELEM5(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { + return TRUE; + } + else if (sa->spacetype == SPACE_IPO) { + /* NOTE: Graph Editor has special version which does some extra stuff. + * No need to show the generic error message for that case though! + */ + return FALSE; + } + } + + CTX_wm_operator_poll_msg_set(C, "Expected an timeline/animation area to be active"); + return FALSE; } /* Set the new frame number */ @@ -83,7 +95,7 @@ static void change_frame_apply(bContext *C, wmOperator *op) /* set the new frame number */ CFRA = RNA_int_get(op->ptr, "frame"); FRAMENUMBER_MIN_CLAMP(CFRA); - SUBFRA = 0.f; + SUBFRA = 0.0f; /* do updates */ sound_seek_scene(bmain, scene); @@ -161,7 +173,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event) static void ANIM_OT_change_frame(wmOperatorType *ot) { /* identifiers */ - ot->name = "Change frame"; + ot->name = "Change Frame"; ot->idname = "ANIM_OT_change_frame"; ot->description = "Interactively change the current frame number"; @@ -175,7 +187,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_POINTER; /* rna */ - RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); + ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); } /* ****************** set preview range operator ****************************/ diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 8ba330e7c3c..9add193a514 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -540,8 +540,8 @@ static float setting_get_rna_value(PointerRNA *ptr, PropertyRNA *prop, int index enum { VISUALKEY_NONE = 0, VISUALKEY_LOC, - VISUALKEY_ROT - /* VISUALKEY_SCA */ /* TODO - looks like support can be added now */ + VISUALKEY_ROT, + VISUALKEY_SCA, }; /* This helper function determines if visual-keyframing should be used when @@ -560,7 +560,7 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) /* validate data */ if (ELEM3(NULL, ptr, ptr->data, prop)) return 0; - + /* get first constraint and determine type of keyframe constraints to check for * - constraints can be on either Objects or PoseChannels, so we only check if the * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for @@ -586,7 +586,7 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) /* check if any data to search using */ if (ELEM(NULL, con, identifier) && (has_parent == FALSE)) return 0; - + /* location or rotation identifiers only... */ if (identifier == NULL) { printf("%s failed: NULL identifier\n", __func__); @@ -598,6 +598,9 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) else if (strstr(identifier, "rotation")) { searchtype = VISUALKEY_ROT; } + else if (strstr(identifier, "scale")) { + searchtype = VISUALKEY_SCA; + } else { printf("%s failed: identifier - '%s'\n", __func__, identifier); return 0; @@ -628,7 +631,7 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) return 1; case CONSTRAINT_TYPE_KINEMATIC: return 1; - + /* single-transform constraits */ case CONSTRAINT_TYPE_TRACKTO: if (searchtype == VISUALKEY_ROT) return 1; @@ -642,15 +645,21 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) case CONSTRAINT_TYPE_LOCLIMIT: if (searchtype == VISUALKEY_LOC) return 1; break; - case CONSTRAINT_TYPE_ROTLIKE: - if (searchtype == VISUALKEY_ROT) return 1; + case CONSTRAINT_TYPE_SIZELIMIT: + if (searchtype == VISUALKEY_SCA) return 1; break; case CONSTRAINT_TYPE_DISTLIMIT: if (searchtype == VISUALKEY_LOC) return 1; break; + case CONSTRAINT_TYPE_ROTLIKE: + if (searchtype == VISUALKEY_ROT) return 1; + break; case CONSTRAINT_TYPE_LOCLIKE: if (searchtype == VISUALKEY_LOC) return 1; break; + case CONSTRAINT_TYPE_SIZELIKE: + if (searchtype == VISUALKEY_SCA) return 1; + break; case CONSTRAINT_TYPE_LOCKTRACK: if (searchtype == VISUALKEY_ROT) return 1; break; @@ -675,45 +684,26 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_index) { const char *identifier = RNA_property_identifier(prop); + float tmat[4][4]; + int rotmode; /* handle for Objects or PoseChannels only + * - only Location, Rotation or Scale keyframes are supported curently * - constraints can be on either Objects or PoseChannels, so we only check if the - * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for + * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for * those structs, allowing us to identify the owner of the data - * - assume that array_index will be sane + * - assume that array_index will be sane */ if (ptr->type == &RNA_Object) { Object *ob = (Object *)ptr->data; - - /* only Location or Rotation keyframes are supported now */ + + /* Loc code is specific... */ if (strstr(identifier, "location")) { return ob->obmat[3][array_index]; } - else if (strstr(identifier, "rotation_euler")) { - float eul[3]; - - mat4_to_eulO(eul, ob->rotmode, ob->obmat); - return eul[array_index]; - } - else if (strstr(identifier, "rotation_quaternion")) { - float trimat[3][3], quat[4]; - - copy_m3_m4(trimat, ob->obmat); - mat3_to_quat_is_ok(quat, trimat); - - return quat[array_index]; - } - else if (strstr(identifier, "rotation_axis_angle")) { - float axis[3], angle; - - mat4_to_axis_angle(axis, &angle, ob->obmat); - - /* w = 0, x,y,z = 1,2,3 */ - if (array_index == 0) - return angle; - else - return axis[array_index - 1]; - } + + copy_m4_m4(tmat, ob->obmat); + rotmode = ob->rotmode; } else if (ptr->type == &RNA_PoseBone) { Object *ob = (Object *)ptr->id.data; /* we assume that this is always set, and is an object */ @@ -726,42 +716,53 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i * will be what owns the pose-channel that is getting this anyway. */ copy_m4_m4(tmat, pchan->pose_mat); - constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + rotmode = pchan->rotmode; - /* Loc, Rot/Quat keyframes are supported... */ + /* Loc code is specific... */ if (strstr(identifier, "location")) { /* only use for non-connected bones */ - if ((pchan->bone->parent) && !(pchan->bone->flag & BONE_CONNECTED)) + if ((pchan->bone->parent == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) return tmat[3][array_index]; - else if (pchan->bone->parent == NULL) - return tmat[3][array_index]; - } - else if (strstr(identifier, "rotation_euler")) { - float eul[3]; - - mat4_to_eulO(eul, pchan->rotmode, tmat); - return eul[array_index]; - } - else if (strstr(identifier, "rotation_quaternion")) { - float trimat[3][3], quat[4]; - - copy_m3_m4(trimat, tmat); - mat3_to_quat_is_ok(quat, trimat); - - return quat[array_index]; - } - else if (strstr(identifier, "rotation_axis_angle")) { - float axis[3], angle; - - mat4_to_axis_angle(axis, &angle, tmat); - - /* w = 0, x,y,z = 1,2,3 */ - if (array_index == 0) - return angle; - else - return axis[array_index - 1]; } } + else { + return setting_get_rna_value(ptr, prop, array_index); + } + + /* Rot/Scale code are common! */ + if (strstr(identifier, "rotation_euler")) { + float eul[3]; + + mat4_to_eulO(eul, rotmode, tmat); + return eul[array_index]; + } + else if (strstr(identifier, "rotation_quaternion")) { + float mat3[3][3], quat[4]; + + copy_m3_m4(mat3, tmat); + mat3_to_quat_is_ok(quat, mat3); + + return quat[array_index]; + } + else if (strstr(identifier, "rotation_axis_angle")) { + float axis[3], angle; + + mat4_to_axis_angle(axis, &angle, tmat); + + /* w = 0, x,y,z = 1,2,3 */ + if (array_index == 0) + return angle; + else + return axis[array_index - 1]; + } + else if (strstr(identifier, "scale")) { + float scale[3]; + + mat4_to_size(scale, tmat); + + return scale[array_index]; + } /* as the function hasn't returned yet, read value from system in the default way */ return setting_get_rna_value(ptr, prop, array_index); diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index ae405c0e113..37314373e98 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -812,7 +812,7 @@ static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChann pose = ob->pose; for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) { for (con = pchant->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -859,7 +859,7 @@ static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChann /* fix object-level constraints */ if (ob != srcArm) { for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1032,7 +1032,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) if (ob->type == OB_ARMATURE) { for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1070,7 +1070,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) /* fix object-level constraints */ if (ob != origArm) { for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1712,7 +1712,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) } else { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -2523,7 +2523,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj /* does this constraint have a subtarget in * this armature? */ - bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -5533,7 +5533,7 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldnam bConstraintTarget *ct; for (curcon = conlist->first; curcon; curcon = curcon->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon); ListBase targets = {NULL, NULL}; if (cti && cti->get_constraint_targets) { diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index 68cfc7fb8c0..3e34a4c6808 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -725,7 +725,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) /* DO SOME MAGIC HERE */ for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -850,7 +850,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) /* DO SOME MAGIC HERE */ for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1830,7 +1830,9 @@ static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEd } #endif -static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge, float *vec0, float *vec1, float *vec2, int i1, int i2, float angle_weight, float length_weight, float distance_weight) +static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge, + float *vec0, float *vec1, float *vec2, int i1, int i2, + float angle_weight, float length_weight, float distance_weight) { float vec_second[3], vec_first[3]; float length2; @@ -1878,7 +1880,9 @@ static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, } } -static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, int joints_left, float angle_weight, float length_weight, float distance_weight) +static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, + int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, + int joints_left, float angle_weight, float length_weight, float distance_weight) { MemoNode *node; int index = indexMemoNode(nb_positions, previous, current, joints_left); diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 2848db18d59..19a97fa0810 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -649,7 +649,9 @@ static float heat_limit_weight(float weight) return weight; } -void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, const char **err_str) +void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, + bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, + float (*root)[3], float (*tip)[3], int *selected, const char **err_str) { LaplacianSystem *sys; MPoly *mp; diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index 576e5983d16..49d4b670cde 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -417,7 +417,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op { if (pchan->bone->flag & BONE_SELECTED) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -925,7 +925,7 @@ static void pose_copy_menu(Scene *scene) /* copy constraints to tmpbase and apply 'local' tags before * appending to list of constraints for this channel */ - copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE); + BKE_copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE); if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) { bConstraint *con; @@ -1034,7 +1034,7 @@ static void pose_copy_menu(Scene *scene) /* copy constraints to tmpbase and apply 'local' tags before * appending to list of constraints for this channel */ - copy_constraints(&tmp_constraints, &const_copy, TRUE); + BKE_copy_constraints(&tmp_constraints, &const_copy, TRUE); if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) { /* add proxy-local tags */ for (con = tmp_constraints.first; con; con = con->next) diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 1b4a67d38c0..f5ab002e0ef 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -291,9 +291,9 @@ int mesh_get_x_mirror_vert(struct Object *ob, int index); struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, struct BMVert *eve, const float co[3], int index); int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em); -int ED_mesh_pick_vert(struct bContext *C, struct Mesh *me, const int mval[2], unsigned int *index, int size); -int ED_mesh_pick_face(struct bContext *C, struct Mesh *me, const int mval[2], unsigned int *index, int size); -int ED_mesh_pick_face_vert(struct bContext *C, struct Mesh *me, struct Object *ob, const int mval[2], unsigned int *index, int size); +int ED_mesh_pick_vert(struct bContext *C, struct Object *ob, const int mval[2], unsigned int *index, int size, int use_zbuf); +int ED_mesh_pick_face(struct bContext *C, struct Object *ob, const int mval[2], unsigned int *index, int size); +int ED_mesh_pick_face_vert(struct bContext *C, struct Object *ob, const int mval[2], unsigned int *index, int size); #define ED_MESH_PICK_DEFAULT_VERT_SIZE 50 #define ED_MESH_PICK_DEFAULT_FACE_SIZE 3 diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index f7f58a4ee7a..3d13938c204 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -85,6 +85,7 @@ typedef struct ViewDepths { } ViewDepths; float *give_cursor(struct Scene *scene, struct View3D *v3d); +void ED_view3d_cursor3d_position(struct bContext *C, float *fp, int mx, int my); void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist); void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist); @@ -124,6 +125,10 @@ typedef enum { /* view3d_iterators.c */ /* foreach iterators */ +void meshobject_foreachScreenVert( + struct ViewContext *vc, + void (*func)(void *userData, struct MVert *eve, const float screen_co[2], int index), + void *userData, const eV3DProjTest clip_flag); void mesh_foreachScreenVert( struct ViewContext *vc, void (*func)(void *userData, struct BMVert *eve, const float screen_co[2], int index), diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 99f7f0856b3..0a794040692 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -699,9 +699,7 @@ DEF_ICON(RNDCURVE) DEF_ICON(PROP_OFF) DEF_ICON(PROP_ON) DEF_ICON(PROP_CON) -#ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK212) -#endif +DEF_ICON(SCULPT_DYNTOPO) DEF_ICON(PARTICLE_POINT) DEF_ICON(PARTICLE_TIP) DEF_ICON(PARTICLE_PATH) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 90f8779b2c7..080367c4325 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -56,6 +56,7 @@ struct PropertyRNA; struct ReportList; struct rcti; struct rctf; +struct uiList; struct uiStyle; struct uiFontStyle; struct uiWidgetColors; @@ -658,6 +659,7 @@ void uiDrawPanels(const struct bContext *C, struct ARegion *ar); struct Panel *uiBeginPanel(struct ScrArea *sa, struct ARegion *ar, uiBlock *block, struct PanelType *pt, int *open); void uiEndPanel(uiBlock *block, int width, int height); +void uiScalePanels(struct ARegion *ar, float new_width); /* Handlers * @@ -778,7 +780,7 @@ uiLayout *uiLayoutRow(uiLayout *layout, int align); uiLayout *uiLayoutColumn(uiLayout *layout, int align); uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align); uiLayout *uiLayoutBox(uiLayout *layout); -uiLayout *uiLayoutListBox(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop, +uiLayout *uiLayoutListBox(uiLayout *layout, struct uiList *ui_list, struct PointerRNA *ptr, struct PropertyRNA *prop, struct PointerRNA *actptr, struct PropertyRNA *actprop); uiLayout *uiLayoutAbsolute(uiLayout *layout, int align); uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align); @@ -824,7 +826,9 @@ void uiTemplateTextureImage(uiLayout *layout, struct bContext *C, struct Tex *te void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C); void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr); -void uiTemplateList(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *activeptr, const char *activeprop, const char *prop_list, int rows, int maxrows, int type); +void uiTemplateList(uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id, + struct PointerRNA *dataptr, const char *propname, struct PointerRNA *active_dataptr, + const char *active_propname, int rows, int maxrows, int layout_type); void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); void uiTemplateTextureUser(uiLayout *layout, struct bContext *C); diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index aa94bdec724..f578d68b852 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -32,12 +32,14 @@ #ifndef __UI_INTERFACE_ICONS_H__ #define __UI_INTERFACE_ICONS_H__ +struct bContext; struct Image; struct ImBuf; struct World; struct Tex; struct Lamp; struct Material; +struct PointerRNA; typedef struct IconFile { struct IconFile *next, *prev; @@ -74,5 +76,6 @@ void UI_icons_free_drawinfo(void *drawinfo); struct ListBase *UI_iconfile_list(void); int UI_iconfile_get_index(const char *filename); +int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, int big); #endif /* __UI_INTERFACE_ICONS_H__ */ diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 236cc371d8b..1035f5815f2 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -122,9 +122,12 @@ enum { TH_SYNTAX_B, TH_SYNTAX_V, + TH_SYNTAX_R, TH_SYNTAX_C, TH_SYNTAX_L, + TH_SYNTAX_D, TH_SYNTAX_N, + TH_SYNTAX_S, TH_BONE_SOLID, TH_BONE_POSE, diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 3ae1e93dc3d..81a0f526049 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -148,7 +148,6 @@ typedef struct View2DScrollers View2DScrollers; void UI_view2d_region_reinit(struct View2D *v2d, short type, int winx, int winy); void UI_view2d_curRect_validate(struct View2D *v2d); -void UI_view2d_curRect_validate_resize(struct View2D *v2d, int resize); void UI_view2d_curRect_reset(struct View2D *v2d); void UI_view2d_sync(struct bScreen *screen, struct ScrArea *sa, struct View2D *v2dcur, int flag); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 25f85883d9c..1d26cbd344b 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -2666,6 +2666,8 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, /* we could do some more error checks here */ if ((type & BUTTYPE) == LABEL) { + if ((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f))) + printf("blah\n"); BLI_assert((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f)) == FALSE); } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index fed84092133..1c9cd92271c 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -44,6 +44,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -219,6 +220,29 @@ static void button_timers_tooltip_remove(bContext *C, uiBut *but); /* ******************** menu navigation helpers ************** */ +/* assumes event type is MOUSEPAN */ +void ui_pan_to_scroll(wmEvent *event, int *type, int *val) +{ + static int lastdy = 0; + int dy = event->prevy - event->y; + + /* sign differs, reset */ + if ((dy > 0 && lastdy < 0) || (dy < 0 && lastdy > 0)) + lastdy = dy; + else { + lastdy += dy; + + if (ABS(lastdy) > (int)UI_UNIT_Y) { + *val = KM_PRESS; + if (event->prevy - event->y > 0) + *type = WHEELUPMOUSE; + else + *type = WHEELDOWNMOUSE; + lastdy = 0; + } + } +} + static int ui_but_editable(uiBut *but) { return ELEM5(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX, PROGRESSBAR); @@ -1893,6 +1917,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle case WHEELUPMOUSE: case WHEELDOWNMOUSE: case MOUSEMOVE: + case MOUSEPAN: if (data->searchbox) ui_searchbox_event(C, data->searchbox, but, event); @@ -2687,12 +2712,16 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton ui_window_to_block(data->region, block, &mx, &my); if (data->state == BUTTON_STATE_HIGHLIGHT) { + int type = event->type, val = event->val; + + ui_pan_to_scroll(event, &type, &val); + /* XXX hardcoded keymap check.... */ - if (event->type == WHEELDOWNMOUSE && event->alt) { + if (type == WHEELDOWNMOUSE && event->alt) { mx = but->rect.xmin; click = 1; } - else if (event->type == WHEELUPMOUSE && event->alt) { + else if (type == WHEELUPMOUSE && event->alt) { mx = but->rect.xmax; click = 1; } @@ -2911,12 +2940,16 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton ui_window_to_block(data->region, block, &mx, &my); if (data->state == BUTTON_STATE_HIGHLIGHT) { + int type = event->type, val = event->val; + + ui_pan_to_scroll(event, &type, &val); + /* XXX hardcoded keymap check.... */ - if (event->type == WHEELDOWNMOUSE && event->alt) { + if (type == WHEELDOWNMOUSE && event->alt) { mx = but->rect.xmin; click = 2; } - else if (event->type == WHEELUPMOUSE && event->alt) { + else if (type == WHEELUPMOUSE && event->alt) { mx = but->rect.xmax; click = 2; } @@ -3142,7 +3175,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, wm } } else if (but->type == COLOR) { - if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { + if (ELEM3(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { float *hsv = ui_block_hsv_get(but->block); float col[3]; @@ -3151,8 +3184,12 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, wm if (event->type == WHEELDOWNMOUSE) hsv[2] = CLAMPIS(hsv[2] - 0.05f, 0.0f, 1.0f); - else + else if (event->type == WHEELUPMOUSE) hsv[2] = CLAMPIS(hsv[2] + 0.05f, 0.0f, 1.0f); + else { + float fac = 0.005 * (event->y - event->prevy); + hsv[2] = CLAMPIS(hsv[2] + fac, 0.0f, 1.0f); + } hsv_to_rgb_v(hsv, data->vec); ui_set_but_vectorf(but, data->vec); @@ -5248,32 +5285,15 @@ static int ui_mouse_inside_region(ARegion *ar, int x, int y) */ if (ar->v2d.mask.xmin != ar->v2d.mask.xmax) { View2D *v2d = &ar->v2d; - rcti mask_rct; int mx, my; /* convert window coordinates to region coordinates */ mx = x; my = y; ui_window_to_region(ar, &mx, &my); - - /* make a copy of the mask rect, and tweak accordingly for hidden scrollbars */ - mask_rct = v2d->mask; - - if (v2d->scroll & (V2D_SCROLL_VERTICAL_HIDE | V2D_SCROLL_VERTICAL_FULLR)) { - if (v2d->scroll & V2D_SCROLL_LEFT) - mask_rct.xmin = v2d->vert.xmin; - else if (v2d->scroll & V2D_SCROLL_RIGHT) - mask_rct.xmax = v2d->vert.xmax; - } - if (v2d->scroll & (V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_HORIZONTAL_FULLR)) { - if (v2d->scroll & (V2D_SCROLL_BOTTOM | V2D_SCROLL_BOTTOM_O)) - mask_rct.ymin = v2d->hor.ymin; - else if (v2d->scroll & V2D_SCROLL_TOP) - mask_rct.ymax = v2d->hor.ymax; - } - + /* check if in the rect */ - if (!BLI_rcti_isect_pt(&mask_rct, mx, my)) + if (!BLI_rcti_isect_pt(&v2d->mask, mx, my)) return 0; } @@ -6109,64 +6129,81 @@ static int ui_handle_list_event(bContext *C, wmEvent *event, ARegion *ar) uiBut *but = ui_list_find_mouse_over(ar, event->x, event->y); int retval = WM_UI_HANDLER_CONTINUE; int value, min, max; + int type = event->type, val = event->val; - if (but && (event->val == KM_PRESS)) { - Panel *pa = but->block->panel; + if (but) { + uiList *ui_list = but->custom_data; - if (ELEM(event->type, UPARROWKEY, DOWNARROWKEY) || - ((ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt))) - { - /* activate up/down the list */ - value = RNA_property_int_get(&but->rnapoin, but->rnaprop); + if (ui_list) { + + /* convert pan to scrollwheel */ + if (type == MOUSEPAN) { + ui_pan_to_scroll(event, &type, &val); + + /* if type still is mousepan, we call it handled, since delta-y accumulate */ + /* also see wm_event_system.c do_wheel_ui hack */ + if (type == MOUSEPAN) + retval = WM_UI_HANDLER_BREAK; + } + + if (val == KM_PRESS) { + + if (ELEM(type, UPARROWKEY, DOWNARROWKEY) || + ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt))) + { + /* activate up/down the list */ + value = RNA_property_int_get(&but->rnapoin, but->rnaprop); - if (ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) - value--; - else - value++; + if (ELEM(type, UPARROWKEY, WHEELUPMOUSE)) + value--; + else + value++; - CLAMP(value, 0, pa->list_last_len - 1); + CLAMP(value, 0, ui_list->list_last_len - 1); - if (value < pa->list_scroll) - pa->list_scroll = value; - else if (value >= pa->list_scroll + pa->list_size) - pa->list_scroll = value - pa->list_size + 1; + if (value < ui_list->list_scroll) + ui_list->list_scroll = value; + else if (value >= ui_list->list_scroll + ui_list->list_size) + ui_list->list_scroll = value - ui_list->list_size + 1; - RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max); - value = CLAMPIS(value, min, max); + RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max); + value = CLAMPIS(value, min, max); - RNA_property_int_set(&but->rnapoin, but->rnaprop, value); - RNA_property_update(C, &but->rnapoin, but->rnaprop); - ED_region_tag_redraw(ar); + RNA_property_int_set(&but->rnapoin, but->rnaprop, value); + RNA_property_update(C, &but->rnapoin, but->rnaprop); + ED_region_tag_redraw(ar); - retval = WM_UI_HANDLER_BREAK; - } - else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) { - /* silly replacement for proper grip */ - if (pa->list_grip_size == 0) - pa->list_grip_size = pa->list_size; + retval = WM_UI_HANDLER_BREAK; + } + else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) { + /* silly replacement for proper grip */ + if (ui_list->list_grip_size == 0) + ui_list->list_grip_size = ui_list->list_size; - if (event->type == WHEELUPMOUSE) - pa->list_grip_size--; - else - pa->list_grip_size++; + if (type == WHEELUPMOUSE) + ui_list->list_grip_size--; + else + ui_list->list_grip_size++; - pa->list_grip_size = MAX2(pa->list_grip_size, 1); + ui_list->list_grip_size = MAX2(ui_list->list_grip_size, 1); - ED_region_tag_redraw(ar); + ED_region_tag_redraw(ar); - retval = WM_UI_HANDLER_BREAK; - } - else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { - if (pa->list_last_len > pa->list_size) { - /* list template will clamp */ - if (event->type == WHEELUPMOUSE) - pa->list_scroll--; - else - pa->list_scroll++; + retval = WM_UI_HANDLER_BREAK; + } + else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { + if (ui_list->list_last_len > ui_list->list_size) { + /* list template will clamp */ + if (type == WHEELUPMOUSE) + ui_list->list_scroll--; + else + ui_list->list_scroll++; - ED_region_tag_redraw(ar); + ED_region_tag_redraw(ar); - retval = WM_UI_HANDLER_BREAK; + retval = WM_UI_HANDLER_BREAK; + } + } } } } @@ -6472,21 +6509,29 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle case DOWNARROWKEY: case WHEELUPMOUSE: case WHEELDOWNMOUSE: + case MOUSEPAN: /* arrowkeys: only handle for block_loop blocks */ if (event->alt || event->shift || event->ctrl || event->oskey) { /* pass */ } else if (inside || (block->flag & UI_BLOCK_LOOP)) { - if (event->val == KM_PRESS) { + int type = event->type; + int val = event->val; + + /* convert pan to scrollwheel */ + if (type == MOUSEPAN) + ui_pan_to_scroll(event, &type, &val); + + if (val == KM_PRESS) { PASS_EVENT_TO_PARENT_IF_NONACTIVE; but = ui_but_find_activated(ar); if (but) { /* is there a situation where UI_LEFT or UI_RIGHT would also change navigation direction? */ - if (((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_DOWN)) || - ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_RIGHT)) || - ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_TOP))) + if (((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_DOWN)) || + ((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_RIGHT)) || + ((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_TOP))) { /* the following is just a hack - uiBut->type set to BUT and BUTM have there menus built * opposite ways - this should be changed so that all popup-menus use the same uiBlock->direction */ @@ -6509,9 +6554,9 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle } if (!but) { - if (((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_DOWN)) || - ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_RIGHT)) || - ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_TOP))) + if (((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_DOWN)) || + ((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_RIGHT)) || + ((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_TOP))) { if ((bt = ui_but_first(block)) && (bt->type & BUT)) { bt = ui_but_last(block); @@ -6928,8 +6973,6 @@ static int ui_handler_region_menu(bContext *C, wmEvent *event, void *UNUSED(user { ARegion *ar; uiBut *but; - uiHandleButtonData *data; - int retval; /* here we handle buttons at the window level, modal, for example * while number sliding, text editing, or when a menu block is open */ @@ -6940,17 +6983,23 @@ static int ui_handler_region_menu(bContext *C, wmEvent *event, void *UNUSED(user but = ui_but_find_activated(ar); if (but) { + uiHandleButtonData *data; + /* handle activated button events */ data = but->active; if (data->state == BUTTON_STATE_MENU_OPEN) { + int retval; + /* handle events for menus and their buttons recursively, * this will handle events from the top to the bottom menu */ if (data->menu) retval = ui_handle_menus_recursive(C, event, data->menu, 0); /* handle events for the activated button */ - if (retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) { + if ((data->menu && (retval == WM_UI_HANDLER_CONTINUE)) || + (event->type == TIMER)) + { if (data->menu && data->menu->menuretval) ui_handle_button_return_submenu(C, event, but); else diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 2928a5607c0..ebc80d61af3 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -49,6 +49,7 @@ #include "BLI_utildefines.h" #include "DNA_brush_types.h" +#include "DNA_dynamicpaint_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -75,8 +76,8 @@ #include "interface_intern.h" -#define ICON_IMAGE_W 600 -#define ICON_IMAGE_H 640 +// #define ICON_IMAGE_W 600 +// #define ICON_IMAGE_H 640 #define ICON_GRID_COLS 26 #define ICON_GRID_ROWS 30 @@ -574,13 +575,15 @@ static void init_internal_icons(void) glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect); while (b16buf->x > 1) { - b16buf = IMB_onehalf(b16buf); - glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect); + ImBuf *nbuf = IMB_onehalf(b16buf); + glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, nbuf->x, nbuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nbuf->rect); level++; + IMB_freeImBuf(b16buf); + b16buf = nbuf; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); @@ -597,7 +600,7 @@ static void init_internal_icons(void) else icontype = ICON_TYPE_BUFFER; - if (b16buf) { + if (b32buf) { for (y = 0; y < ICON_GRID_ROWS; y++) { for (x = 0; x < ICON_GRID_COLS; x++) { def_internal_icon(b32buf, BIFICONID_FIRST + y * ICON_GRID_COLS + x, @@ -1179,6 +1182,44 @@ int ui_id_icon_get(bContext *C, ID *id, int big) return iconid; } +int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, int big) +{ + ID *id = NULL; + + if (!ptr->data) + return rnaicon; + + /* try ID, material, texture or dynapaint slot */ + if (RNA_struct_is_ID(ptr->type)) { + id = ptr->id.data; + } + else if (RNA_struct_is_a(ptr->type, &RNA_MaterialSlot)) { + id = RNA_pointer_get(ptr, "material").data; + } + else if (RNA_struct_is_a(ptr->type, &RNA_TextureSlot)) { + id = RNA_pointer_get(ptr, "texture").data; + } + else if (RNA_struct_is_a(ptr->type, &RNA_DynamicPaintSurface)) { + DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data; + + if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) + return ICON_TEXTURE_SHADED; + else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) + return ICON_OUTLINER_DATA_MESH; + else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) + return ICON_FILE_IMAGE; + } + + /* get icon from ID */ + if (id) { + int icon = ui_id_icon_get(C, id, big); + + return icon ? icon : rnaicon; + } + + return rnaicon; +} + static void icon_draw_at_size(float x, float y, int icon_id, float aspect, float alpha, enum eIconSizes size, int nocreate) { int draw_size = get_draw_size(size); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index f088b3a54f4..706301dc060 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -271,6 +271,9 @@ struct uiBut { /* active button data */ struct uiHandleButtonData *active; + /* Custom button data. */ + void *custom_data; + char *editstr; double *editval; float *editvec; @@ -504,6 +507,7 @@ void ui_draw_but_IMAGE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, rct void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, rcti *rect); /* interface_handlers.c */ +extern void ui_pan_to_scroll(struct wmEvent *event, int *type, int *val); extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, uiBut *but); extern void ui_button_active_free(const struct bContext *C, uiBut *but); extern int ui_button_is_active(struct ARegion *ar); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index a15256bc86f..f4af1f036a3 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -186,13 +186,13 @@ static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_ static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset) { + if (offset) + *offset = 0; + /* available == 0 is unlimited */ if (available == 0) return item; - - if (offset) - *offset = 0; - + if (all > available) { /* contents is bigger than available space */ if (last) @@ -346,7 +346,9 @@ static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index) } /* create buttons for an item with an RNA array */ -static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h), int expand, int slider, int toggle, int icon_only) +static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon, + PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h), + int expand, int slider, int toggle, int icon_only) { uiStyle *style = layout->root->style; uiBut *but; @@ -2306,11 +2308,14 @@ uiLayout *uiLayoutBox(uiLayout *layout) return (uiLayout *)ui_layout_box(layout, ROUNDBOX); } -uiLayout *uiLayoutListBox(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr, PropertyRNA *actprop) +uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr, + PropertyRNA *actprop) { uiLayoutItemBx *box = ui_layout_box(layout, LISTBOX); uiBut *but = box->roundbox; + but->custom_data = ui_list; + but->rnasearchpoin = *ptr; but->rnasearchprop = prop; but->rnapoin = *actptr; diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 5b6a609e4d2..9fbf2fe8898 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -112,7 +112,7 @@ static int panel_aligned(ScrArea *sa, ARegion *ar) else if (sa->spacetype == SPACE_FILE && ar->regiontype == RGN_TYPE_CHANNELS) return BUT_VERTICAL; else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW) - return BUT_VERTICAL; + return BUT_VERTICAL; else if (ELEM3(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) return BUT_VERTICAL; @@ -812,8 +812,8 @@ static void ui_panels_size(ScrArea *sa, ARegion *ar, int *x, int *y) { Panel *pa; int align = panel_aligned(sa, ar); - int sizex = UI_PANEL_WIDTH; - int sizey = UI_PANEL_WIDTH; + int sizex = 0; + int sizey = 0; /* compute size taken up by panels, for setting in view2d */ for (pa = ar->panels.first; pa; pa = pa->next) { @@ -834,6 +834,11 @@ static void ui_panels_size(ScrArea *sa, ARegion *ar, int *x, int *y) } } + if (sizex == 0) + sizex = UI_PANEL_WIDTH; + if (sizey == 0) + sizey = -UI_PANEL_WIDTH; + *x = sizex; *y = sizey; } @@ -956,6 +961,25 @@ void uiDrawPanels(const bContext *C, ARegion *ar) } } +void uiScalePanels(ARegion *ar, float new_width) +{ + uiBlock *block; + uiBut *but; + + for (block = ar->uiblocks.first; block; block = block->next) { + if (block->panel) { + float fac = new_width / (float)block->panel->sizex; + printf("scaled %f\n", fac); + block->panel->sizex = new_width; + + for (but = block->buttons.first; but; but = but->next) { + but->rect.xmin *= fac; + but->rect.xmax *= fac; + } + } + } +} + /* ------------ panel merging ---------------- */ static void check_panel_overlap(ARegion *ar, Panel *panel) diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 57c126c31c5..4a8ad5d24a6 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -651,10 +651,10 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) ofsx = 0; //(but->block->panel) ? but->block->panel->ofsx : 0; ofsy = 0; //(but->block->panel) ? but->block->panel->ofsy : 0; - rect_fl.xmin = (but->rect.xmin + but->rect.xmax) * 0.5f + ofsx - (TIP_BORDER_X ); - rect_fl.xmax = rect_fl.xmin + fontw + (TIP_BORDER_X ); - rect_fl.ymax = but->rect.ymin + ofsy - (TIP_BORDER_Y ); - rect_fl.ymin = rect_fl.ymax - fonth - (TIP_BORDER_Y ); + rect_fl.xmin = (but->rect.xmin + but->rect.xmax) * 0.5f + ofsx - TIP_BORDER_X; + rect_fl.xmax = rect_fl.xmin + fontw + TIP_BORDER_X; + rect_fl.ymax = but->rect.ymin + ofsy - TIP_BORDER_Y; + rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y; #undef TIP_MARGIN_Y #undef TIP_BORDER_X @@ -896,8 +896,12 @@ void ui_searchbox_apply(uiBut *but, ARegion *ar) void ui_searchbox_event(bContext *C, ARegion *ar, uiBut *but, wmEvent *event) { uiSearchboxData *data = ar->regiondata; + int type = event->type, val = event->val; - switch (event->type) { + if (type == MOUSEPAN) + ui_pan_to_scroll(event, &type, &val); + + switch (type) { case WHEELUPMOUSE: case UPARROWKEY: ui_searchbox_select(C, ar, but, -1); @@ -1527,6 +1531,7 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar) static void ui_popup_block_clip(wmWindow *window, uiBlock *block) { + uiBut *bt; int width = UI_ThemeMenuShadowWidth(); int winx, winy; @@ -1536,7 +1541,6 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block) winx = WM_window_pixels_x(window); winy = WM_window_pixels_y(window); - // wm_window_get_size(window, &winx, &winy); if (block->rect.xmin < width) block->rect.xmin = width; @@ -1547,6 +1551,15 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block) block->rect.ymin = width; if (block->rect.ymax > winy - MENU_TOP) block->rect.ymax = winy - MENU_TOP; + + /* ensure menu items draw inside left/right boundary */ + for (bt = block->buttons.first; bt; bt = bt->next) { + if (bt->rect.xmin < block->rect.xmin) + bt->rect.xmin = block->rect.xmin; + if (bt->rect.xmax > block->rect.xmax) + bt->rect.xmax = block->rect.xmax; + } + } void ui_popup_block_scrolltest(uiBlock *block) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 33f647d1db6..f704ac0e203 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -31,18 +31,16 @@ #include "MEM_guardedalloc.h" -#include "DNA_anim_types.h" #include "DNA_dynamicpaint_types.h" -#include "DNA_key_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" -#include "DNA_userdef_types.h" #include "BLI_utildefines.h" #include "BLI_string.h" #include "BLI_ghash.h" #include "BLI_rect.h" +#include "BLF_api.h" #include "BLF_translation.h" #include "BKE_animsys.h" @@ -59,6 +57,7 @@ #include "BKE_displist.h" #include "BKE_sca.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "ED_screen.h" #include "ED_object.h" @@ -71,11 +70,9 @@ #include "WM_types.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "interface_intern.h" -#include "BLF_api.h" -#include "BLF_translation.h" - void UI_template_fix_linking(void) { } @@ -1090,7 +1087,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) // int rb_col; // UNUSED /* get constraint typeinfo */ - cti = constraint_get_typeinfo(con); + cti = BKE_constraint_get_typeinfo(con); if (cti == NULL) { /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */ BLI_strncpy(typestr, (con->type == CONSTRAINT_TYPE_NULL) ? "Null" : "Unknown", sizeof(typestr)); @@ -1099,7 +1096,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) BLI_strncpy(typestr, cti->name, sizeof(typestr)); /* determine whether constraint is proxy protected or not */ - if (proxylocked_constraints_owner(ob, pchan)) + if (BKE_proxylocked_constraints_owner(ob, pchan)) proxy_protected = (con->flag & CONSTRAINT_PROXY_LOCAL) == 0; else proxy_protected = 0; @@ -1161,7 +1158,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) * * Up/Down buttons should only be shown (or not grayed - todo) if they serve some purpose. */ - if (proxylocked_constraints_owner(ob, pchan)) { + if (BKE_proxylocked_constraints_owner(ob, pchan)) { if (con->prev) { prev_proxylock = (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1; } @@ -2341,437 +2338,195 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam /************************* List Template **************************/ - -static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big) +static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout, + struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon, + struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname), + int UNUSED(index)) { - ID *id = NULL; - int icon; - - if (!itemptr->data) - return rnaicon; - - /* try ID, material or texture slot */ - if (RNA_struct_is_ID(itemptr->type)) { - id = itemptr->id.data; - } - else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) { - id = RNA_pointer_get(itemptr, "material").data; - } - else if (RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) { - id = RNA_pointer_get(itemptr, "texture").data; - } - else if (RNA_struct_is_a(itemptr->type, &RNA_DynamicPaintSurface)) { - DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data; - - if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) return ICON_TEXTURE_SHADED; - else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) return ICON_OUTLINER_DATA_MESH; - else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return ICON_FILE_IMAGE; - } - - /* get icon from ID */ - if (id) { - icon = ui_id_icon_get(C, id, big); - - if (icon) - return icon; - } - - return rnaicon; -} - -static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i, - int rnaicon, PointerRNA *activeptr, PropertyRNA *activeprop, const char *prop_list_id) -{ - uiBlock *block = uiLayoutGetBlock(layout); - uiBut *but; - uiLayout *split, *overlap, *sub, *row; char *namebuf; const char *name; - int icon; - - overlap = uiLayoutOverlap(layout); - - /* list item behind label & other buttons */ - sub = uiLayoutRow(overlap, FALSE); - - but = uiDefButR_prop(block, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr, activeprop, - 0, 0, i, 0, 0, ""); - uiButSetFlag(but, UI_BUT_NO_TOOLTIP); - - sub = uiLayoutRow(overlap, FALSE); - - /* retrieve icon and name */ - icon = list_item_icon_get(C, itemptr, rnaicon, 0); - if (icon == ICON_NONE || icon == ICON_DOT) - icon = 0; namebuf = RNA_struct_name_get_alloc(itemptr, NULL, 0, NULL); name = (namebuf) ? namebuf : ""; - /* hardcoded types */ - if (itemptr->type == &RNA_MeshTexturePolyLayer || itemptr->type == &RNA_MeshLoopColorLayer) { - uiItemL(sub, name, icon); - uiBlockSetEmboss(block, UI_EMBOSSN); - uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", - 0, 0, 0, 0, 0, NULL); - uiBlockSetEmboss(block, UI_EMBOSS); + /* Simplest one! */ + switch (ui_list->layout_type) { + case UILST_LAYOUT_GRID: + uiItemL(layout, "", icon); + break; + case UILST_LAYOUT_DEFAULT: + case UILST_LAYOUT_COMPACT: + default: + uiItemL(layout, name, icon); + break; } - else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) { - uiItemL(sub, name, icon); - uiBlockSetEmboss(block, UI_EMBOSS); - uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0, NULL); - } -#ifdef WITH_FREESTYLE - else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer) || - RNA_struct_is_a(itemptr->type, &RNA_FreestyleLineSet)) { -#else - else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) { -#endif - uiItemL(sub, name, icon); - uiBlockSetEmboss(block, UI_EMBOSS); - uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0, NULL); - } - else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) { - /* provision to draw active node name */ - Material *ma, *manode; - Scene *scene = CTX_data_scene(C); - Object *ob = (Object *)ptr->id.data; - int index = (Material **)itemptr->data - ob->mat; - - /* default item with material base name */ - uiItemL(sub, name, icon); - ma = give_current_material(ob, index + 1); - if (ma && !BKE_scene_use_new_shading_nodes(scene)) { - manode = give_node_material(ma); - if (manode) { - char str[MAX_ID_NAME + 12]; - BLI_snprintf(str, sizeof(str), IFACE_("Node %s"), manode->id.name + 2); - uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1)); - } - else if (ma->use_nodes) { - uiItemL(sub, IFACE_("Node <none>"), ICON_NONE); - } - } - } - else if (itemptr->type == &RNA_ShapeKey) { - Object *ob = (Object *)activeptr->data; - Key *key = (Key *)itemptr->id.data; - KeyBlock *kb = (KeyBlock *)itemptr->data; - - split = uiLayoutSplit(sub, 0.66f, FALSE); - - uiItemL(split, name, icon); - - uiBlockSetEmboss(block, UI_EMBOSSN); - row = uiLayoutRow(split, TRUE); - if (i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE); - else uiItemR(row, itemptr, "value", 0, "", ICON_NONE); - uiItemR(row, itemptr, "mute", 0, "", ICON_NONE); - - if ((kb->flag & KEYBLOCK_MUTE) || - (ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH))) - { - uiLayoutSetActive(row, FALSE); - } - uiBlockSetEmboss(block, UI_EMBOSS); - } - else if (itemptr->type == &RNA_VertexGroup) { - bDeformGroup *dg = (bDeformGroup *)itemptr->data; - uiItemL(sub, name, icon); - /* RNA does not allow nice lock icons, use lower level buttons */ -#if 0 - uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "lock_weight", 0, 0, 0, 0, 0, NULL); -#else - uiBlockSetEmboss(block, UI_EMBOSSN); - uiDefIconButBitC(block, TOG, DG_LOCK_WEIGHT, 0, (dg->flag & DG_LOCK_WEIGHT) ? ICON_LOCKED : ICON_UNLOCKED, - 0, 0, UI_UNIT_X, UI_UNIT_Y, &dg->flag, 0, 0, 0, 0, - TIP_("Maintain relative weights while painting")); - uiBlockSetEmboss(block, UI_EMBOSS); -#endif - } - else if (itemptr->type == &RNA_KeyingSetPath) { - KS_Path *ksp = (KS_Path *)itemptr->data; - - /* icon needs to be the type of ID which is currently active */ - RNA_enum_icon_from_value(id_type_items, ksp->idtype, &icon); - - /* nothing else special to do... */ - uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */ - } - else if (itemptr->type == &RNA_DynamicPaintSurface) { - char name_final[96]; - const char *enum_name; - PropertyRNA *prop = RNA_struct_find_property(itemptr, "surface_type"); - DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data; - - RNA_property_enum_name(C, itemptr, prop, RNA_property_enum_get(itemptr, prop), &enum_name); - - BLI_snprintf(name_final, sizeof(name_final), "%s (%s)", name, enum_name); - uiItemL(sub, name_final, icon); - if (dynamicPaint_surfaceHasColorPreview(surface)) { - uiBlockSetEmboss(block, UI_EMBOSSN); - uiDefIconButR(block, OPTION, 0, - (surface->flags & MOD_DPAINT_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON, - 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "show_preview", 0, 0, 0, 0, 0, NULL); - uiBlockSetEmboss(block, UI_EMBOSS); - } - uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "is_active", i, 0, 0, 0, 0, NULL); - } - else if (itemptr->type == &RNA_MovieTrackingObject) { - MovieTrackingObject *tracking_object = (MovieTrackingObject *)itemptr->data; - - split = uiLayoutSplit(sub, 0.75f, FALSE); - if (tracking_object->flag & TRACKING_OBJECT_CAMERA) { - uiItemL(split, name, ICON_CAMERA_DATA); - } - else { - uiItemL(split, name, ICON_OBJECT_DATA); - } - } - else if (itemptr->type == &RNA_MaskLayer) { - split = uiLayoutRow(sub, FALSE); - - uiItemL(split, name, icon); - - uiBlockSetEmboss(block, UI_EMBOSSN); - row = uiLayoutRow(split, TRUE); - uiItemR(row, itemptr, "alpha", 0, "", ICON_NONE); - uiItemR(row, itemptr, "hide", 0, "", ICON_NONE); - uiItemR(row, itemptr, "hide_select", 0, "", ICON_NONE); - uiItemR(row, itemptr, "hide_render", 0, "", ICON_NONE); - - uiBlockSetEmboss(block, UI_EMBOSS); - } - - /* There is a last chance to display custom controls (in addition to the name/label): - * If the given item property group features a string property named as prop_list, - * this tries to add controls for all properties of the item listed in that string property. - * (colon-separated names). - * - * This is especially useful for python. E.g., if you list a collection of this property - * group: - * - * class TestPropertyGroup(bpy.types.PropertyGroup): - * bool = BoolProperty(default=False) - * integer = IntProperty() - * string = StringProperty() - * - * # A string of all identifiers (colon-separated) which property's controls should be - * # displayed in a template_list. - * template_list_controls = StringProperty(default="integer:bool:string", options={"HIDDEN"}) - * - * ... you'll get a numfield for the integer prop, a check box for the bool prop, and a textfield - * for the string prop, after the name of each item of the collection. - */ - else if (prop_list_id) { - row = uiLayoutRow(sub, TRUE); - uiItemL(row, name, icon); - - /* XXX: Check, as sometimes we get an itemptr looking like - * {id = {data = 0x0}, type = 0x0, data = 0x0} - * which would obviously produce a sigsev... */ - if (itemptr->type) { - /* If the special property is set for the item, and it is a collection... */ - PropertyRNA *prop_list = RNA_struct_find_property(itemptr, prop_list_id); - - if (prop_list && RNA_property_type(prop_list) == PROP_STRING) { - int prop_names_len; - char *prop_names = RNA_property_string_get_alloc(itemptr, prop_list, NULL, 0, &prop_names_len); - char *prop_names_end = prop_names + prop_names_len; - char *id = prop_names; - char *id_next; - while (id < prop_names_end) { - if ((id_next = strchr(id, ':'))) *id_next++ = '\0'; - else id_next = prop_names_end; - uiItemR(row, itemptr, id, 0, NULL, ICON_NONE); - id = id_next; - } - MEM_freeN(prop_names); - } - } - } - - else - uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */ - /* free name */ if (namebuf) { MEM_freeN(namebuf); } } -void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *activeptr, - const char *activepropname, const char *prop_list, int rows, int maxrows, int listtype) +void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id, + PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, + const char *active_propname, int rows, int maxrows, int layout_type) { + uiListType *ui_list_type; + uiList *ui_list = NULL; + ARegion *ar; + uiListDrawItemFunc draw_item; + PropertyRNA *prop = NULL, *activeprop; PropertyType type, activetype; StructRNA *ptype; - uiLayout *box, *row, *col; - uiBlock *block; + uiLayout *box, *row, *col, *sub, *overlap; + uiBlock *block, *subblock; uiBut *but; - Panel *pa; - const char *name; + + char ui_list_id[UI_MAX_NAME_STR]; char numstr[32]; - int rnaicon = 0, icon = 0, i = 0, activei = 0, len = 0, items, found, min, max; + int rnaicon = ICON_NONE, icon = ICON_NONE; + int i = 0, activei = 0; + int len = 0; + int items; + int found; + int min, max; /* validate arguments */ block = uiLayoutGetBlock(layout); - pa = block->panel; - if (!pa) { - RNA_warning("Only works inside a panel"); + if (!active_dataptr->data) { + RNA_warning("No active data"); return; } - if (!activeptr->data) - return; - - if (ptr->data) { - prop = RNA_struct_find_property(ptr, propname); + if (dataptr->data) { + prop = RNA_struct_find_property(dataptr, propname); if (!prop) { - RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); + RNA_warning("Property not found: %s.%s", RNA_struct_identifier(dataptr->type), propname); return; } } - activeprop = RNA_struct_find_property(activeptr, activepropname); + activeprop = RNA_struct_find_property(active_dataptr, active_propname); if (!activeprop) { - RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), activepropname); + RNA_warning("Property not found: %s.%s", RNA_struct_identifier(active_dataptr->type), active_propname); return; } if (prop) { type = RNA_property_type(prop); if (type != PROP_COLLECTION) { - RNA_warning("uiExpected collection property"); + RNA_warning("Expected a collection data property"); return; } } activetype = RNA_property_type(activeprop); if (activetype != PROP_INT) { - RNA_warning("Expected integer property"); + RNA_warning("Expected an integer active data property"); return; } /* get icon */ - if (ptr->data && prop) { - ptype = RNA_property_pointer_type(ptr, prop); + if (dataptr->data && prop) { + ptype = RNA_property_pointer_type(dataptr, prop); rnaicon = RNA_struct_ui_icon(ptype); } /* get active data */ - activei = RNA_property_int_get(activeptr, activeprop); - - if (listtype == 'i') { - box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop); - col = uiLayoutColumn(box, TRUE); - row = uiLayoutRow(col, FALSE); + activei = RNA_property_int_get(active_dataptr, activeprop); - if (ptr->data && prop) { - /* create list items */ - RNA_PROP_BEGIN (ptr, itemptr, prop) - { - /* create button */ - if (!(i % 9)) - row = uiLayoutRow(col, FALSE); + /* Find the uiList type. */ + ui_list_type = WM_uilisttype_find(listtype_name, FALSE); - icon = list_item_icon_get(C, &itemptr, rnaicon, 1); - but = uiDefIconButR_prop(block, LISTROW, 0, icon, 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr, - activeprop, 0, 0, i, 0, 0, ""); - uiButSetFlag(but, UI_BUT_NO_TOOLTIP); - - - i++; + if (ui_list_type == NULL) { + RNA_warning("List type %s not found", listtype_name); + return; } - RNA_PROP_END; - } - } - else if (listtype == 'c') { - /* compact layout */ - row = uiLayoutRow(layout, TRUE); + draw_item = ui_list_type->draw_item ? ui_list_type->draw_item : uilist_draw_item_default; - if (ptr->data && prop) { - /* create list items */ - RNA_PROP_BEGIN (ptr, itemptr, prop) - { - found = (activei == i); + /* Find or add the uiList to the current Region. */ + /* We tag the list id with the list type... */ + BLI_snprintf(ui_list_id, sizeof(ui_list_id), "%s_%s", ui_list_type->idname, list_id ? list_id : ""); - if (found) { - /* create button */ - name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); - icon = list_item_icon_get(C, &itemptr, rnaicon, 0); - uiItemL(row, (name) ? name : "", icon); + ar = CTX_wm_region(C); + ui_list = BLI_findstring(&ar->ui_lists, ui_list_id, offsetof(uiList, list_id)); - if (name) { - MEM_freeN((void *)name); + if (!ui_list) { + ui_list = MEM_callocN(sizeof(uiList), __func__); + BLI_strncpy(ui_list->list_id, ui_list_id, sizeof(ui_list->list_id)); + BLI_addtail(&ar->ui_lists, ui_list); } - } - i++; - } - RNA_PROP_END; - } - - /* if not found, add in dummy button */ - if (i == 0) - uiItemL(row, "", ICON_NONE); + /* Because we can't actually pass type across save&load... */ + ui_list->type = ui_list_type; + ui_list->layout_type = layout_type; - /* next/prev button */ - BLI_snprintf(numstr, sizeof(numstr), "%d :", i); - but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, activeptr, - activeprop, 0, 0, 0, 0, 0, ""); - if (i == 0) - uiButSetFlag(but, UI_BUT_DISABLED); - } - else { + switch (layout_type) { + case UILST_LAYOUT_DEFAULT: /* default rows */ if (rows == 0) rows = 5; if (maxrows == 0) maxrows = 5; - if (pa->list_grip_size != 0) - rows = pa->list_grip_size; + if (ui_list->list_grip_size != 0) + rows = ui_list->list_grip_size; /* layout */ - box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop); + box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); row = uiLayoutRow(box, FALSE); col = uiLayoutColumn(row, TRUE); /* init numbers */ - RNA_property_int_range(activeptr, activeprop, &min, &max); + RNA_property_int_range(active_dataptr, activeprop, &min, &max); if (prop) - len = RNA_property_collection_length(ptr, prop); + len = RNA_property_collection_length(dataptr, prop); items = CLAMPIS(len, rows, MAX2(rows, maxrows)); /* if list length changes and active is out of view, scroll to it */ - if (pa->list_last_len != len) - if ((activei < pa->list_scroll || activei >= pa->list_scroll + items)) - pa->list_scroll = activei; + if ((ui_list->list_last_len != len) && + (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items)) { + ui_list->list_scroll = activei; + } - pa->list_scroll = MIN2(pa->list_scroll, len - items); - pa->list_scroll = MAX2(pa->list_scroll, 0); - pa->list_size = items; - pa->list_last_len = len; + ui_list->list_scroll = min_ii(ui_list->list_scroll, len - items); + ui_list->list_scroll = max_ii(ui_list->list_scroll, 0); + ui_list->list_size = items; + ui_list->list_last_len = len; - if (ptr->data && prop) { + if (dataptr->data && prop) { /* create list items */ - RNA_PROP_BEGIN (ptr, itemptr, prop) + RNA_PROP_BEGIN (dataptr, itemptr, prop) { - if (i >= pa->list_scroll && i < pa->list_scroll + items) - list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activeprop, prop_list); + if (i >= ui_list->list_scroll && i < ui_list->list_scroll + items) { + subblock = uiLayoutGetBlock(col); + overlap = uiLayoutOverlap(col); + + /* list item behind label & other buttons */ + sub = uiLayoutRow(overlap, FALSE); + + but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, + active_dataptr, activeprop, 0, 0, i, 0, 0, ""); + uiButSetFlag(but, UI_BUT_NO_TOOLTIP); + + sub = uiLayoutRow(overlap, FALSE); + icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE); + if (icon == ICON_DOT) + icon = ICON_NONE; + draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + } i++; } RNA_PROP_END; } /* add dummy buttons to fill space */ - while (i < pa->list_scroll + items) { - if (i >= pa->list_scroll) + while (i < ui_list->list_scroll + items) { + if (i >= ui_list->list_scroll) uiItemL(col, "", ICON_NONE); i++; } @@ -2779,9 +2534,75 @@ void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char * /* add scrollbar */ if (len > items) { col = uiLayoutColumn(row, FALSE); - uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &pa->list_scroll, + uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &ui_list->list_scroll, 0, len - items, items, 0, ""); } + break; + case UILST_LAYOUT_COMPACT: + row = uiLayoutRow(layout, TRUE); + + if (dataptr->data && prop) { + /* create list items */ + RNA_PROP_BEGIN (dataptr, itemptr, prop) + { + found = (activei == i); + + if (found) { + icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE); + if (icon == ICON_DOT) + icon = ICON_NONE; + draw_item(ui_list, C, row, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + } + + i++; +} + RNA_PROP_END; + } + + /* if list is empty, add in dummy button */ + if (i == 0) + uiItemL(row, "", ICON_NONE); + + /* next/prev button */ + BLI_snprintf(numstr, sizeof(numstr), "%d :", i); + but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, + active_dataptr, activeprop, 0, 0, 0, 0, 0, ""); + if (i == 0) + uiButSetFlag(but, UI_BUT_DISABLED); + break; + case UILST_LAYOUT_GRID: + box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); + col = uiLayoutColumn(box, TRUE); + row = uiLayoutRow(col, FALSE); + + if (dataptr->data && prop) { + /* create list items */ + RNA_PROP_BEGIN (dataptr, itemptr, prop) + { + /* create button */ + if (!(i % 9)) + row = uiLayoutRow(col, FALSE); + + subblock = uiLayoutGetBlock(row); + overlap = uiLayoutOverlap(row); + + /* list item behind label & other buttons */ + sub = uiLayoutRow(overlap, FALSE); + + but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, + active_dataptr, activeprop, 0, 0, i, 0, 0, ""); + uiButSetFlag(but, UI_BUT_NO_TOOLTIP); + + sub = uiLayoutRow(overlap, FALSE); + + icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE); + draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + + i++; + } + RNA_PROP_END; + } + break; } } @@ -3095,7 +2916,7 @@ void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char colorspace_settings_ptr = RNA_property_pointer_get(ptr, prop); - uiItemL(layout, "Color Space:", ICON_NONE); + uiItemL(layout, "Input Color Space:", ICON_NONE); uiItemR(layout, &colorspace_settings_ptr, "name", 0, "", ICON_NONE); } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 4687647223a..e4ad3a4f73b 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1324,11 +1324,13 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB /* icons default draw 0.8f x height */ rect->xmin += (int)(0.8f * BLI_rcti_size_y(rect)); - if (but->editstr || (but->flag & UI_TEXT_LEFT)) - rect->xmin += 0.4f * U.widget_unit; + if (but->editstr || (but->flag & UI_TEXT_LEFT)) { + rect->xmin += (0.4f * U.widget_unit) / but->block->aspect; + } + } + else if ((but->flag & UI_TEXT_LEFT)) { + rect->xmin += (0.4f * U.widget_unit) / but->block->aspect; } - else if ((but->flag & UI_TEXT_LEFT)) - rect->xmin += 0.4f * U.widget_unit; /* always draw text for textbutton cursor */ widget_draw_text(fstyle, wcol, but, rect); @@ -2319,7 +2321,7 @@ void ui_draw_link_bezier(const rcti *rect) glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, coord_array); - glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL); + glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL + 1); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_BLEND); @@ -3467,14 +3469,14 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic if (iconid) { float height, aspect; int xs = rect->xmin + 0.2f * UI_UNIT_X; - int ys = 1 + (rect->ymin + rect->ymax - UI_DPI_ICON_SIZE) / 2; + int ys = rect->ymin + 0.1f * BLI_rcti_size_y(rect); /* icons are 80% of height of button (16 pixels inside 20 height) */ height = 0.8f * BLI_rcti_size_y(rect); aspect = ICON_DEFAULT_HEIGHT / height; - + glEnable(GL_BLEND); - UI_icon_draw_aspect(xs, ys, iconid, aspect, 0.5f); /* XXX scale weak get from fstyle? */ + UI_icon_draw_aspect(xs, ys, iconid, aspect, 1.0f); /* XXX scale weak get from fstyle? */ glDisable(GL_BLEND); } } diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index fd84c1fd4c4..361bdfacbb2 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -364,8 +364,14 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->syntaxc; break; case TH_SYNTAX_L: cp = ts->syntaxl; break; + case TH_SYNTAX_D: + cp = ts->syntaxd; break; + case TH_SYNTAX_R: + cp = ts->syntaxr; break; case TH_SYNTAX_N: cp = ts->syntaxn; break; + case TH_SYNTAX_S: + cp = ts->syntaxs; break; case TH_NODE: cp = ts->syntaxl; break; @@ -879,8 +885,8 @@ void ui_theme_init_default(void) rgba_char_args_set_fl(btheme->tima.preview_stitch_vert, 0.0, 0.0, 1.0, 0.2); rgba_char_args_set_fl(btheme->tima.preview_stitch_stitchable, 0.0, 1.0, 0.0, 1.0); rgba_char_args_set_fl(btheme->tima.preview_stitch_unstitchable, 1.0, 0.0, 0.0, 1.0); - rgba_char_args_set_fl(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140); - + rgba_char_args_set_fl(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140); + /* space text */ btheme->text = btheme->tv3d; rgba_char_args_set(btheme->text.back, 153, 153, 153, 255); @@ -890,10 +896,13 @@ void ui_theme_init_default(void) /* syntax highlighting */ rgba_char_args_set(btheme->text.syntaxn, 0, 0, 200, 255); /* Numbers Blue*/ - rgba_char_args_set(btheme->text.syntaxl, 100, 0, 0, 255); /* Strings red */ - rgba_char_args_set(btheme->text.syntaxc, 0, 100, 50, 255); /* Comments greenish */ - rgba_char_args_set(btheme->text.syntaxv, 95, 95, 0, 255); /* Special */ - rgba_char_args_set(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin, red-purple */ + rgba_char_args_set(btheme->text.syntaxl, 100, 0, 0, 255); /* Strings Red */ + rgba_char_args_set(btheme->text.syntaxc, 0, 100, 50, 255); /* Comments Greenish */ + rgba_char_args_set(btheme->text.syntaxv, 95, 95, 0, 255); /* Special Yellow*/ + rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */ + rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange*/ + rgba_char_args_set(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin Red-purple */ + rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Grey (mix between fg/bg) */ /* space oops */ btheme->toops = btheme->tv3d; @@ -2106,6 +2115,15 @@ void init_userdef_do_versions(void) } } } + + if (!MAIN_VERSION_ATLEAST(bmain, 266, 4)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */ + rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange */ + rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Grey (mix between fg/bg) */ + } + } if (U.pixelsize == 0.0f) U.pixelsize = 1.0f; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 190d90b3c36..d0d631e14a5 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -60,6 +60,8 @@ #include "interface_intern.h" +static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers); + /* *********************************************************************** */ /* XXX still unresolved: scrolls hide/unhide vs region mask handling */ @@ -73,15 +75,15 @@ */ static int view2d_scroll_mapped(int scroll) { - if (scroll & V2D_SCROLL_HORIZONTAL_HIDE) + if (scroll & V2D_SCROLL_HORIZONTAL_FULLR) scroll &= ~(V2D_SCROLL_HORIZONTAL); - if (scroll & V2D_SCROLL_VERTICAL_HIDE) + if (scroll & V2D_SCROLL_VERTICAL_FULLR) scroll &= ~(V2D_SCROLL_VERTICAL); return scroll; } /* called each time cur changes, to dynamically update masks */ -static void view2d_masks(View2D *v2d) +static void view2d_masks(View2D *v2d, int check_scrollers) { int scroll; @@ -90,19 +92,26 @@ static void view2d_masks(View2D *v2d) v2d->mask.xmax = v2d->winx - 1; /* -1 yes! masks are pixels */ v2d->mask.ymax = v2d->winy - 1; -#if 0 - /* XXX see above */ - v2d->scroll &= ~(V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_VERTICAL_HIDE); - /* check size if: */ - if (v2d->scroll & V2D_SCROLL_HORIZONTAL) - if (!(v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL)) - if (BLI_rctf_size_x(&v2d->tot) <= BLI_rcti_size_x(&v2d->cur)) - v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - if (v2d->scroll & V2D_SCROLL_VERTICAL) - if (!(v2d->scroll & V2D_SCROLL_SCALE_VERTICAL)) - if (BLI_rctf_size_y(&v2d->tot) <= BLI_rctf_size_y(&v2d->cur)) - v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE; -#endif + if (check_scrollers) { + /* check size if hiding flag is set: */ + if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) { + if (!(v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL)) { + if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) + v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR; + else + v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR; + } + } + if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) { + if (!(v2d->scroll & V2D_SCROLL_SCALE_VERTICAL)) { + if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) + v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR; + else + v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR; + } + } + } + scroll = view2d_scroll_mapped(v2d->scroll); /* scrollers shrink mask area, but should be based off regionsize @@ -126,8 +135,8 @@ static void view2d_masks(View2D *v2d) } /* horizontal scroller */ - if (scroll & (V2D_SCROLL_BOTTOM | V2D_SCROLL_BOTTOM_O)) { - /* on bottom edge of region (V2D_SCROLL_BOTTOM_O is outliner, the other is for standard) */ + if (scroll & (V2D_SCROLL_BOTTOM)) { + /* on bottom edge of region */ v2d->hor = v2d->mask; v2d->hor.ymax = V2D_SCROLL_HEIGHT; v2d->mask.ymin = v2d->hor.ymax + 1; @@ -142,8 +151,8 @@ static void view2d_masks(View2D *v2d) /* adjust vertical scroller if there's a horizontal scroller, to leave corner free */ if (scroll & V2D_SCROLL_VERTICAL) { /* just set y min/max for vertical scroller to y min/max of mask as appropriate */ - if (scroll & (V2D_SCROLL_BOTTOM | V2D_SCROLL_BOTTOM_O)) { - /* on bottom edge of region (V2D_SCROLL_BOTTOM_O is outliner, the other is for standard) */ + if (scroll & (V2D_SCROLL_BOTTOM)) { + /* on bottom edge of region */ v2d->vert.ymin = v2d->mask.ymin; } else if (scroll & V2D_SCROLL_TOP) { @@ -152,7 +161,6 @@ static void view2d_masks(View2D *v2d) } } } - } /* Refresh and Validation */ @@ -165,163 +173,173 @@ static void view2d_masks(View2D *v2d) */ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) { - short tot_changed = 0, init = 0; + short tot_changed = 0, do_init; uiStyle *style = UI_GetStyle(); - /* initialize data if there is a need for such */ - if ((v2d->flag & V2D_IS_INITIALISED) == 0) { - /* set initialized flag so that View2D doesn't get reinitialised next time again */ - v2d->flag |= V2D_IS_INITIALISED; - - init = 1; + do_init = (v2d->flag & V2D_IS_INITIALISED) == 0; - /* see eView2D_CommonViewTypes in UI_view2d.h for available view presets */ - switch (type) { - /* 'standard view' - optimum setup for 'standard' view behavior, - * that should be used new views as basis for their - * own unique View2D settings, which should be used instead of this in most cases... + /* see eView2D_CommonViewTypes in UI_view2d.h for available view presets */ + switch (type) { + /* 'standard view' - optimum setup for 'standard' view behavior, + * that should be used new views as basis for their + * own unique View2D settings, which should be used instead of this in most cases... + */ + case V2D_COMMONVIEW_STANDARD: + { + /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */ + v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM); + v2d->minzoom = 0.01f; + v2d->maxzoom = 1000.0f; + + /* tot rect and cur should be same size, and aligned using 'standard' OpenGL coordinates for now + * - region can resize 'tot' later to fit other data + * - keeptot is only within bounds, as strict locking is not that critical + * - view is aligned for (0,0) -> (winx-1, winy-1) setup */ - case V2D_COMMONVIEW_STANDARD: - { - /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */ - v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM); - v2d->minzoom = 0.01f; - v2d->maxzoom = 1000.0f; - - /* tot rect and cur should be same size, and aligned using 'standard' OpenGL coordinates for now - * - region can resize 'tot' later to fit other data - * - keeptot is only within bounds, as strict locking is not that critical - * - view is aligned for (0,0) -> (winx-1, winy-1) setup - */ - v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); - v2d->keeptot = V2D_KEEPTOT_BOUNDS; - + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); + v2d->keeptot = V2D_KEEPTOT_BOUNDS; + + if (do_init) { v2d->tot.xmin = v2d->tot.ymin = 0.0f; v2d->tot.xmax = (float)(winx - 1); v2d->tot.ymax = (float)(winy - 1); v2d->cur = v2d->tot; - - /* scrollers - should we have these by default? */ - /* XXX for now, we don't override this, or set it either! */ } - break; + /* scrollers - should we have these by default? */ + /* XXX for now, we don't override this, or set it either! */ + } + break; + + /* 'list/channel view' - zoom, aspect ratio, and alignment restrictions are set here */ + case V2D_COMMONVIEW_LIST: + { + /* zoom + aspect ratio are locked */ + v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); + v2d->minzoom = v2d->maxzoom = 1.0f; - /* 'list/channel view' - zoom, aspect ratio, and alignment restrictions are set here */ - case V2D_COMMONVIEW_LIST: - { - /* zoom + aspect ratio are locked */ - v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); - v2d->minzoom = v2d->maxzoom = 1.0f; - - /* tot rect has strictly regulated placement, and must only occur in +/- quadrant */ - v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); - v2d->keeptot = V2D_KEEPTOT_STRICT; - tot_changed = 1; - - /* scroller settings are currently not set here... that is left for regions... */ - } - break; - - /* 'stack view' - practically the same as list/channel view, except is located in the pos y half instead. - * zoom, aspect ratio, and alignment restrictions are set here */ - case V2D_COMMONVIEW_STACK: - { - /* zoom + aspect ratio are locked */ - v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); - v2d->minzoom = v2d->maxzoom = 1.0f; - - /* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */ - v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); - v2d->keeptot = V2D_KEEPTOT_STRICT; - tot_changed = 1; - - /* scroller settings are currently not set here... that is left for regions... */ - } - break; + /* tot rect has strictly regulated placement, and must only occur in +/- quadrant */ + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); + v2d->keeptot = V2D_KEEPTOT_STRICT; + tot_changed = do_init; + + /* scroller settings are currently not set here... that is left for regions... */ + } + break; + + /* 'stack view' - practically the same as list/channel view, except is located in the pos y half instead. + * zoom, aspect ratio, and alignment restrictions are set here */ + case V2D_COMMONVIEW_STACK: + { + /* zoom + aspect ratio are locked */ + v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); + v2d->minzoom = v2d->maxzoom = 1.0f; + + /* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */ + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); + v2d->keeptot = V2D_KEEPTOT_STRICT; + tot_changed = do_init; + + /* scroller settings are currently not set here... that is left for regions... */ + } + break; + + /* 'header' regions - zoom, aspect ratio, alignment, and panning restrictions are set here */ + case V2D_COMMONVIEW_HEADER: + { + /* zoom + aspect ratio are locked */ + v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); + v2d->minzoom = v2d->maxzoom = 1.0f; + + if (do_init) { + v2d->tot.xmin = 0.0f; + v2d->tot.xmax = winx; + v2d->tot.ymin = 0.0f; + v2d->tot.ymax = winy; + v2d->cur = v2d->tot; - /* 'header' regions - zoom, aspect ratio, alignment, and panning restrictions are set here */ - case V2D_COMMONVIEW_HEADER: - { - /* zoom + aspect ratio are locked */ - v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); - v2d->minzoom = v2d->maxzoom = 1.0f; v2d->min[0] = v2d->max[0] = (float)(winx - 1); v2d->min[1] = v2d->max[1] = (float)(winy - 1); - - /* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */ - v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); - v2d->keeptot = V2D_KEEPTOT_STRICT; - tot_changed = 1; - - /* panning in y-axis is prohibited */ - v2d->keepofs = V2D_LOCKOFS_Y; - - /* absolutely no scrollers allowed */ - v2d->scroll = 0; - } - break; + /* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */ + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); + v2d->keeptot = V2D_KEEPTOT_STRICT; + tot_changed = do_init; + + /* panning in y-axis is prohibited */ + v2d->keepofs = V2D_LOCKOFS_Y; + + /* absolutely no scrollers allowed */ + v2d->scroll = 0; + + } + break; + + /* panels view, with horizontal/vertical align */ + case V2D_COMMONVIEW_PANELS_UI: + { - /* panels view, with horizontal/vertical align */ - case V2D_COMMONVIEW_PANELS_UI: - { + /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */ + v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM | V2D_KEEPZOOM); + v2d->minzoom = 0.5f; + v2d->maxzoom = 2.0f; + + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); + v2d->keeptot = V2D_KEEPTOT_BOUNDS; + + /* note, scroll is being flipped in ED_region_panels() drawing */ + v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE; + v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE; + + if (do_init) { float panelzoom = (style) ? style->panelzoom : 1.0f; + float scrolw = v2d->scroll & V2D_SCROLL_RIGHT ? V2D_SCROLL_WIDTH : 0.0f; - /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */ - v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM | V2D_KEEPZOOM); - v2d->minzoom = 0.5f; - v2d->maxzoom = 2.0f; - //tot_changed = 1; - - v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); - v2d->keeptot = V2D_KEEPTOT_BOUNDS; - - v2d->scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); - v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - v2d->scroll &= ~V2D_SCROLL_VERTICAL_HIDE; - v2d->tot.xmin = 0.0f; - v2d->tot.xmax = winx; + v2d->tot.xmax = winx - scrolw; v2d->tot.ymax = 0.0f; v2d->tot.ymin = -winy; v2d->cur.xmin = 0.0f; - /* bad workaround for keeping zoom level with scrollers */ - v2d->cur.xmax = (winx - V2D_SCROLL_WIDTH) * panelzoom; + v2d->cur.xmax = (winx) * panelzoom - scrolw; v2d->cur.ymax = 0.0f; v2d->cur.ymin = (-winy) * panelzoom; } - break; - - /* other view types are completely defined using their own settings already */ - default: - /* we don't do anything here, as settings should be fine, but just make sure that rect */ - break; } + break; + + /* other view types are completely defined using their own settings already */ + default: + /* we don't do anything here, as settings should be fine, but just make sure that rect */ + break; } + /* set initialized flag so that View2D doesn't get reinitialised next time again */ + v2d->flag |= V2D_IS_INITIALISED; + /* store view size */ v2d->winx = winx; v2d->winy = winy; - /* set masks */ - view2d_masks(v2d); + /* set masks (always do), but leave scroller scheck to totrect_set */ + view2d_masks(v2d, 0); /* set 'tot' rect before setting cur? */ - if (tot_changed) - UI_view2d_totRect_set_resize(v2d, winx, winy, !init); + /* XXX confusing stuff here still - I made this function not check scroller hide - that happens in totrect_set */ + if (tot_changed) + UI_view2d_totRect_set_resize(v2d, winx, winy, !do_init); else - UI_view2d_curRect_validate_resize(v2d, !init); + ui_view2d_curRect_validate_resize(v2d, !do_init, 0); + } /* Ensure View2D rects remain in a viable configuration * - cur is not allowed to be: larger than max, smaller than min, or outside of tot */ // XXX pre2.5 -> this used to be called test_view2d() -void UI_view2d_curRect_validate_resize(View2D *v2d, int resize) +static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers) { float totwidth, totheight, curwidth, curheight, width, height; float winx, winy; @@ -715,12 +733,12 @@ void UI_view2d_curRect_validate_resize(View2D *v2d, int resize) } /* set masks */ - view2d_masks(v2d); + view2d_masks(v2d, mask_scrollers); } void UI_view2d_curRect_validate(View2D *v2d) { - UI_view2d_curRect_validate_resize(v2d, 0); + ui_view2d_curRect_validate_resize(v2d, 0, 1); } /* ------------------ */ @@ -844,7 +862,7 @@ void UI_view2d_curRect_reset(View2D *v2d) /* Change the size of the maximum viewable area (i.e. 'tot' rect) */ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize) { - int scroll = view2d_scroll_mapped(v2d->scroll); +// int scroll = view2d_scroll_mapped(v2d->scroll); /* don't do anything if either value is 0 */ width = abs(width); @@ -853,10 +871,10 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize /* hrumf! */ /* XXX: there are work arounds for this in the panel and file browse code. */ /* round to int, because this is called with width + V2D_SCROLL_WIDTH */ - if (scroll & V2D_SCROLL_HORIZONTAL) - width -= (int)V2D_SCROLL_WIDTH; - if (scroll & V2D_SCROLL_VERTICAL) - height -= (int)V2D_SCROLL_HEIGHT; +// if (scroll & V2D_SCROLL_HORIZONTAL) +// width -= (int)V2D_SCROLL_WIDTH; +// if (scroll & V2D_SCROLL_VERTICAL) +// height -= (int)V2D_SCROLL_HEIGHT; if (ELEM(0, width, height)) { if (G.debug & G_DEBUG) @@ -903,12 +921,21 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize } /* make sure that 'cur' rect is in a valid state as a result of these changes */ - UI_view2d_curRect_validate_resize(v2d, resize); + ui_view2d_curRect_validate_resize(v2d, resize, 1); + } void UI_view2d_totRect_set(View2D *v2d, int width, int height) { + int scroll = view2d_scroll_mapped(v2d->scroll); + UI_view2d_totRect_set_resize(v2d, width, height, 0); + + /* solve bad recursion... if scroller state changed, mask is different, so you get different rects */ + if (scroll != view2d_scroll_mapped(v2d->scroll)) { + UI_view2d_totRect_set_resize(v2d, width, height, 0); + } + } int UI_view2d_tab_set(View2D *v2d, int tab) @@ -1494,15 +1521,6 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, CLAMP(scrollers->hor_min, hor.xmin, hor.xmax - V2D_SCROLLER_HANDLE_SIZE); } - /* check whether sliders can disappear due to the full-range being used */ - if (v2d->keeptot) { - if ((fac1 <= 0.0f) && (fac2 >= 1.0f)) { - v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR; - scrollers->horfull = 1; - } - else - v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR; - } } /* vertical scrollers */ @@ -1536,15 +1554,6 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, CLAMP(scrollers->vert_min, vert.ymin, vert.ymax - V2D_SCROLLER_HANDLE_SIZE); } - /* check whether sliders can disappear due to the full-range being used */ - if (v2d->keeptot) { - if ((fac1 <= 0.0f) && (fac2 >= 1.0f)) { - v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR; - scrollers->vertfull = 1; - } - else - v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR; - } } /* grid markings on scrollbars */ @@ -1618,45 +1627,42 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* horizontal scrollbar */ if (scroll & V2D_SCROLL_HORIZONTAL) { - /* only draw scrollbar when it doesn't fill the entire space */ - if (vs->horfull == 0) { - bTheme *btheme = UI_GetTheme(); - uiWidgetColors wcol = btheme->tui.wcol_scroll; - rcti slider; - int state; - unsigned char col[4]; - - slider.xmin = vs->hor_min; - slider.xmax = vs->hor_max; - slider.ymin = hor.ymin; - slider.ymax = hor.ymax; - - state = (v2d->scroll_ui & V2D_SCROLL_H_ACTIVE) ? UI_SCROLL_PRESSED : 0; - - /* show zoom handles if: - * - zooming on x-axis is allowed (no scroll otherwise) - * - slider bubble is large enough (no overdraw confusion) - * - scale is shown on the scroller - * (workaround to make sure that button windows don't show these, - * and only the time-grids with their zoomability can do so) - */ - if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 && - (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) && - (BLI_rcti_size_x(&slider) > V2D_SCROLLER_HANDLE_SIZE)) - { - state |= UI_SCROLL_ARROWS; - } - - /* clean rect behind slider, but not with transparent background */ - UI_GetThemeColor4ubv(TH_BACK, col); - if (col[3] == 255) { - glColor3ub(col[0], col[1], col[2]); - glRecti(v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax); - } - - uiWidgetScrollDraw(&wcol, &hor, &slider, state); + bTheme *btheme = UI_GetTheme(); + uiWidgetColors wcol = btheme->tui.wcol_scroll; + rcti slider; + int state; + unsigned char col[4]; + + slider.xmin = vs->hor_min; + slider.xmax = vs->hor_max; + slider.ymin = hor.ymin; + slider.ymax = hor.ymax; + + state = (v2d->scroll_ui & V2D_SCROLL_H_ACTIVE) ? UI_SCROLL_PRESSED : 0; + + /* show zoom handles if: + * - zooming on x-axis is allowed (no scroll otherwise) + * - slider bubble is large enough (no overdraw confusion) + * - scale is shown on the scroller + * (workaround to make sure that button windows don't show these, + * and only the time-grids with their zoomability can do so) + */ + if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 && + (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) && + (BLI_rcti_size_x(&slider) > V2D_SCROLLER_HANDLE_SIZE)) + { + state |= UI_SCROLL_ARROWS; } + /* clean rect behind slider, but not with transparent background */ + UI_GetThemeColor4ubv(TH_BACK, col); + if (col[3] == 255) { + glColor3ub(col[0], col[1], col[2]); + glRecti(v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax); + } + + uiWidgetScrollDraw(&wcol, &hor, &slider, state); + /* scale indicators */ if ((scroll & V2D_SCROLL_SCALE_HORIZONTAL) && (vs->grid)) { View2DGrid *grid = vs->grid; @@ -1734,45 +1740,42 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* vertical scrollbar */ if (scroll & V2D_SCROLL_VERTICAL) { - /* only draw scrollbar when it doesn't fill the entire space */ - if (vs->vertfull == 0) { - bTheme *btheme = UI_GetTheme(); - uiWidgetColors wcol = btheme->tui.wcol_scroll; - rcti slider; - int state; - unsigned char col[4]; - - slider.xmin = vert.xmin; - slider.xmax = vert.xmax; - slider.ymin = vs->vert_min; - slider.ymax = vs->vert_max; - - state = (v2d->scroll_ui & V2D_SCROLL_V_ACTIVE) ? UI_SCROLL_PRESSED : 0; - - /* show zoom handles if: - * - zooming on y-axis is allowed (no scroll otherwise) - * - slider bubble is large enough (no overdraw confusion) - * - scale is shown on the scroller - * (workaround to make sure that button windows don't show these, - * and only the time-grids with their zoomability can do so) - */ - if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 && - (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) && - (BLI_rcti_size_y(&slider) > V2D_SCROLLER_HANDLE_SIZE)) - { - state |= UI_SCROLL_ARROWS; - } - - /* clean rect behind slider, but not with transparent background */ - UI_GetThemeColor4ubv(TH_BACK, col); - if (col[3] == 255) { - glColor3ub(col[0], col[1], col[2]); - glRecti(v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax); - } - - uiWidgetScrollDraw(&wcol, &vert, &slider, state); + bTheme *btheme = UI_GetTheme(); + uiWidgetColors wcol = btheme->tui.wcol_scroll; + rcti slider; + int state; + unsigned char col[4]; + + slider.xmin = vert.xmin; + slider.xmax = vert.xmax; + slider.ymin = vs->vert_min; + slider.ymax = vs->vert_max; + + state = (v2d->scroll_ui & V2D_SCROLL_V_ACTIVE) ? UI_SCROLL_PRESSED : 0; + + /* show zoom handles if: + * - zooming on y-axis is allowed (no scroll otherwise) + * - slider bubble is large enough (no overdraw confusion) + * - scale is shown on the scroller + * (workaround to make sure that button windows don't show these, + * and only the time-grids with their zoomability can do so) + */ + if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 && + (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) && + (BLI_rcti_size_y(&slider) > V2D_SCROLLER_HANDLE_SIZE)) + { + state |= UI_SCROLL_ARROWS; } + /* clean rect behind slider, but not with transparent background */ + UI_GetThemeColor4ubv(TH_BACK, col); + if (col[3] == 255) { + glColor3ub(col[0], col[1], col[2]); + glRecti(v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax); + } + + uiWidgetScrollDraw(&wcol, &vert, &slider, state); + /* scale indiators */ if ((scroll & V2D_SCROLL_SCALE_VERTICAL) && (vs->grid)) { diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 006644bf366..cc473998340 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -937,7 +937,7 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event) vzd = op->customdata; v2d = vzd->v2d; - if (event->type == MOUSEZOOM) { + if (event->type == MOUSEZOOM || event->type == MOUSEPAN) { float dx, dy, fac; vzd->lastx = event->prevx; @@ -948,6 +948,8 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event) */ fac = 0.01f * (event->x - event->prevx); dx = fac * BLI_rctf_size_x(&v2d->cur) / 10.0f; + if (event->type == MOUSEPAN) + fac = 0.01f * (event->y - event->prevy); dy = fac * BLI_rctf_size_y(&v2d->cur) / 10.0f; RNA_float_set(op->ptr, "deltax", dx); @@ -1744,8 +1746,8 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, wmEvent *event) } /* zone is also inappropriate if scroller is not visible... */ - if (((vsm->scroller == 'h') && (v2d->scroll & (V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_HORIZONTAL_FULLR))) || - ((vsm->scroller == 'v') && (v2d->scroll & (V2D_SCROLL_VERTICAL_HIDE | V2D_SCROLL_VERTICAL_FULLR))) ) + if (((vsm->scroller == 'h') && (v2d->scroll & (V2D_SCROLL_HORIZONTAL_FULLR))) || + ((vsm->scroller == 'v') && (v2d->scroll & (V2D_SCROLL_VERTICAL_FULLR))) ) { /* free customdata initialized */ scroller_activate_exit(C, op); @@ -1903,6 +1905,7 @@ void UI_view2d_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0); WM_keymap_verify_item(keymap, "VIEW2D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0); @@ -1951,6 +1954,7 @@ void UI_view2d_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEZOOM, 0, 0, 0); + WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_reset", HOMEKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 29139c5154f..3fbfaabbc0d 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -69,7 +69,14 @@ void paintface_flush_flags(Object *ob) int totface, totpoly; int i; - if (me == NULL || dm == NULL) + if (me == NULL) + return; + + /* we could call this directly in all areas that change selection, + * since this could become slow for realtime updates (circle-select for eg) */ + BKE_mesh_flush_select_from_polys(me); + + if (dm == NULL) return; /* @@ -477,7 +484,7 @@ int paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], in /* Get the face under the cursor */ me = BKE_mesh_from_object(ob); - if (!ED_mesh_pick_face(C, me, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) + if (!ED_mesh_pick_face(C, ob, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) return 0; if (index >= me->totpoly) @@ -603,7 +610,14 @@ void paintvert_flush_flags(Object *ob) int totvert; int i; - if (me == NULL || dm == NULL) + if (me == NULL) + return; + + /* we could call this directly in all areas that change selection, + * since this could become slow for realtime updates (circle-select for eg) */ + BKE_mesh_flush_select_from_verts(me); + + if (dm == NULL) return; index_array = dm->getVertDataArray(dm, CD_ORIGINDEX); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index c8a1264fd10..590bcd5939e 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1315,7 +1315,7 @@ static void knife_bgl_get_mats(KnifeTool_OpData *UNUSED(kcd), bglMats *mats) //copy_m4_m4(mats->projection, kcd->vc.rv3d->winmat); } -/* Calculate maximum excursion (doubled) from (0,0,0) of mesh */ +/* Calculate maximum excursion from (0,0,0) of mesh */ static void calc_ortho_extent(KnifeTool_OpData *kcd) { BMIter iter; @@ -1328,7 +1328,19 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) for (i = 0; i < 3; i++) max_xyz = max_ff(max_xyz, fabs(v->co[i])); } - kcd->ortho_extent = 2 * max_xyz; + kcd->ortho_extent = max_xyz; +} + +/* Clip the line (v1, v2) to planes perpendicular to it and distances d from + * the closest point on the line to the origin */ +static void clip_to_ortho_planes(float v1[3], float v2[3], float d) +{ + float closest[3]; + const float origin[3] = {0.0f, 0.0f, 0.0f}; + + closest_to_line_v3(closest, origin, v1, v2); + dist_ensure_v3_v3fl(v1, closest, d); + dist_ensure_v3_v3fl(v2, closest, d); } /* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */ @@ -1375,8 +1387,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) if (kcd->is_ortho) { if (kcd->ortho_extent == 0.0f) calc_ortho_extent(kcd); - limit_dist_v3(v1, v3, kcd->ortho_extent + 10.0f); - limit_dist_v3(v2, v4, kcd->ortho_extent + 10.0f); + clip_to_ortho_planes(v1, v3, kcd->ortho_extent + 10.0f); + clip_to_ortho_planes(v2, v4, kcd->ortho_extent + 10.0f); } BLI_smallhash_init(ehash); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 41b263e8929..27c68ce21bc 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -1674,7 +1674,7 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op) BMEditMesh *em = BMEdit_FromObject(obedit); int usex = TRUE, usey = TRUE, usez = TRUE, preserve_volume = TRUE; int i, repeat; - float lambda; + float lambda_factor; float lambda_border; BMIter fiter; BMFace *f; @@ -1695,7 +1695,7 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op) } repeat = RNA_int_get(op->ptr, "repeat"); - lambda = RNA_float_get(op->ptr, "lambda"); + lambda_factor = RNA_float_get(op->ptr, "lambda_factor"); lambda_border = RNA_float_get(op->ptr, "lambda_border"); usex = RNA_boolean_get(op->ptr, "use_x"); usey = RNA_boolean_get(op->ptr, "use_y"); @@ -1706,8 +1706,8 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op) for (i = 0; i < repeat; i++) { if (!EDBM_op_callf(em, op, - "smooth_laplacian_vert verts=%hv lambda=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b", - BM_ELEM_SELECT, lambda, lambda_border, usex, usey, usez, preserve_volume)) + "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b", + BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume)) { return OPERATOR_CANCELLED; } @@ -1740,7 +1740,7 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot) RNA_def_int(ot->srna, "repeat", 1, 1, 200, "Number of iterations to smooth the mesh", "", 1, 200); - RNA_def_float(ot->srna, "lambda", 0.00005f, 0.0000001f, 1000.0f, + RNA_def_float(ot->srna, "lambda_factor", 0.00005f, 0.0000001f, 1000.0f, "Lambda factor", "", 0.0000001f, 1000.0f); RNA_def_float(ot->srna, "lambda_border", 0.00005f, 0.0000001f, 1000.0f, "Lambda factor in border", "", 0.0000001f, 1000.0f); @@ -3582,7 +3582,7 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot) prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f), "Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f)); - RNA_def_property_float_default(prop, DEG2RADF(15.0f)); + RNA_def_property_float_default(prop, DEG2RADF(5.0f)); RNA_def_boolean(ot->srna, "use_dissolve_boundaries", 0, "All Boundaries", "Dissolve all vertices inbetween face boundaries"); } @@ -4768,6 +4768,7 @@ static int edbm_bevel_calc(wmOperator *op) #ifdef NEW_BEVEL float offset = RNA_float_get(op->ptr, "offset"); int segments = RNA_int_get(op->ptr, "segments"); + int vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); /* revert to original mesh */ if (opdata->is_modal) { @@ -4775,8 +4776,8 @@ static int edbm_bevel_calc(wmOperator *op) } if (!EDBM_op_init(em, &bmop, op, - "bevel geom=%hev offset=%f segments=%i", - BM_ELEM_SELECT, offset, segments)) + "bevel geom=%hev offset=%f segments=%i vertex_only=%b", + BM_ELEM_SELECT, offset, segments, vertex_only)) { return 0; } @@ -5101,6 +5102,7 @@ void MESH_OT_bevel(wmOperatorType *ot) #ifdef NEW_BEVEL RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Offset", "", 0.0f, 1.0f); RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8); + RNA_def_boolean(ot->srna, "vertex_only", FALSE, "Vertex only", "Bevel only vertices"); #else /* take note, used as a factor _and_ a distance depending on 'use_dist' */ RNA_def_float(ot->srna, "percent", 0.0f, -FLT_MAX, FLT_MAX, "Percentage", "", 0.0f, 1.0f); @@ -5732,18 +5734,6 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op) void MESH_OT_symmetrize(struct wmOperatorType *ot) { - static EnumPropertyItem axis_direction_items[] = { - {BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""}, - {BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""}, - - {BMO_SYMMETRIZE_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y to +Y", ""}, - {BMO_SYMMETRIZE_POSITIVE_Y, "POSITIVE_Y", 0, "+Y to -Y", ""}, - - {BMO_SYMMETRIZE_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z to +Z", ""}, - {BMO_SYMMETRIZE_POSITIVE_Z, "POSITIVE_Z", 0, "+Z to -Z", ""}, - {0, NULL, 0, NULL, NULL}, - }; - /* identifiers */ ot->name = "Symmetrize"; ot->description = "Enforce symmetry (both form and topological) across an axis"; @@ -5756,7 +5746,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "direction", axis_direction_items, + ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items, BMO_SYMMETRIZE_NEGATIVE_X, "Direction", "Which sides to copy from and to"); } diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index 1a81cab8de7..99fa85b3ee7 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -157,8 +157,9 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, int *nverts_r, float *tris_r = tris; } -static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris, - struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh) +static bool buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris, + struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh, + ReportList *reports) { float bmin[3], bmax[3]; struct recast_heightfield *solid; @@ -185,14 +186,20 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts /* Set the area where the navigation will be build. */ recast_calcGridSize(bmin, bmax, recastParams->cellsize, &width, &height); + /* zero dimensions cause zero alloc later on [#33758] */ + if (width <= 0 || height <= 0) { + BKE_report(reports, RPT_ERROR, "Object has a width or height of zero"); + return false; + } + /* ** Step 2: Rasterize input polygon soup ** */ /* Allocate voxel heightfield where we rasterize our input data to */ solid = recast_newHeightfield(); if (!recast_createHeightfield(solid, width, height, bmin, bmax, recastParams->cellsize, recastParams->cellheight)) { recast_destroyHeightfield(solid); - - return 0; + BKE_report(reports, RPT_ERROR, "Failed to create height field"); + return false; } /* Allocate array that can hold triangle flags */ @@ -215,7 +222,8 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts recast_destroyHeightfield(solid); recast_destroyCompactHeightfield(chf); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to create compact height field"); + return false; } recast_destroyHeightfield(solid); @@ -224,21 +232,24 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts if (!recast_erodeWalkableArea(walkableRadius, chf)) { recast_destroyCompactHeightfield(chf); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to erode walkable area"); + return false; } /* Prepare for region partitioning, by calculating distance field along the walkable surface */ if (!recast_buildDistanceField(chf)) { recast_destroyCompactHeightfield(chf); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to build distance field"); + return false; } /* Partition the walkable surface into simple regions without holes */ if (!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) { recast_destroyCompactHeightfield(chf); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to build regions"); + return false; } /* ** Step 5: Trace and simplify region contours ** */ @@ -249,7 +260,8 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts recast_destroyCompactHeightfield(chf); recast_destroyContourSet(cset); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to build contours"); + return false; } /* ** Step 6: Build polygons mesh from contours ** */ @@ -259,7 +271,8 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts recast_destroyContourSet(cset); recast_destroyPolyMesh(*pmesh); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to build poly mesh"); + return false; } @@ -272,13 +285,14 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts recast_destroyPolyMesh(*pmesh); recast_destroyPolyMeshDetail(*dmesh); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to build poly mesh detail"); + return false; } recast_destroyCompactHeightfield(chf); recast_destroyContourSet(cset); - return 1; + return true; } static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, Base *base) @@ -437,6 +451,7 @@ static int navmesh_create_exec(bContext *C, wmOperator *op) if (obs) { struct recast_polyMesh *pmesh = NULL; struct recast_polyMeshDetail *dmesh = NULL; + bool ok; int nverts = 0, ntris = 0; int *tris = 0; @@ -444,13 +459,14 @@ static int navmesh_create_exec(bContext *C, wmOperator *op) createVertsTrisData(C, obs, &nverts, &verts, &ntris, &tris); BLI_linklist_free(obs, NULL); - buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh); - createRepresentation(C, pmesh, dmesh, navmeshBase); + if ((ok = buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh, op->reports))) { + createRepresentation(C, pmesh, dmesh, navmeshBase); + } MEM_freeN(verts); MEM_freeN(tris); - return OPERATOR_FINISHED; + return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } else { BKE_report(op->reports, RPT_ERROR, "No mesh objects found"); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 773331d20f8..96b8f1080b9 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -40,6 +40,8 @@ #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -1165,9 +1167,12 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em) * * \return boolean TRUE == Found */ -int ED_mesh_pick_face(bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size) +int ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size) { ViewContext vc; + Mesh *me = ob->data; + + BLI_assert(me && GS(me->id.name) == ID_ME); if (!me || me->totpoly == 0) return 0; @@ -1197,11 +1202,14 @@ int ED_mesh_pick_face(bContext *C, Mesh *me, const int mval[2], unsigned int *in * Use when the back buffer stores face index values. but we want a vert. * This gets the face then finds the closest vertex to mval. */ -int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], unsigned int *index, int size) +int ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size) { unsigned int poly_index; + Mesh *me = ob->data; - if (ED_mesh_pick_face(C, me, mval, &poly_index, size)) { + BLI_assert(me && GS(me->id.name) == ID_ME); + + if (ED_mesh_pick_face(C, ob, mval, &poly_index, size)) { Scene *scene = CTX_data_scene(C); struct ARegion *ar = CTX_wm_region(C); @@ -1210,6 +1218,8 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], int v_idx_best = -1; if (dm->getVertCo) { + RegionView3D *rv3d = ar->regiondata; + /* find the vert closest to 'mval' */ const float mval_f[2] = {(float)mval[0], (float)mval[1]}; @@ -1217,14 +1227,15 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], int fidx; float len_best = FLT_MAX; + ED_view3d_init_mats_rv3d(ob, rv3d); + fidx = mp->totloop - 1; do { float co[3], sco[2], len; const int v_idx = me->mloop[mp->loopstart + fidx].v; dm->getVertCo(dm, v_idx, co); - mul_m4_v3(ob->obmat, co); - if (ED_view3d_project_float_global(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - len = len_squared_v2v2(mval_f, sco); + if (ED_view3d_project_float_object(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + len = len_manhattan_v2v2(mval_f, sco); if (len < len_best) { len_best = len; v_idx_best = v_idx; @@ -1250,31 +1261,97 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], * * \return boolean TRUE == Found */ -int ED_mesh_pick_vert(bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size) +typedef struct VertPickData { + const MVert *mvert; + const float *mval_f; /* [2] */ + ARegion *ar; + + /* runtime */ + float len_best; + int v_idx_best; +} VertPickData; + +static void ed_mesh_pick_vert__mapFunc(void *userData, int index, const float co[3], + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + VertPickData *data = userData; + if ((data->mvert[index].flag & ME_HIDE) == 0) { + float sco[2]; + + if (ED_view3d_project_float_object(data->ar, co, sco, V3D_PROJ_TEST_CLIP_DEFAULT) == V3D_PROJ_RET_OK) { + const float len = len_manhattan_v2v2(data->mval_f, sco); + if (len < data->len_best) { + data->len_best = len; + data->v_idx_best = index; + } + } + } +} +int ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size, int use_zbuf) { ViewContext vc; + Mesh *me = ob->data; + + BLI_assert(me && GS(me->id.name) == ID_ME); if (!me || me->totvert == 0) return 0; view3d_set_viewcontext(C, &vc); - if (size > 0) { - /* sample rect to increase chances of selecting, so that when clicking - * on an face in the backbuf, we can still select a vert */ + if (use_zbuf) { + if (size > 0) { + /* sample rect to increase chances of selecting, so that when clicking + * on an face in the backbuf, we can still select a vert */ - float dummy_dist; - *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL); + float dummy_dist; + *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL); + } + else { + /* sample only on the exact position */ + *index = view3d_sample_backbuf(&vc, mval[0], mval[1]); + } + + if ((*index) <= 0 || (*index) > (unsigned int)me->totvert) + return 0; + + (*index)--; } else { - /* sample only on the exact position */ - *index = view3d_sample_backbuf(&vc, mval[0], mval[1]); - } + /* derived mesh to find deformed locations */ + DerivedMesh *dm = mesh_get_derived_final(vc.scene, ob, CD_MASK_BAREMESH); + ARegion *ar = vc.ar; + RegionView3D *rv3d = ar->regiondata; - if ((*index) <= 0 || (*index) > (unsigned int)me->totvert) - return 0; + /* find the vert closest to 'mval' */ + const float mval_f[2] = {(float)mval[0], + (float)mval[1]}; - (*index)--; + VertPickData data = {0}; + + ED_view3d_init_mats_rv3d(ob, rv3d); + + if (dm == NULL) { + return 0; + } + + /* setup data */ + data.mvert = me->mvert; + data.ar = ar; + data.mval_f = mval_f; + data.len_best = FLT_MAX; + data.v_idx_best = -1; + + dm->foreachMappedVert(dm, ed_mesh_pick_vert__mapFunc, &data); + + dm->release(dm); + + if (data.v_idx_best == -1) { + return 0; + } + + *index = data.v_idx_best; + } return 1; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 473119c90f3..4db416b6f72 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -808,9 +808,16 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) if (RNA_struct_property_is_set(op->ptr, "name")) { char name[MAX_ID_NAME - 2]; - + RNA_string_get(op->ptr, "name", name); group = (Group *)BKE_libblock_find_name(ID_GR, name); + + if (0 == RNA_struct_property_is_set(op->ptr, "location")) { + wmEvent *event = CTX_wm_window(C)->eventstate; + ED_object_location_from_view(C, loc); + ED_view3d_cursor3d_position(C, loc, event->x, event->y); + RNA_float_set_array(op->ptr, "location", loc); + } } else group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group")); @@ -1994,6 +2001,7 @@ void OBJECT_OT_duplicate(wmOperatorType *ot) static int add_named_exec(bContext *C, wmOperator *op) { + wmEvent *event = CTX_wm_window(C)->eventstate; Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Base *basen, *base; @@ -2026,6 +2034,8 @@ static int add_named_exec(bContext *C, wmOperator *op) basen->lay = basen->object->lay = scene->lay; ED_object_location_from_view(C, basen->object->loc); + ED_view3d_cursor3d_position(C, basen->object->loc, event->x, event->y); + ED_base_object_activate(C, basen); copy_object_set_idnew(C, dupflag); diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index d3ebd1dae0a..f36c6d79783 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -89,6 +89,7 @@ typedef struct MultiresBakerJobData { struct MultiresBakerJobData *next, *prev; DerivedMesh *lores_dm, *hires_dm; int simple, lvl, tot_lvl; + ListBase images; } MultiresBakerJobData; /* data passing to multires-baker job */ @@ -429,7 +430,7 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa RE_multires_bake_images(&bkr); - BLI_freelistN(&bkr.image); + data->images = bkr.image; baked_objects++; } @@ -439,12 +440,22 @@ static void multiresbake_freejob(void *bkv) { MultiresBakeJob *bkj = bkv; MultiresBakerJobData *data, *next; + LinkData *link; data = bkj->data.first; while (data) { next = data->next; data->lores_dm->release(data->lores_dm); data->hires_dm->release(data->hires_dm); + + /* delete here, since this delete will be called from main thread */ + for (link = data->images.first; link; link = link->next) { + Image *ima = (Image *)link->data; + GPU_free_image(ima); + } + + BLI_freelistN(&data->images); + MEM_freeN(data); data = next; } diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index f78e1203bc4..6cb7cd5e326 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -141,7 +141,7 @@ ListBase *get_constraint_lb(Object *ob, bConstraint *con, bPoseChannel **pchan_r /* single constraint */ bConstraint *get_active_constraint(Object *ob) { - return constraints_get_active(get_active_constraints(ob)); + return BKE_constraints_get_active(get_active_constraints(ob)); } /* -------------- Constraint Management (Add New, Remove, Rename) -------------------- */ @@ -225,7 +225,7 @@ static void update_pyconstraint_cb(void *arg1, void *arg2) /* helper function for add_constriant - sets the last target for the active constraint */ static void set_constraint_nth_target(bConstraint *con, Object *target, const char subtarget[], int index) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; int num_targets, i; @@ -297,7 +297,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan) /* Check all constraints - is constraint valid? */ if (conlist) { for (curcon = conlist->first; curcon; curcon = curcon->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -610,7 +610,7 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int list = get_active_constraints(ob); } - con = constraints_findByName(list, constraint_name); + con = BKE_constraints_findByName(list, constraint_name); //if (G.debug & G_DEBUG) //printf("constraint found = %p, %s\n", (void *)con, (con)?con->name:"<Not found>"); @@ -1123,7 +1123,7 @@ void ED_object_constraint_set_active(Object *ob, bConstraint *con) if ((lb && con) && (con->flag & CONSTRAINT_ACTIVE)) return; - constraints_set_active(lb, con); + BKE_constraints_set_active(lb, con); } void ED_object_constraint_update(Object *ob) @@ -1162,9 +1162,9 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) const short is_ik = ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK); /* free the constraint */ - if (remove_constraint(lb, con)) { + if (BKE_remove_constraint(lb, con)) { /* there's no active constraint now, so make sure this is the case */ - constraints_set_active(lb, NULL); + BKE_constraints_set_active(lb, NULL); ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */ @@ -1308,7 +1308,7 @@ static int pose_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op)) /* free constraints for all selected bones */ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) { - free_constraints(&pchan->constraints); + BKE_free_constraints(&pchan->constraints); pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK | PCHAN_HAS_CONST); } CTX_DATA_END; @@ -1346,7 +1346,7 @@ static int object_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op)) /* do freeing */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - free_constraints(&ob->constraints); + BKE_free_constraints(&ob->constraints); DAG_id_tag_update(&ob->id, OB_RECALC_OB); } CTX_DATA_END; @@ -1391,7 +1391,7 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op) { /* if we're not handling the object we're copying from, copy all constraints over */ if (pchan != chan) { - copy_constraints(&chan->constraints, &pchan->constraints, TRUE); + BKE_copy_constraints(&chan->constraints, &pchan->constraints, TRUE); /* update flags (need to add here, not just copy) */ chan->constflag |= pchan->constflag; } @@ -1432,7 +1432,7 @@ static int object_constraint_copy_exec(bContext *C, wmOperator *UNUSED(op)) { /* if we're not handling the object we're copying from, copy all constraints over */ if (obact != ob) { - copy_constraints(&ob->constraints, &obact->constraints, TRUE); + BKE_copy_constraints(&ob->constraints, &obact->constraints, TRUE); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } } @@ -1642,9 +1642,9 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase /* create a new constraint of the type requried, and add it to the active/given constraints list */ if (pchan) - con = add_pose_constraint(ob, pchan, NULL, type); + con = BKE_add_pose_constraint(ob, pchan, NULL, type); else - con = add_ob_constraint(ob, NULL, type); + con = BKE_add_ob_constraint(ob, NULL, type); /* get the first selected object/bone, and make that the target * - apart from the buttons-window add buttons, we shouldn't add in this way @@ -1940,7 +1940,7 @@ static int pose_ik_clear_exec(bContext *C, wmOperator *UNUSED(op)) for (con = pchan->constraints.first; con; con = next) { next = con->next; if (con->type == CONSTRAINT_TYPE_KINEMATIC) { - remove_constraint(&pchan->constraints, con); + BKE_remove_constraint(&pchan->constraints, con); } } pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index c9492d8f683..fcc3b5d012e 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -954,7 +954,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) } else if (event == 22) { /* Copy the constraint channels over */ - copy_constraints(&base->object->constraints, &ob->constraints, TRUE); + BKE_copy_constraints(&base->object->constraints, &ob->constraints, TRUE); do_scene_sort = TRUE; } diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index a3bf27a19d6..7bf1a5db3b1 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -313,7 +313,7 @@ static int group_create_exec(bContext *C, wmOperator *op) group = add_group(name); - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) + CTX_DATA_BEGIN (C, Base *, base, selected_bases) { add_to_group(group, base->object, scene, base); } diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c index 4aa2e825954..c9eae776ac7 100644 --- a/source/blender/editors/object/object_lattice.c +++ b/source/blender/editors/object/object_lattice.c @@ -52,7 +52,7 @@ #include "BKE_depsgraph.h" #include "BKE_key.h" #include "BKE_lattice.h" -#include "BKE_mesh.h" +#include "BKE_deform.h" #include "ED_lattice.h" #include "ED_object.h" @@ -77,7 +77,7 @@ void free_editLatt(Object *ob) if (editlt->def) MEM_freeN(editlt->def); if (editlt->dvert) - free_dverts(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw); + BKE_defvert_array_free(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw); MEM_freeN(editlt); MEM_freeN(lt->editlatt); @@ -104,7 +104,7 @@ void make_editLatt(Object *obedit) if (lt->dvert) { int tot = lt->pntsu * lt->pntsv * lt->pntsw; lt->editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); - copy_dverts(lt->editlatt->latt->dvert, lt->dvert, tot); + BKE_defvert_array_copy(lt->editlatt->latt->dvert, lt->dvert, tot); } if (lt->key) lt->editlatt->shapenr = obedit->shapenr; @@ -156,7 +156,7 @@ void load_editLatt(Object *obedit) } if (lt->dvert) { - free_dverts(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); lt->dvert = NULL; } @@ -164,7 +164,7 @@ void load_editLatt(Object *obedit) tot = lt->pntsu * lt->pntsv * lt->pntsw; lt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); - copy_dverts(lt->dvert, editlt->dvert, tot); + BKE_defvert_array_copy(lt->dvert, editlt->dvert, tot); } } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index d19277d20a2..03b50c05071 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -252,15 +252,6 @@ void ED_operatormacros_object(void) RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF); } - /* XXX */ - ot = WM_operatortype_append_macro("OBJECT_OT_add_named_cursor", "Add Named At Cursor", - "Add named object at cursor", OPTYPE_UNDO | OPTYPE_REGISTER); - if (ot) { - RNA_def_string(ot->srna, "name", "Cube", MAX_ID_NAME - 2, "Name", "Object name to add"); - - WM_operatortype_macro_define(ot, "VIEW3D_OT_cursor3d"); - WM_operatortype_macro_define(ot, "OBJECT_OT_add_named"); - } } static int object_mode_poll(bContext *C) diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 0988a196fb1..fa44d3d7fb4 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -716,12 +716,12 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object bFollowPathConstraint *data; float cmat[4][4], vec[3]; - con = add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH); + con = BKE_add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH); data = con->data; data->tar = par; - get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); + BKE_get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); sub_v3_v3v3(vec, ob->obmat[3], cmat[3]); ob->loc[0] = vec[0]; @@ -1051,7 +1051,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op) for (con = ob->constraints.last; con; con = pcon) { pcon = con->prev; if (ELEM3(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK)) - remove_constraint(&ob->constraints, con); + BKE_remove_constraint(&ob->constraints, con); } if (type == 1) @@ -1109,7 +1109,7 @@ static int track_set_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob != obact) { - con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK); + con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK); data = con->data; data->tar = obact; @@ -1129,7 +1129,7 @@ static int track_set_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob != obact) { - con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO); + con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO); data = con->data; data->tar = obact; @@ -1151,7 +1151,7 @@ static int track_set_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob != obact) { - con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK); + con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK); data = con->data; data->tar = obact; diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 2aa737d204d..07eca749a74 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -42,6 +42,7 @@ #include "DNA_property_types.h" #include "DNA_scene_types.h" #include "DNA_armature_types.h" +#include "DNA_lamp_types.h" #include "BLI_math.h" #include "BLI_listbase.h" @@ -525,6 +526,7 @@ static EnumPropertyItem prop_select_grouped_types[] = { {10, "COLOR", 0, "Color", "Object Color"}, {11, "PROPERTIES", 0, "Properties", "Game Properties"}, {12, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"}, + {13, "LAMP_TYPE", 0, "Lamp Type", "Matching lamp types"}, {0, NULL, 0, NULL, NULL} }; @@ -656,7 +658,25 @@ static short select_grouped_siblings(bContext *C, Object *ob) CTX_DATA_END; return changed; } +static short select_similar_lamps(bContext *C, Object *ob) +{ + Lamp *la = ob->data; + + short changed = 0; + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) + { + if (base->object->type == OB_LAMP) { + Lamp *la_test = base->object->data; + if ((la->type == la_test->type) && !(base->flag & SELECT)) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } + } + CTX_DATA_END; + return changed; +} static short select_grouped_type(bContext *C, Object *ob) { short changed = 0; @@ -803,7 +823,12 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "No active object"); return OPERATOR_CANCELLED; } - + + if (nr == 13 && ob->type != OB_LAMP) { + BKE_report(op->reports, RPT_ERROR, "Active object must be a lamp"); + return OPERATOR_CANCELLED; + } + if (nr == 1) changed |= select_grouped_children(C, ob, 1); else if (nr == 2) changed |= select_grouped_children(C, ob, 0); else if (nr == 3) changed |= select_grouped_parent(C); @@ -816,6 +841,7 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) else if (nr == 10) changed |= select_grouped_color(C, ob); else if (nr == 11) changed |= select_grouped_gameprops(C, ob); else if (nr == 12) changed |= select_grouped_keyingset(C, ob); + else if (nr == 13) changed |= select_similar_lamps(C, ob); if (changed) { WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 16fe94ff2e5..cbc076b3342 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -281,7 +281,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender) IMB_color_to_bw(ibuf); } - BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, FALSE); + BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, FALSE); ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, TRUE); /* no need to stamp here */ if (ok) printf("OpenGL Render written to '%s'\n", name); else printf("OpenGL Render failed to write '%s'\n", name); @@ -505,7 +505,7 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op) is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype); if (!is_movie) { - BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, TRUE); + BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, TRUE); if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) { printf("skipping existing frame \"%s\"\n", name); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index a864fe306b3..8d748d3ea20 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -280,11 +280,6 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre sce->r.tiley = sce->r.ysch / 4; } - /* exception: don't apply render part of display transform for texture previews or icons */ - if ((id && sp->pr_method == PR_ICON_RENDER) || id_type == ID_TE) { - BKE_scene_disable_color_management(sce); - } - if ((id && sp->pr_method == PR_ICON_RENDER) && id_type != ID_WO) sce->r.alphamode = R_ALPHAPREMUL; else @@ -488,24 +483,15 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre /* new UI convention: draw is in pixel space already. */ /* uses ROUNDBOX button in block to get the rect */ -static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int first, rcti *rect, rcti *newrect) +static int ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, rcti *newrect) { Render *re; RenderResult rres; char name[32]; - int do_gamma_correct = FALSE, do_predivide = FALSE; int offx = 0; int newx = BLI_rcti_size_x(rect); int newy = BLI_rcti_size_y(rect); - if (id && GS(id->name) != ID_TE) { - /* exception: don't color manage texture previews - show the raw values */ - if (sce) { - do_gamma_correct = TRUE; - do_predivide = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE; - } - } - if (!split || first) sprintf(name, "Preview %p", (void *)sa); else sprintf(name, "SecondPreview %p", (void *)sa); @@ -520,8 +506,10 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int } } + /* test if something rendered ok */ re = RE_GetRender(name); RE_AcquireResultImage(re, &rres); + RE_ReleaseResultImage(re); if (rres.rectf) { @@ -531,40 +519,20 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty); if (rres.rectx && rres.recty) { - /* temporary conversion to byte for drawing */ + unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"); float fx = rect->xmin + offx; float fy = rect->ymin; - int dither = 0; - unsigned char *rect_byte; - - rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"); - - if (do_gamma_correct) { - IMB_display_buffer_transform_apply(rect_byte, rres.rectf, rres.rectx, rres.recty, 4, - &sce->view_settings, &sce->display_settings, do_predivide); - - } - else { - /* OCIO_TODO: currently seems an exception for textures (came fro mlegacish time), - * but is it indeed expected behavior, or textures should be - * color managed as well? - */ - IMB_buffer_byte_from_float(rect_byte, rres.rectf, - 4, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, do_predivide, - rres.rectx, rres.recty, rres.rectx, rres.rectx); - } - + + RE_ResultGet32(re, (unsigned int *)rect_byte); glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte); - + MEM_freeN(rect_byte); + + return 1; } - - RE_ReleaseResultImage(re); - return 1; } } - RE_ReleaseResultImage(re); return 0; } @@ -572,7 +540,6 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r { if (idp) { ScrArea *sa = CTX_wm_area(C); - Scene *sce = CTX_data_scene(C); ID *id = (ID *)idp; ID *parent = (ID *)parentp; MTex *slot = (MTex *)slotp; @@ -588,11 +555,11 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r newrect.ymax = rect->ymin; if (parent) { - ok = ed_preview_draw_rect(sa, sce, id, 1, 1, rect, &newrect); - ok &= ed_preview_draw_rect(sa, sce, parent, 1, 0, rect, &newrect); + ok = ed_preview_draw_rect(sa, 1, 1, rect, &newrect); + ok &= ed_preview_draw_rect(sa, 1, 0, rect, &newrect); } else - ok = ed_preview_draw_rect(sa, sce, id, 0, 0, rect, &newrect); + ok = ed_preview_draw_rect(sa, 0, 0, rect, &newrect); if (ok) *rect = newrect; diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index bc33936b2e3..dfc53d0b195 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -1310,7 +1310,7 @@ static int envmap_save_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", path); if (scene->r.scemode & R_EXTENSION) { - BKE_add_image_extension(path, imtype); + BKE_add_image_extension(path, &scene->r.im_format); } WM_cursor_wait(1); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index fbdec3dd8ad..5af60726f14 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -574,8 +574,8 @@ static void area_azone_initialize(bScreen *screen, ScrArea *sa) az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone"); BLI_addtail(&(sa->actionzones), az); az->type = AZONE_AREA; - az->x1 = sa->totrct.xmin - 1; - az->y1 = sa->totrct.ymin - 1; + az->x1 = sa->totrct.xmin; + az->y1 = sa->totrct.ymin; az->x2 = sa->totrct.xmin + (AZONESPOT - 1); az->y2 = sa->totrct.ymin + (AZONESPOT - 1); BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2); @@ -917,7 +917,7 @@ static int region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar) { if (U.uiflag2 & USER_REGION_OVERLAP) if (WM_is_draw_triple(win)) - if (ELEM5(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ, SPACE_CLIP, SPACE_NODE)) + if (ELEM4(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ, SPACE_CLIP)) if (ELEM3(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS)) return 1; return 0; @@ -1300,6 +1300,9 @@ void ED_region_init(bContext *C, ARegion *ar) ar->winx = BLI_rcti_size_x(&ar->winrct) + 1; ar->winy = BLI_rcti_size_y(&ar->winrct) + 1; + /* v2d mask is used to subtract scrollbars from a 2d view. Needs initialize here. */ + BLI_rcti_init(&ar->v2d.mask, 0, ar->winx - 1, 0, ar->winy -1); + /* UI convention */ wmOrtho2(-0.01f, ar->winx - 0.01f, -0.01f, ar->winy - 0.01f); glLoadIdentity(); @@ -1612,86 +1615,141 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char * View2D *v2d = &ar->v2d; View2DScrollers *scrollers; int x, y, xco, yco, w, em, triangle, open, newcontext = 0; - + int redo; + int scroll; + if (contextnr >= 0) newcontext = UI_view2d_tab_set(v2d, contextnr); - + + /* before setting the view */ if (vertical) { - w = BLI_rctf_size_x(&v2d->cur); - em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y; + /* only allow scrolling in vertical direction */ + v2d->keepofs |= V2D_LOCKOFS_X | V2D_KEEPOFS_Y; + v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X); + v2d->scroll &= ~(V2D_SCROLL_BOTTOM); + v2d->scroll |= (V2D_SCROLL_RIGHT); } else { - w = UI_PANEL_WIDTH; - em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y; + /* for now, allow scrolling in both directions (since layouts are optimized for vertical, + * they often don't fit in horizontal layout) + */ + v2d->keepofs &= ~(V2D_LOCKOFS_X | V2D_LOCKOFS_Y | V2D_KEEPOFS_X | V2D_KEEPOFS_Y); + v2d->scroll |= (V2D_SCROLL_BOTTOM); + v2d->scroll &= ~(V2D_SCROLL_RIGHT); } - /* create panels */ - uiBeginPanels(C, ar); + scroll = v2d->scroll; + + /* sortof hack - but we cannot predict the height of panels, until it's being generated */ + /* the layout engine works with fixed width (from v2d->cur), which is being set at end of the loop */ + /* in case scroller settings (hide flags) differ from previous, the whole loop gets done again */ + for (redo = 2; redo > 0; redo--) { + + if (vertical) { + w = BLI_rctf_size_x(&v2d->cur); + em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y; + } + else { + w = UI_PANEL_WIDTH; + em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y; + } + + /* create panels */ + uiBeginPanels(C, ar); - /* set view2d view matrix for scrolling (without scrollers) */ - UI_view2d_view_ortho(v2d); + /* set view2d view matrix - uiBeginBlock() stores it */ + UI_view2d_view_ortho(v2d); - for (pt = ar->type->paneltypes.first; pt; pt = pt->next) { - /* verify context */ - if (context) - if (pt->context[0] && strcmp(context, pt->context) != 0) - continue; + for (pt = ar->type->paneltypes.first; pt; pt = pt->next) { + /* verify context */ + if (context) + if (pt->context[0] && strcmp(context, pt->context) != 0) + continue; - /* draw panel */ - if (pt->draw && (!pt->poll || pt->poll(C, pt))) { - block = uiBeginBlock(C, ar, pt->idname, UI_EMBOSS); - panel = uiBeginPanel(sa, ar, block, pt, &open); + /* draw panel */ + if (pt->draw && (!pt->poll || pt->poll(C, pt))) { + block = uiBeginBlock(C, ar, pt->idname, UI_EMBOSS); + panel = uiBeginPanel(sa, ar, block, pt, &open); - /* bad fixed values */ - triangle = (int)(UI_UNIT_Y * 1.1f); + /* bad fixed values */ + triangle = (int)(UI_UNIT_Y * 1.1f); - if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) { - /* for enabled buttons */ - panel->layout = uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, - triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, style); + if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) { + /* for enabled buttons */ + panel->layout = uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, + triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, style); - pt->draw_header(C, panel); + pt->draw_header(C, panel); - uiBlockLayoutResolve(block, &xco, &yco); - panel->labelofs = xco - triangle; - panel->layout = NULL; - } - else { - panel->labelofs = 0; - } + uiBlockLayoutResolve(block, &xco, &yco); + panel->labelofs = xco - triangle; + panel->layout = NULL; + } + else { + panel->labelofs = 0; + } - if (open) { - short panelContext; - - /* panel context can either be toolbar region or normal panels region */ - if (ar->regiontype == RGN_TYPE_TOOLS) - panelContext = UI_LAYOUT_TOOLBAR; - else - panelContext = UI_LAYOUT_PANEL; - - panel->layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, panelContext, - style->panelspace, 0, w - 2 * style->panelspace, em, style); + if (open) { + short panelContext; + + /* panel context can either be toolbar region or normal panels region */ + if (ar->regiontype == RGN_TYPE_TOOLS) + panelContext = UI_LAYOUT_TOOLBAR; + else + panelContext = UI_LAYOUT_PANEL; + + panel->layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, panelContext, + style->panelspace, 0, w - 2 * style->panelspace, em, style); - pt->draw(C, panel); + pt->draw(C, panel); - uiBlockLayoutResolve(block, &xco, &yco); - panel->layout = NULL; + uiBlockLayoutResolve(block, &xco, &yco); + panel->layout = NULL; - yco -= 2 * style->panelspace; - uiEndPanel(block, w, -yco); - } - else { - yco = 0; - uiEndPanel(block, w, 0); + yco -= 2 * style->panelspace; + uiEndPanel(block, w, -yco); + } + else { + yco = 0; + uiEndPanel(block, w, 0); + } + + uiEndBlock(C, block); } + } - uiEndBlock(C, block); + /* align panels and return size */ + uiEndPanels(C, ar, &x, &y); + + /* before setting the view */ + if (vertical) { + /* we always keep the scroll offset - so the total view gets increased with the scrolled away part */ + if (v2d->cur.ymax < - 0.001f) + y = min_ii(y, v2d->cur.ymin); + + y = -y; + } + else { + /* don't jump back when panels close or hide */ + if (!newcontext) + x = max_ii(x, v2d->cur.xmax); + y = -y; } + + /* this also changes the 'cur' */ + UI_view2d_totRect_set(v2d, x, y); + + if (scroll != v2d->scroll) { + /* Note: this code scales fine, but because of rounding differences, positions of elements + * flip +1 or -1 pixel compared to redoing the entire layout again. + * Leaving in commented code for future tests */ + /* uiScalePanels(ar, BLI_rctf_size_x(&v2d->cur)); + break; */ + } + else break; } - - /* align panels and return size */ - uiEndPanels(C, ar, &x, &y); - + + /* clear */ if (ar->overlap) { /* view should be in pixelspace */ @@ -1706,36 +1764,6 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char * glClear(GL_COLOR_BUFFER_BIT); } - /* before setting the view */ - if (vertical) { - /* only allow scrolling in vertical direction */ - v2d->keepofs |= V2D_LOCKOFS_X | V2D_KEEPOFS_Y; - v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X); - v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - v2d->scroll &= ~V2D_SCROLL_VERTICAL_HIDE; - - /* ensure tot is set correctly, to keep views on bottons, with sliders */ - y = min_ii(y, v2d->cur.ymin); - y = -y; - } - else { - /* for now, allow scrolling in both directions (since layouts are optimized for vertical, - * they often don't fit in horizontal layout) - */ - v2d->keepofs &= ~(V2D_LOCKOFS_X | V2D_LOCKOFS_Y | V2D_KEEPOFS_X | V2D_KEEPOFS_Y); - //v2d->keepofs |= V2D_LOCKOFS_Y|V2D_KEEPOFS_X; - //v2d->keepofs &= ~(V2D_LOCKOFS_X|V2D_KEEPOFS_Y); - v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE; - v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_HIDE; - - /* don't jump back when panels close or hide */ - if (!newcontext) - x = max_ii(x, v2d->cur.xmax); - y = -y; - } - - /* +V2D_SCROLL_HEIGHT is workaround to set the actual height (needs to be int) */ - UI_view2d_totRect_set(v2d, x + (int)V2D_SCROLL_WIDTH, y + (int)V2D_SCROLL_HEIGHT); /* set the view */ UI_view2d_view_ortho(v2d); @@ -1755,17 +1783,6 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char * void ED_region_panels_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; - - /* XXX quick hacks for files saved with 2.5 already (i.e. the builtin defaults file) - * scrollbars for button regions */ - ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); - ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - ar->v2d.scroll &= ~V2D_SCROLL_VERTICAL_HIDE; - ar->v2d.keepzoom |= V2D_KEEPZOOM; - - /* correctly initialized User-Prefs? */ - if (!(ar->v2d.align & V2D_ALIGN_NO_POS_Y)) - ar->v2d.flag &= ~V2D_IS_INITIALISED; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy); @@ -1828,6 +1845,7 @@ void ED_region_header(const bContext *C, ARegion *ar) void ED_region_header_init(ARegion *ar) { + ar->v2d.flag &= ~V2D_IS_INITIALISED; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy); } diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index ca85daadf3b..2982e1f21af 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -223,7 +223,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event) static int screenshot_check(bContext *UNUSED(C), wmOperator *op) { ScreenshotData *scd = op->customdata; - return WM_operator_filesel_ensure_ext_imtype(op, scd->im_format.imtype); + return WM_operator_filesel_ensure_ext_imtype(op, &scd->im_format); } static int screenshot_cancel(bContext *UNUSED(C), wmOperator *op) @@ -361,7 +361,7 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float char name[FILE_MAX]; int ok; - BKE_makepicstring(name, rd.pic, sj->bmain->name, rd.cfra, rd.im_format.imtype, rd.scemode & R_EXTENSION, TRUE); + BKE_makepicstring(name, rd.pic, sj->bmain->name, rd.cfra, &rd.im_format, rd.scemode & R_EXTENSION, TRUE); ibuf->rect = sj->dumprect; ok = BKE_imbuf_write(ibuf, name, &rd.im_format); diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index ae72dce1415..5bed31e2e52 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -42,6 +42,7 @@ set(SRC paint_cursor.c paint_hide.c paint_image.c + paint_image_2d.c paint_mask.c paint_ops.c paint_stroke.c diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index 36fe4715fc0..d50261a3b98 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -112,8 +112,8 @@ static void partialvis_update_mesh(Object *ob, int *vert_indices; int any_changed = 0, any_visible = 0, totvert, i; - BLI_pbvh_node_num_verts(pbvh, node, NULL, &totvert); - BLI_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert); + BKE_pbvh_node_num_verts(pbvh, node, NULL, &totvert); + BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert); paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); @@ -136,8 +136,8 @@ static void partialvis_update_mesh(Object *ob, } if (any_changed) { - BLI_pbvh_node_mark_rebuild_draw(node); - BLI_pbvh_node_fully_hidden_set(node, !any_visible); + BKE_pbvh_node_mark_rebuild_draw(node); + BKE_pbvh_node_fully_hidden_set(node, !any_visible); } } @@ -157,11 +157,11 @@ static void partialvis_update_grids(Object *ob, int *grid_indices, totgrid, any_changed, i; /* get PBVH data */ - BLI_pbvh_node_get_grids(pbvh, node, + BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, &grids, NULL); - grid_hidden = BLI_pbvh_grid_hidden(pbvh); - BLI_pbvh_get_grid_key(pbvh, &key); + grid_hidden = BKE_pbvh_grid_hidden(pbvh); + BKE_pbvh_get_grid_key(pbvh, &key); sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); @@ -226,12 +226,81 @@ static void partialvis_update_grids(Object *ob, /* mark updates if anything was hidden/shown */ if (any_changed) { - BLI_pbvh_node_mark_rebuild_draw(node); - BLI_pbvh_node_fully_hidden_set(node, !any_visible); + BKE_pbvh_node_mark_rebuild_draw(node); + BKE_pbvh_node_fully_hidden_set(node, !any_visible); multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED); } } +static void partialvis_update_bmesh_verts(BMesh *bm, + GHash *verts, + PartialVisAction action, + PartialVisArea area, + float planes[4][4], + int *any_changed, + int *any_visible) +{ + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + float *vmask = CustomData_bmesh_get(&bm->vdata, + v->head.data, + CD_PAINT_MASK); + + /* hide vertex if in the hide volume */ + if (is_effected(area, planes, v->co, *vmask)) { + if (action == PARTIALVIS_HIDE) + BM_elem_flag_enable(v, BM_ELEM_HIDDEN); + else + BM_elem_flag_disable(v, BM_ELEM_HIDDEN); + (*any_changed) = TRUE; + } + + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + (*any_visible) = TRUE; + } +} + +static void partialvis_update_bmesh(Object *ob, + PBVH *pbvh, + PBVHNode *node, + PartialVisAction action, + PartialVisArea area, + float planes[4][4]) +{ + BMesh *bm; + GHash *unique, *other; + int any_changed = 0, any_visible = 0; + + bm = BKE_pbvh_get_bmesh(pbvh); + unique = BKE_pbvh_bmesh_node_unique_verts(node); + other = BKE_pbvh_bmesh_node_other_verts(node); + + sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); + + partialvis_update_bmesh_verts(bm, + unique, + action, + area, + planes, + &any_changed, + &any_visible); + + partialvis_update_bmesh_verts(bm, + other, + action, + area, + planes, + &any_changed, + &any_visible); + + if (any_changed) { + BKE_pbvh_node_mark_rebuild_draw(node); + BKE_pbvh_node_fully_hidden_set(node, !any_visible); + } +} + static void rect_from_props(rcti *rect, PointerRNA *ptr) { rect->xmin = RNA_int_get(ptr, "xmin"); @@ -265,22 +334,22 @@ static void get_pbvh_nodes(PBVH *pbvh, float clip_planes[4][4], PartialVisArea mode) { - BLI_pbvh_SearchCallback cb = NULL; + BKE_pbvh_SearchCallback cb = NULL; /* select search callback */ switch (mode) { case PARTIALVIS_INSIDE: - cb = BLI_pbvh_node_planes_contain_AABB; + cb = BKE_pbvh_node_planes_contain_AABB; break; case PARTIALVIS_OUTSIDE: - cb = BLI_pbvh_node_planes_exclude_AABB; + cb = BKE_pbvh_node_planes_exclude_AABB; break; case PARTIALVIS_ALL: case PARTIALVIS_MASKED: break; } - BLI_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode); + BKE_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode); } static int hide_show_exec(bContext *C, wmOperator *op) @@ -310,7 +379,7 @@ static int hide_show_exec(bContext *C, wmOperator *op) ob->sculpt->pbvh = pbvh; get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area); - pbvh_type = BLI_pbvh_type(pbvh); + pbvh_type = BKE_pbvh_type(pbvh); /* start undo */ switch (action) { @@ -330,6 +399,9 @@ static int hide_show_exec(bContext *C, wmOperator *op) case PBVH_GRIDS: partialvis_update_grids(ob, pbvh, nodes[i], action, area, clip_planes); break; + case PBVH_BMESH: + partialvis_update_bmesh(ob, pbvh, nodes[i], action, area, clip_planes); + break; } } diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 8c9531e5554..fa8252c824d 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -42,7 +42,6 @@ #include "BLI_math.h" #include "BLI_blenlib.h" -#include "BLI_dynstr.h" #include "BLI_linklist.h" #include "BLI_memarena.h" #include "BLI_threads.h" @@ -54,13 +53,9 @@ #include "IMB_imbuf_types.h" #include "DNA_brush_types.h" -#include "DNA_camera_types.h" #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_texture_types.h" #include "BKE_camera.h" #include "BKE_context.h" @@ -77,8 +72,7 @@ #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BKE_global.h" -#include "BKE_deform.h" +#include "BKE_colortools.h" #include "BKE_tessmesh.h" @@ -102,7 +96,6 @@ #include "RNA_enum_types.h" #include "GPU_draw.h" -#include "GPU_extensions.h" #include "IMB_colormanagement.h" @@ -5142,15 +5135,16 @@ static int texture_paint_init(bContext *C, wmOperator *op) return 0; } } - - paint_brush_init_tex(pop->s.brush); - + /* note, if we have no UVs on the derived mesh, then we must return here */ if (pop->mode == PAINT_MODE_3D_PROJECT) { /* initialize all data from the context */ project_state_init(C, OBACT, &pop->ps); - + + /* needed so multiple threads don't try to initialize the brush at once (can leak memory) */ + curvemapping_initialize(pop->ps.brush->curve); + paint_brush_init_tex(pop->ps.brush); pop->ps.source = PROJ_SRC_VIEW; @@ -5168,6 +5162,9 @@ static int texture_paint_init(bContext *C, wmOperator *op) if (pop->ps.dm == NULL) return 0; } + else { + paint_brush_init_tex(pop->s.brush); + } settings->imapaint.flag |= IMAGEPAINT_DRAWING; undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, @@ -5237,8 +5234,6 @@ static void paint_exit(bContext *C, wmOperator *op) if (pop->restore_projection) settings->imapaint.flag &= ~IMAGEPAINT_PROJECT_DISABLE; - paint_brush_exit_tex(pop->s.brush); - settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; imapaint_canvas_free(&pop->s); BKE_brush_painter_free(pop->painter); @@ -5250,6 +5245,8 @@ static void paint_exit(bContext *C, wmOperator *op) project_paint_end(&pop->ps); } else { + paint_brush_exit_tex(pop->s.brush); + /* non projection 3d paint, could move into own function of more needs adding */ if (pop->s.dm_release) pop->s.dm->release(pop->s.dm); diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c new file mode 100644 index 00000000000..c30996f03de --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -0,0 +1,561 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_image_2d.c + * \ingroup bke + */ +//#include <math.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_scene_types.h" + +#include "BKE_brush.h" + +#include "BLI_math.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "RE_shader_ext.h" + + /* Brush Painting for 2D image editor */ + +typedef struct BrushPainterCache { + short enabled; + + int size; /* size override, if 0 uses 2*BKE_brush_size_get(brush) */ + short flt; /* need float imbuf? */ + short texonly; /* no alpha, color or fallof, only texture in imbuf */ + + int lastsize; + float lastalpha; + float lastjitter; + + ImBuf *ibuf; + ImBuf *texibuf; + ImBuf *maskibuf; +} BrushPainterCache; + +struct BrushPainter { + Scene *scene; + Brush *brush; + + float lastmousepos[2]; /* mouse position of last paint call */ + + float accumdistance; /* accumulated distance of brush since last paint op */ + float lastpaintpos[2]; /* position of last paint op */ + float startpaintpos[2]; /* position of first paint */ + + double accumtime; /* accumulated time since last paint op (airbrush) */ + double lasttime; /* time of last update */ + + float lastpressure; + + short firsttouch; /* first paint op */ + + float startsize; + float startalpha; + float startjitter; + float startspacing; + + BrushPainterCache cache; +}; + +BrushPainter *BKE_brush_painter_new(Scene *scene, Brush *brush) +{ + BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter"); + + painter->brush = brush; + painter->scene = scene; + painter->firsttouch = 1; + painter->cache.lastsize = -1; /* force ibuf create in refresh */ + + painter->startsize = BKE_brush_size_get(scene, brush); + painter->startalpha = BKE_brush_alpha_get(scene, brush); + painter->startjitter = brush->jitter; + painter->startspacing = brush->spacing; + + return painter; +} + + +static void brush_pressure_apply(BrushPainter *painter, Brush *brush, float pressure) +{ + if (BKE_brush_use_alpha_pressure(painter->scene, brush)) + BKE_brush_alpha_set(painter->scene, brush, max_ff(0.0f, painter->startalpha * pressure)); + if (BKE_brush_use_size_pressure(painter->scene, brush)) + BKE_brush_size_set(painter->scene, brush, max_ff(1.0f, painter->startsize * pressure)); + if (brush->flag & BRUSH_JITTER_PRESSURE) + brush->jitter = max_ff(0.0f, painter->startjitter * pressure); + if (brush->flag & BRUSH_SPACING_PRESSURE) + brush->spacing = max_ff(1.0f, painter->startspacing * (1.5f - pressure)); +} + + +void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size) +{ + if ((painter->cache.flt != flt) || (painter->cache.size != size) || + ((painter->cache.texonly != texonly) && texonly)) + { + if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); + if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); + painter->cache.ibuf = painter->cache.maskibuf = NULL; + painter->cache.lastsize = -1; /* force ibuf create in refresh */ + } + + if (painter->cache.flt != flt) { + if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); + painter->cache.texibuf = NULL; + painter->cache.lastsize = -1; /* force ibuf create in refresh */ + } + + painter->cache.size = size; + painter->cache.flt = flt; + painter->cache.texonly = texonly; + painter->cache.enabled = 1; +} + +void BKE_brush_painter_free(BrushPainter *painter) +{ + Brush *brush = painter->brush; + + BKE_brush_size_set(painter->scene, brush, painter->startsize); + BKE_brush_alpha_set(painter->scene, brush, painter->startalpha); + brush->jitter = painter->startjitter; + brush->spacing = painter->startspacing; + + if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); + if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); + if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); + MEM_freeN(painter); +} + +static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, + int x, int y, int w, int h, int xt, int yt, + const float pos[2]) +{ + Scene *scene = painter->scene; + Brush *brush = painter->brush; + ImBuf *ibuf, *maskibuf, *texibuf; + float *bf, *mf, *tf, *otf = NULL, xoff, yoff, xy[2], rgba[4]; + unsigned char *b, *m, *t, *ot = NULL; + int dotexold, origx = x, origy = y; + const int radius = BKE_brush_size_get(painter->scene, brush); + + xoff = -radius + 0.5f; + yoff = -radius + 0.5f; + xoff += (int)pos[0] - (int)painter->startpaintpos[0]; + yoff += (int)pos[1] - (int)painter->startpaintpos[1]; + + ibuf = painter->cache.ibuf; + texibuf = painter->cache.texibuf; + maskibuf = painter->cache.maskibuf; + + dotexold = (oldtexibuf != NULL); + + /* not sure if it's actually needed or it's a mistake in coords/sizes + * calculation in brush_painter_fixed_tex_partial_update(), but without this + * limitation memory gets corrupted at fast strokes with quite big spacing (sergey) */ + w = min_ii(w, ibuf->x); + h = min_ii(h, ibuf->y); + + if (painter->cache.flt) { + for (; y < h; y++) { + bf = ibuf->rect_float + (y * ibuf->x + origx) * 4; + tf = texibuf->rect_float + (y * texibuf->x + origx) * 4; + mf = maskibuf->rect_float + (y * maskibuf->x + origx) * 4; + + if (dotexold) + otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + xt) * 4; + + for (x = origx; x < w; x++, bf += 4, mf += 4, tf += 4) { + if (dotexold) { + copy_v3_v3(tf, otf); + tf[3] = otf[3]; + otf += 4; + } + else { + xy[0] = x + xoff; + xy[1] = y + yoff; + + BKE_brush_sample_tex(scene, brush, xy, tf, 0); + } + + bf[0] = tf[0] * mf[0]; + bf[1] = tf[1] * mf[1]; + bf[2] = tf[2] * mf[2]; + bf[3] = tf[3] * mf[3]; + } + } + } + else { + for (; y < h; y++) { + b = (unsigned char *)ibuf->rect + (y * ibuf->x + origx) * 4; + t = (unsigned char *)texibuf->rect + (y * texibuf->x + origx) * 4; + m = (unsigned char *)maskibuf->rect + (y * maskibuf->x + origx) * 4; + + if (dotexold) + ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + xt) * 4; + + for (x = origx; x < w; x++, b += 4, m += 4, t += 4) { + if (dotexold) { + t[0] = ot[0]; + t[1] = ot[1]; + t[2] = ot[2]; + t[3] = ot[3]; + ot += 4; + } + else { + xy[0] = x + xoff; + xy[1] = y + yoff; + + BKE_brush_sample_tex(scene, brush, xy, rgba, 0); + rgba_float_to_uchar(t, rgba); + } + + b[0] = t[0] * m[0] / 255; + b[1] = t[1] * m[1] / 255; + b[2] = t[2] * m[2] / 255; + b[3] = t[3] * m[3] / 255; + } + } + } +} + +static void brush_painter_fixed_tex_partial_update(BrushPainter *painter, const float pos[2]) +{ + const Scene *scene = painter->scene; + Brush *brush = painter->brush; + BrushPainterCache *cache = &painter->cache; + ImBuf *oldtexibuf, *ibuf; + int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2; + const int diameter = 2 * BKE_brush_size_get(scene, brush); + + imbflag = (cache->flt) ? IB_rectfloat : IB_rect; + if (!cache->ibuf) + cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag); + ibuf = cache->ibuf; + + oldtexibuf = cache->texibuf; + cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag); + + if (oldtexibuf) { + srcx = srcy = 0; + destx = (int)painter->lastpaintpos[0] - (int)pos[0]; + desty = (int)painter->lastpaintpos[1] - (int)pos[1]; + w = oldtexibuf->x; + h = oldtexibuf->y; + + IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h); + } + else { + srcx = srcy = 0; + destx = desty = 0; + w = h = 0; + } + + x1 = destx; + y1 = desty; + x2 = destx + w; + y2 = desty + h; + + /* blend existing texture in new position */ + if ((x1 < x2) && (y1 < y2)) + brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos); + + if (oldtexibuf) + IMB_freeImBuf(oldtexibuf); + + /* sample texture in new areas */ + if ((0 < x1) && (0 < ibuf->y)) + brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos); + if ((x2 < ibuf->x) && (0 < ibuf->y)) + brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos); + if ((x1 < x2) && (0 < y1)) + brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos); + if ((x1 < x2) && (y2 < ibuf->y)) + brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos); +} + +static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction) +{ + const Scene *scene = painter->scene; + Brush *brush = painter->brush; + BrushPainterCache *cache = &painter->cache; + MTex *mtex = &brush->mtex; + int size; + short flt; + const int diameter = 2 * BKE_brush_size_get(scene, brush); + const float alpha = BKE_brush_alpha_get(scene, brush); + + if (diameter != cache->lastsize || + alpha != cache->lastalpha || + brush->jitter != cache->lastjitter) + { + if (cache->ibuf) { + IMB_freeImBuf(cache->ibuf); + cache->ibuf = NULL; + } + if (cache->maskibuf) { + IMB_freeImBuf(cache->maskibuf); + cache->maskibuf = NULL; + } + + flt = cache->flt; + size = (cache->size) ? cache->size : diameter; + + if (brush->flag & BRUSH_FIXED_TEX) { + BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction); + brush_painter_fixed_tex_partial_update(painter, pos); + } + else + BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction); + + cache->lastsize = diameter; + cache->lastalpha = alpha; + cache->lastjitter = brush->jitter; + } + else if ((brush->flag & BRUSH_FIXED_TEX) && mtex && mtex->tex) { + int dx = (int)painter->lastpaintpos[0] - (int)pos[0]; + int dy = (int)painter->lastpaintpos[1] - (int)pos[1]; + + if ((dx != 0) || (dy != 0)) + brush_painter_fixed_tex_partial_update(painter, pos); + } +} + +void BKE_brush_painter_break_stroke(BrushPainter *painter) +{ + painter->firsttouch = 1; +} + + +int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float pos[2], double time, float pressure, + void *user, int use_color_correction) +{ + Scene *scene = painter->scene; + Brush *brush = painter->brush; + int totpaintops = 0; + + if (pressure == 0.0f) { + if (painter->lastpressure) // XXX - hack, operator misses + pressure = painter->lastpressure; + else + pressure = 1.0f; /* zero pressure == not using tablet */ + } + if (painter->firsttouch) { + /* paint exactly once on first touch */ + painter->startpaintpos[0] = pos[0]; + painter->startpaintpos[1] = pos[1]; + + brush_pressure_apply(painter, brush, pressure); + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, pos, use_color_correction); + totpaintops += func(user, painter->cache.ibuf, pos, pos); + + painter->lasttime = time; + painter->firsttouch = 0; + painter->lastpaintpos[0] = pos[0]; + painter->lastpaintpos[1] = pos[1]; + } +#if 0 + else if (painter->brush->flag & BRUSH_AIRBRUSH) { + float spacing, step, paintpos[2], dmousepos[2], len; + double starttime, curtime = time; + + /* compute brush spacing adapted to brush size */ + spacing = brush->rate; //radius*brush->spacing*0.01f; + + /* setup starting time, direction vector and accumulated time */ + starttime = painter->accumtime; + sub_v2_v2v2(dmousepos, pos, painter->lastmousepos); + len = normalize_v2(dmousepos); + painter->accumtime += curtime - painter->lasttime; + + /* do paint op over unpainted time distance */ + while (painter->accumtime >= spacing) { + step = (spacing - starttime) * len; + paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step; + paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step; + + if (painter->cache.enabled) + brush_painter_refresh_cache(painter); + totpaintops += func(user, painter->cache.ibuf, + painter->lastpaintpos, paintpos); + + painter->lastpaintpos[0] = paintpos[0]; + painter->lastpaintpos[1] = paintpos[1]; + painter->accumtime -= spacing; + starttime -= spacing; + } + + painter->lasttime = curtime; + } +#endif + else { + float startdistance, spacing, step, paintpos[2], dmousepos[2], finalpos[2]; + float t, len, press; + const int radius = BKE_brush_size_get(scene, brush); + + /* compute brush spacing adapted to brush radius, spacing may depend + * on pressure, so update it */ + brush_pressure_apply(painter, brush, painter->lastpressure); + spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f; + + /* setup starting distance, direction vector and accumulated distance */ + startdistance = painter->accumdistance; + sub_v2_v2v2(dmousepos, pos, painter->lastmousepos); + len = normalize_v2(dmousepos); + painter->accumdistance += len; + + if (brush->flag & BRUSH_SPACE) { + /* do paint op over unpainted distance */ + while ((len > 0.0f) && (painter->accumdistance >= spacing)) { + step = spacing - startdistance; + paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step; + paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step; + + t = step / len; + press = (1.0f - t) * painter->lastpressure + t * pressure; + brush_pressure_apply(painter, brush, press); + spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f; + + BKE_brush_jitter_pos(scene, brush, paintpos, finalpos); + + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, finalpos, use_color_correction); + + totpaintops += + func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos); + + painter->lastpaintpos[0] = paintpos[0]; + painter->lastpaintpos[1] = paintpos[1]; + painter->accumdistance -= spacing; + startdistance -= spacing; + } + } + else { + BKE_brush_jitter_pos(scene, brush, pos, finalpos); + + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, finalpos, use_color_correction); + + totpaintops += func(user, painter->cache.ibuf, pos, finalpos); + + painter->lastpaintpos[0] = pos[0]; + painter->lastpaintpos[1] = pos[1]; + painter->accumdistance = 0; + } + + /* do airbrush paint ops, based on the number of paint ops left over + * from regular painting. this is a temporary solution until we have + * accurate time stamps for mouse move events */ + if (brush->flag & BRUSH_AIRBRUSH) { + double curtime = time; + double painttime = brush->rate * totpaintops; + + painter->accumtime += curtime - painter->lasttime; + if (painter->accumtime <= painttime) + painter->accumtime = 0.0; + else + painter->accumtime -= painttime; + + while (painter->accumtime >= (double)brush->rate) { + brush_pressure_apply(painter, brush, pressure); + + BKE_brush_jitter_pos(scene, brush, pos, finalpos); + + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, finalpos, use_color_correction); + + totpaintops += + func(user, painter->cache.ibuf, painter->lastmousepos, finalpos); + painter->accumtime -= (double)brush->rate; + } + + painter->lasttime = curtime; + } + } + + painter->lastmousepos[0] = pos[0]; + painter->lastmousepos[1] = pos[1]; + painter->lastpressure = pressure; + + BKE_brush_alpha_set(scene, brush, painter->startalpha); + BKE_brush_size_set(scene, brush, painter->startsize); + brush->jitter = painter->startjitter; + brush->spacing = painter->startspacing; + + return totpaintops; +} + + +/* TODO: should probably be unified with BrushPainter stuff? */ +unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side) +{ + unsigned int *texcache = NULL; + MTex *mtex = &br->mtex; + TexResult texres = {0}; + int hasrgb, ix, iy; + int side = half_side * 2; + + if (mtex->tex) { + float x, y, step = 2.0 / side, co[3]; + + texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache"); + + /*do normalized cannonical view coords for texture*/ + for (y = -1.0, iy = 0; iy < side; iy++, y += step) { + for (x = -1.0, ix = 0; ix < side; ix++, x += step) { + co[0] = x; + co[1] = y; + co[2] = 0.0f; + + /* This is copied from displace modifier code */ + hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres); + + /* if the texture gave an RGB value, we assume it didn't give a valid + * intensity, so calculate one (formula from do_material_tex). + * if the texture didn't give an RGB value, copy the intensity across + */ + if (hasrgb & TEX_RGB) + texres.tin = rgb_to_grayscale(&texres.tr); + + ((char *)texcache)[(iy * side + ix) * 4] = + ((char *)texcache)[(iy * side + ix) * 4 + 1] = + ((char *)texcache)[(iy * side + ix) * 4 + 2] = + ((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(texres.tin * 255.0f); + } + } + } + + return texcache; +} + diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 9fe7fc1d3ac..3cf67667f39 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -96,7 +96,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) pbvh = dm->getPBVH(ob, dm); ob->sculpt->pbvh = pbvh; - BLI_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); sculpt_undo_push_begin("Mask flood fill"); @@ -105,12 +105,12 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK); - BLI_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) { + BKE_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) { mask_flood_fill_set_elem(vi.mask, mode, value); - } BLI_pbvh_vertex_iter_end; + } BKE_pbvh_vertex_iter_end; - BLI_pbvh_node_mark_update(nodes[i]); - if (BLI_pbvh_type(pbvh) == PBVH_GRIDS) + BKE_pbvh_node_mark_update(nodes[i]); + if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); } diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 10b9f26dbcd..9e702c16e2f 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -648,6 +648,18 @@ void ED_keymap_paint(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "PAINT_OT_mask_flood_fill", IKEY, KM_PRESS, KM_CTRL, 0); RNA_enum_set(kmi->ptr, "mode", PAINT_MASK_INVERT); + /* Toggle dynamic topology */ + WM_keymap_add_item(keymap, "SCULPT_OT_dynamic_topology_toggle", DKEY, KM_PRESS, KM_CTRL, 0); + + /* Dynamic-topology detail size + * + * This should be improved further, perhaps by showing a triangle + * grid rather than brush alpha */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", DKEY, KM_PRESS, KM_SHIFT, 0); + set_brush_rc_props(kmi->ptr, "sculpt", "detail_size", NULL, 0); + RNA_string_set(kmi->ptr, "data_path_primary", + "tool_settings.sculpt.detail_size"); + /* multires switch */ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", PAGEUPKEY, KM_PRESS, 0, 0); RNA_int_set(kmi->ptr, "level", 1); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 9ebeb61a7bb..2f4115dcd94 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -416,6 +416,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) if (!stroke->stroke_started) { copy_v2_v2(stroke->last_mouse_position, sample_average.mouse); stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse); + BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */ if (stroke->stroke_started) { stroke->smooth_stroke_cursor = diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 359486a4a8d..08c26aaa755 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -372,31 +372,22 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active); if (defgroup) { - bDeformGroup *curdef; int mirrdef; char name[MAXBONENAME]; flip_side_name(name, defgroup->name, FALSE); - - if (strcmp(name, defgroup->name) != 0) { - for (curdef = ob->defbase.first, mirrdef = 0; curdef; curdef = curdef->next, mirrdef++) { - if (!strcmp(curdef->name, name)) { - break; - } - } - - if (curdef == NULL) { - int olddef = ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */ - curdef = ED_vgroup_add_name(ob, name); - ob->actdef = olddef; - } - - /* curdef should never be NULL unless this is - * a lamp and ED_vgroup_add_name fails */ - if (curdef) { - return mirrdef; + mirrdef = defgroup_name_index(ob, name); + if (mirrdef == -1) { + int olddef = ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */ + if (ED_vgroup_add_name(ob, name)) { + mirrdef = BLI_countlist(&ob->defbase) - 1; } + ob->actdef = olddef; } + + /* curdef should never be NULL unless this is + * a lamp and ED_vgroup_add_name fails */ + return mirrdef; } return -1; @@ -414,7 +405,7 @@ static void free_vpaint_prev(VPaint *vp) static void free_wpaint_prev(VPaint *vp) { if (vp->wpaint_prev) { - MEM_freeN(vp->wpaint_prev); + BKE_defvert_array_free(vp->wpaint_prev, vp->tot); vp->wpaint_prev = NULL; vp->tot = 0; } @@ -441,7 +432,7 @@ static void copy_wpaint_prev(VPaint *wp, MDeformVert *dverts, int dcount) wp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev"); wp->tot = dcount; - copy_dverts(wp->wpaint_prev, dverts, dcount); + BKE_defvert_array_copy(wp->wpaint_prev, dverts, dcount); } } @@ -868,7 +859,10 @@ static float calc_vp_strength_dl(VPaint *vp, ViewContext *vc, const float co[3], { float vertco[2]; - if (ED_view3d_project_float_global(vc->ar, co, vertco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object(vc->ar, + co, vertco, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { float delta[2]; float dist_squared; @@ -1037,15 +1031,15 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) view3d_operator_needs_opengl(C); if (use_vert_sel) { - if (ED_mesh_pick_vert(C, me, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) { + if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) { v_idx_best = index; } } else { - if (ED_mesh_pick_face_vert(C, me, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { v_idx_best = index; } - else if (ED_mesh_pick_face(C, me, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */ BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations"); } @@ -1126,13 +1120,13 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA view3d_operator_needs_opengl(C); if (use_vert_sel) { - if (ED_mesh_pick_vert(C, me, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) { + if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) { MDeformVert *dvert = &me->dvert[index]; found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); } } else { - if (ED_mesh_pick_face(C, me, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { MPoly *mp = &me->mpoly[index]; unsigned int fidx = mp->totloop - 1; @@ -2058,32 +2052,28 @@ struct WPaintData { int vgroup_mirror; DMCoNo *vertexcosnos; float wpimat[3][3]; - + /* variables for auto normalize */ const char *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */ const char *lock_flags; int defbase_tot; }; -static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2])) +/* ensure we have data on wpaint start, add if needed */ +static int wpaint_ensure_data(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - struct PaintStroke *stroke = op->customdata; - ToolSettings *ts = scene->toolsettings; - VPaint *wp = ts->wpaint; Object *ob = CTX_data_active_object(C); - struct WPaintData *wpd; - Mesh *me; + Mesh *me = BKE_mesh_from_object(ob); - float mat[4][4], imat[4][4]; - if (scene->obedit) { return FALSE; } - - me = BKE_mesh_from_object(ob); - if (me == NULL || me->totpoly == 0) return OPERATOR_PASS_THROUGH; - + + if (me == NULL || me->totpoly == 0) { + return FALSE; + } + /* if nothing was added yet, we make dverts and a vertex deform group */ if (!me->dvert) { ED_vgroup_data_create(&me->id); @@ -2122,6 +2112,25 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNU return FALSE; } + return TRUE; +} + +static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2])) +{ + Scene *scene = CTX_data_scene(C); + struct PaintStroke *stroke = op->customdata; + ToolSettings *ts = scene->toolsettings; + VPaint *wp = ts->wpaint; + Object *ob = CTX_data_active_object(C); + Mesh *me = BKE_mesh_from_object(ob); + struct WPaintData *wpd; + + float mat[4][4], imat[4][4]; + + if (wpaint_ensure_data(C, op) == FALSE) { + return FALSE; + } + { /* check if we are attempting to paint onto a locked vertex group, * and other options disallow it from doing anything useful */ @@ -2184,7 +2193,15 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P unsigned int index, totindex; float alpha; float mval[2]; - int use_vert_sel; + bool use_vert_sel; + bool use_face_sel; + bool use_depth; + + MDeformWeight *(*dw_func)(MDeformVert *, const int) = + (brush->vertexpaint_tool == PAINT_BLEND_BLUR) ? + ((wp->flag & VP_ONLYVGROUP) ? + (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index : + defvert_verify_index) : NULL; const float pressure = RNA_float_get(itemptr, "pressure"); const float brush_size_pressure = BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f); @@ -2201,7 +2218,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P ED_region_tag_redraw(CTX_wm_region(C)); return; } - + vc = &wpd->vc; ob = vc->obact; me = ob->data; @@ -2242,31 +2259,38 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P swap_m4m4(wpd->vc.rv3d->persmat, mat); use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + use_depth = (vc->v3d->flag & V3D_ZBUF_SELECT); /* which faces are involved */ - if (wp->flag & VP_AREA) { - /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */ - me->editflag &= ~ME_EDIT_PAINT_VERT_SEL; - totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); - me->editflag |= use_vert_sel ? ME_EDIT_PAINT_VERT_SEL : 0; - } - else { - indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]); - if (indexar[0]) totindex = 1; - else totindex = 0; - } + if (use_depth) { + if (wp->flag & VP_AREA) { + /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */ + me->editflag &= ~ME_EDIT_PAINT_VERT_SEL; + totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); + me->editflag |= use_vert_sel ? ME_EDIT_PAINT_VERT_SEL : 0; + } + else { + indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]); + if (indexar[0]) totindex = 1; + else totindex = 0; + } - if ((me->editflag & ME_EDIT_PAINT_FACE_SEL) && me->mpoly) { - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1); - - if ((mpoly->flag & ME_FACE_SEL) == 0) { - indexar[index] = 0; + if (use_face_sel && me->mpoly) { + for (index = 0; index < totindex; index++) { + if (indexar[index] && indexar[index] <= me->totpoly) { + MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1); + + if ((mpoly->flag & ME_FACE_SEL) == 0) { + indexar[index] = 0; + } } } } } + else { + indexar = NULL; + } /* make sure each vertex gets treated only once */ /* and calculate filter weight */ @@ -2275,80 +2299,121 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P paintweight = 0.0f; else paintweight = BKE_brush_weight_get(scene, brush); - - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = me->mpoly + (indexar[index] - 1); - MLoop *ml = me->mloop + mpoly->loopstart; - int i; - if (use_vert_sel) { - for (i = 0; i < mpoly->totloop; i++, ml++) { - me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT); +#define WP_BLUR_ACCUM(v_idx_var) \ + { \ + const unsigned int vidx = v_idx_var; \ + const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure); \ + if (fac > 0.0f) { \ + MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \ + paintweight += dw ? (dw->weight * fac) : 0.0f; \ + totw += fac; \ + } \ + } (void)0 + + + if (use_depth) { + for (index = 0; index < totindex; index++) { + if (indexar[index] && indexar[index] <= me->totpoly) { + MPoly *mpoly = me->mpoly + (indexar[index] - 1); + MLoop *ml = me->mloop + mpoly->loopstart; + int i; + + if (use_vert_sel) { + for (i = 0; i < mpoly->totloop; i++, ml++) { + me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT); + } } - } - else { - for (i = 0; i < mpoly->totloop; i++, ml++) { - me->dvert[ml->v].flag = 1; + else { + for (i = 0; i < mpoly->totloop; i++, ml++) { + me->dvert[ml->v].flag = 1; + } } - } - - if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { - MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int); - - if (wp->flag & VP_ONLYVGROUP) - dw_func = (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index; - else - dw_func = defvert_verify_index; - - ml = me->mloop + mpoly->loopstart; - for (i = 0; i < mpoly->totloop; i++, ml++) { - unsigned int vidx = ml->v; - const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure); - if (fac > 0.0f) { - dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); - paintweight += dw ? (dw->weight * fac) : 0.0f; - totw += fac; + + if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { + ml = me->mloop + mpoly->loopstart; + for (i = 0; i < mpoly->totloop; i++, ml++) { + WP_BLUR_ACCUM(ml->v); } } } } } - + else { + const unsigned int totvert = me->totvert; + unsigned int i; + + /* in the case of face selection we need to flush */ + if (use_vert_sel || use_face_sel) { + for (i = 0; i < totvert; i++) { + me->dvert[i].flag = me->mvert[i].flag & SELECT; + } + } + else { + for (i = 0; i < totvert; i++) { + me->dvert[i].flag = SELECT; + } + } + + if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { + for (i = 0; i < totvert; i++) { + WP_BLUR_ACCUM(i); + } + } + } + +#undef WP_BLUR_ACCUM + + if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { paintweight /= totw; } - for (index = 0; index < totindex; index++) { +#define WP_PAINT(v_idx_var) \ + { \ + unsigned int vidx = v_idx_var; \ + if (me->dvert[vidx].flag) { \ + alpha = calc_vp_alpha_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \ + mval, brush_size_pressure, brush_alpha_pressure); \ + if (alpha) { \ + do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \ + } \ + me->dvert[vidx].flag = 0; \ + } \ + } (void)0 + + if (use_depth) { + for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = me->mpoly + (indexar[index] - 1); - MLoop *ml = me->mloop + mpoly->loopstart; - int i; - - for (i = 0; i < mpoly->totloop; i++, ml++) { - unsigned int vidx = ml->v; - - if (me->dvert[vidx].flag) { - alpha = calc_vp_alpha_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], - mval, brush_size_pressure, brush_alpha_pressure); - if (alpha) { - do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); - } - me->dvert[vidx].flag = 0; + if (indexar[index] && indexar[index] <= me->totpoly) { + MPoly *mpoly = me->mpoly + (indexar[index] - 1); + MLoop *ml = me->mloop + mpoly->loopstart; + int i; + + for (i = 0; i < mpoly->totloop; i++, ml++) { + WP_PAINT(ml->v); } } } } + else { + const unsigned int totvert = me->totvert; + unsigned int i; + + for (i = 0; i < totvert; i++) { + WP_PAINT(i); + } + } +#undef WP_PAINT /* *** free wpi members */ MEM_freeN((void *)wpi.defbase_sel); - /* *** don't freeing wpi members */ + /* *** done freeing wpi members */ swap_m4m4(vc->rv3d->persmat, mat); - + DAG_id_tag_update(ob->data, 0); ED_region_tag_redraw(vc->ar); } @@ -2442,7 +2507,7 @@ void PAINT_OT_weight_paint(wmOperatorType *ot) RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); } -static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op)) +static int weight_paint_set_exec(bContext *C, wmOperator *op) { struct Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); @@ -2450,6 +2515,10 @@ static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op)) Brush *brush = paint_brush(&ts->wpaint->paint); float vgroup_weight = BKE_brush_weight_get(scene, brush); + if (wpaint_ensure_data(C, op) == FALSE) { + return OPERATOR_CANCELLED; + } + wpaint_fill(scene->toolsettings->wpaint, obact, vgroup_weight); ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */ return OPERATOR_FINISHED; @@ -2992,9 +3061,9 @@ static void gradientVert__mapFunc(void *userData, int index, const float co[3], * the screen coords of the verts need to be cached because * updating the mesh may move them about (entering feedback loop) */ if (grad_data->is_init) { - if (ED_view3d_project_float_global(grad_data->ar, + if (ED_view3d_project_float_object(grad_data->ar, co, vs->sco, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { /* ok */ MDeformVert *dv = &me->dvert[index]; @@ -3022,11 +3091,9 @@ static void gradientVert__mapFunc(void *userData, int index, const float co[3], if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) { alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end); } - else if (grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL) { - alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; - } else { - BLI_assert(0); + BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL); + alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; } /* no need to clamp 'alpha' yet */ @@ -3082,7 +3149,7 @@ static int paint_weight_gradient_modal(bContext *C, wmOperator *op, wmEvent *eve VPaint *wp = ts->wpaint; Object *ob = CTX_data_active_object(C); Mesh *me = ob->data; - copy_dverts(me->dvert, wp->wpaint_prev, me->totvert); + BKE_defvert_array_copy(me->dvert, wp->wpaint_prev, me->totvert); free_wpaint_prev(wp); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); @@ -3159,7 +3226,13 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, wmEvent *event) { - int ret = WM_gesture_straightline_invoke(C, op, event); + int ret; + + if (wpaint_ensure_data(C, op) == FALSE) { + return OPERATOR_CANCELLED; + } + + ret = WM_gesture_straightline_invoke(C, op, event); if (ret & OPERATOR_RUNNING_MODAL) { struct ARegion *ar = CTX_wm_region(C); if (ar->regiontype == RGN_TYPE_WINDOW) { diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 8325b47beab..54ae2ebf588 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -65,6 +65,7 @@ #include "BKE_report.h" #include "BKE_lattice.h" /* for armature_deform_verts */ #include "BKE_node.h" +#include "BKE_object.h" #include "BKE_subsurf.h" #include "BIF_glutil.h" @@ -86,6 +87,8 @@ #include "GPU_buffers.h" +#include "bmesh.h" + #include <math.h> #include <stdlib.h> #include <string.h> @@ -98,8 +101,13 @@ void ED_sculpt_force_update(bContext *C) { Object *ob = CTX_data_active_object(C); - if (ob && (ob->mode & OB_MODE_SCULPT)) + if (ob && (ob->mode & OB_MODE_SCULPT)) { multires_force_update(ob); + + /* Set reorder=false so that saving the file doesn't reorder + * the BMesh's elements */ + sculptsession_bm_to_me(ob, FALSE); + } } float *ED_sculpt_get_last_stroke(struct Object *ob) @@ -172,7 +180,8 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) Mesh *me = (Mesh *)ob->data; MultiresModifierData *mmd = sculpt_multires_active(scene, ob); - if (mmd) return 0; + if (mmd || ob->sculpt->bm) + return 0; /* non-locked shape keys could be handled in the same way as deformed mesh */ if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr) @@ -281,12 +290,130 @@ typedef struct StrokeCache { rcti previous_r; /* previous redraw rectangle */ } StrokeCache; +/************** Access to original unmodified vertex data *************/ + +typedef struct { + BMLog *bm_log; + + SculptUndoNode *unode; + float (*coords)[3]; + short (*normals)[3]; + float *vmasks; + + /* Original coordinate, normal, and mask */ + const float *co; + float mask; + short no[3]; +} SculptOrigVertData; + + +/* Initialize a SculptOrigVertData for accessing original vertex data; + * handles BMesh, mesh, and multires */ +static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data, + Object *ob, + SculptUndoNode *unode) +{ + SculptSession *ss = ob->sculpt; + BMesh *bm = ss->bm; + + memset(data, 0, sizeof(*data)); + data->unode = unode; + + if (bm) { + data->bm_log = ss->bm_log; + } + else { + data->coords = data->unode->co; + data->normals = data->unode->no; + data->vmasks = data->unode->mask; + } +} + +/* Initialize a SculptOrigVertData for accessing original vertex data; + * handles BMesh, mesh, and multires */ +static void sculpt_orig_vert_data_init(SculptOrigVertData *data, + Object *ob, + PBVHNode *node) +{ + SculptUndoNode *unode; + unode = sculpt_undo_push_node(ob, node, SCULPT_UNDO_COORDS); + sculpt_orig_vert_data_unode_init(data, ob, unode); + +} + +/* Update a SculptOrigVertData for a particular vertex from the PBVH + * iterator */ +static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data, + PBVHVertexIter *iter) +{ + if (orig_data->unode->type == SCULPT_UNDO_COORDS) { + if (orig_data->coords) { + orig_data->co = orig_data->coords[iter->i]; + } + else { + orig_data->co = BM_log_original_vert_co(orig_data->bm_log, iter->bm_vert); + } + + if (orig_data->normals) { + copy_v3_v3_short(orig_data->no, orig_data->normals[iter->i]); + } + else { + /* TODO: log doesn't store normals yet */ + normal_float_to_short_v3(orig_data->no, iter->bm_vert->no); + } + } + else if (orig_data->unode->type == SCULPT_UNDO_MASK) { + if (orig_data->vmasks) { + orig_data->mask = orig_data->vmasks[iter->i]; + } + else { + orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert); + } + } +} + +/**********************************************************************/ + +/* Returns true if the stroke will use dynamic topology, false + otherwise. + + Factors: some brushes like grab cannot do dynamic topology. + Others, like smooth, are better without. Same goes for alt- + key smoothing. */ +static int sculpt_stroke_dynamic_topology(const SculptSession *ss, + const Brush *brush) +{ + return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) && + + (!ss->cache || (!ss->cache->alt_smooth)) && + + /* Requires mesh restore, which doesn't work with + * dynamic-topology */ + !(brush->flag & BRUSH_ANCHORED) && + !(brush->flag & BRUSH_RESTORE_MESH) && + + (!ELEM6(brush->sculpt_tool, + /* These brushes, as currently coded, cannot + * support dynamic topology */ + SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_LAYER, + + /* These brushes could handle dynamic topology, + * but user feedback indicates it's better not + * to */ + SCULPT_TOOL_SMOOTH, + SCULPT_TOOL_MASK))); +} /*** paint mesh ***/ -static void paint_mesh_restore_co(Sculpt *sd, SculptSession *ss) +static void paint_mesh_restore_co(Sculpt *sd, Object *ob) { + SculptSession *ss = ob->sculpt; StrokeCache *cache = ss->cache; + const Brush *brush = paint_brush(&sd->paint); int i; PBVHNode **nodes; @@ -296,31 +423,38 @@ static void paint_mesh_restore_co(Sculpt *sd, SculptSession *ss) (void)sd; /* quied unused warning */ #endif - BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n = 0; n < totnode; n++) { SculptUndoNode *unode; - - unode = sculpt_undo_get_node(nodes[n]); + SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ? + SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS); + + unode = sculpt_undo_push_node(ob, nodes[n], type); if (unode) { PBVHVertexIter vd; + SculptOrigVertData orig_data; - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + sculpt_orig_vert_data_unode_init(&orig_data, ob, unode); + + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - if (unode->type == SCULPT_UNDO_COORDS) { - copy_v3_v3(vd.co, unode->co[vd.i]); - if (vd.no) copy_v3_v3_short(vd.no, unode->no[vd.i]); - else normal_short_to_float_v3(vd.fno, unode->no[vd.i]); + sculpt_orig_vert_data_update(&orig_data, &vd); + + if (orig_data.unode->type == SCULPT_UNDO_COORDS) { + copy_v3_v3(vd.co, orig_data.co); + if (vd.no) copy_v3_v3_short(vd.no, orig_data.no); + else normal_short_to_float_v3(vd.fno, orig_data.no); } - else if (unode->type == SCULPT_UNDO_MASK) { - *vd.mask = unode->mask[vd.i]; + else if (orig_data.unode->type == SCULPT_UNDO_MASK) { + *vd.mask = orig_data.mask; } if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; - BLI_pbvh_node_mark_update(nodes[n]); + BKE_pbvh_node_mark_update(nodes[n]); } } @@ -347,7 +481,7 @@ static int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, if (!pbvh) return 0; - BLI_pbvh_redraw_BB(pbvh, bb_min, bb_max); + BKE_pbvh_redraw_BB(pbvh, bb_min, bb_max); /* convert 3D bounding box to screen space */ if (!paint_convert_bb_to_rect(rect, @@ -387,7 +521,7 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar, /* clear redraw flag from nodes */ if (pbvh) - BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL); + BKE_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL); } /************************ Brush Testing *******************/ @@ -405,7 +539,7 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) test->dist = 0.0f; /* just for initialize */ } -static int sculpt_brush_test(SculptBrushTest *test, float co[3]) +static int sculpt_brush_test(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); @@ -418,7 +552,7 @@ static int sculpt_brush_test(SculptBrushTest *test, float co[3]) } } -static int sculpt_brush_test_sq(SculptBrushTest *test, float co[3]) +static int sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); @@ -734,7 +868,8 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather) } /* Return a multiplier for brush strength on a particular vertex. */ -static float tex_strength(SculptSession *ss, Brush *br, float point[3], +static float tex_strength(SculptSession *ss, Brush *br, + const float point[3], const float len, const float sculpt_normal[3], const short vno[3], @@ -871,9 +1006,9 @@ static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v) int i; if (data->original) - BLI_pbvh_node_get_original_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_original_BB(node, bb_min, bb_max); else - BLI_pbvh_node_get_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_BB(node, bb_min, bb_max); for (i = 0; i < 3; ++i) { if (bb_min[i] > center[i]) @@ -926,6 +1061,11 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod original = (paint_brush(&sd->paint)->sculpt_tool == SCULPT_TOOL_GRAB ? TRUE : ss->cache->original); + /* In general the original coords are not available with dynamic + * topology */ + if (ss->bm) + original = FALSE; + (void)sd; /* unused w/o openmp */ zero_v3(an); @@ -942,7 +1082,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod sculpt_brush_test_init(ss, &test); if (original) { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, unode->co[vd.i])) { float fno[3]; @@ -951,10 +1091,10 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno); } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } else { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, vd.co)) { if (vd.no) { @@ -968,7 +1108,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } #pragma omp critical @@ -1210,6 +1350,71 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert) return vmask[vert]; } +/* Same logic as neighbor_average(), but for bmesh rather than mesh */ +static void bmesh_neighbor_average(float avg[3], BMVert *v) +{ + const int vfcount = BM_vert_face_count(v); + + zero_v3(avg); + + /* Don't modify corner vertices */ + if (vfcount > 1) { + BMIter liter; + BMLoop *l; + int i, total = 0; + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + BMVert *adj_v[3] = {l->prev->v, v, l->next->v}; + + for (i = 0; i < 3; i++) { + if (vfcount != 2 || BM_vert_face_count(adj_v[i]) <= 2) { + add_v3_v3(avg, adj_v[i]->co); + total++; + } + } + } + + if (total > 0) { + mul_v3_fl(avg, 1.0f / total); + return; + } + } + + copy_v3_v3(avg, v->co); +} + +/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */ +static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v) +{ + BMIter liter; + BMLoop *l; + float avg = 0; + int i, total = 0; + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + BMVert *adj_v[3] = {l->prev->v, v, l->next->v}; + + for (i = 0; i < 3; i++) { + BMVert *v2 = adj_v[i]; + float *vmask = CustomData_bmesh_get(&bm->vdata, + v2->head.data, + CD_PAINT_MASK); + avg += (*vmask); + total++; + } + } + + if (total > 0) { + return avg / (float)total; + } + else { + float *vmask = CustomData_bmesh_get(&bm->vdata, + v->head.data, + CD_PAINT_MASK); + return (*vmask); + } +} + static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask) { Brush *brush = paint_brush(&sd->paint); @@ -1220,7 +1425,7 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, @@ -1248,7 +1453,48 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; +} + +static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask) +{ + Brush *brush = paint_brush(&sd->paint); + PBVHVertexIter vd; + SculptBrushTest test; + + CLAMP(bstrength, 0.0f, 1.0f); + + sculpt_brush_test_init(ss, &test); + + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + { + if (sculpt_brush_test(&test, vd.co)) { + const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, + ss->cache->view_normal, vd.no, vd.fno, + smooth_mask ? 0 : *vd.mask); + if (smooth_mask) { + float val = bmesh_neighbor_average_mask(ss->bm, vd.bm_vert) - *vd.mask; + val *= fade * bstrength; + *vd.mask += val; + CLAMP(*vd.mask, 0, 1); + } + else { + float avg[3], val[3]; + + bmesh_neighbor_average(avg, vd.bm_vert); + sub_v3_v3v3(val, avg, vd.co); + mul_v3_fl(val, fade); + + add_v3_v3(val, vd.co); + + sculpt_clip(sd, ss, vd.co, val); + } + + if (vd.mvert) + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; } static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, @@ -1269,9 +1515,9 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no CLAMP(bstrength, 0.0f, 1.0f); - BLI_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid, + BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid, NULL, &gridsize, &griddata, &gridadj); - BLI_pbvh_get_grid_key(ss->pbvh, &key); + BKE_pbvh_get_grid_key(ss->pbvh, &key); thread_num = 0; #ifdef _OPENMP @@ -1405,7 +1651,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, SculptSession *ss = ob->sculpt; const int max_iterations = 4; const float fract = 1.0f / max_iterations; - PBVHType type = BLI_pbvh_type(ss->pbvh); + PBVHType type = BKE_pbvh_type(ss->pbvh); int iteration, n, count; float last; @@ -1433,6 +1679,9 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, do_mesh_smooth_brush(sd, ss, nodes[n], strength, smooth_mask); break; + case PBVH_BMESH: + do_bmesh_smooth_brush(sd, ss, nodes[n], strength, smooth_mask); + break; } } @@ -1462,7 +1711,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { float fade = tex_strength(ss, brush, vd.co, test.dist, @@ -1474,7 +1723,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } } @@ -1514,11 +1763,11 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { /* offset vertex */ @@ -1532,7 +1781,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1570,11 +1819,11 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { /* offset vertex */ @@ -1597,7 +1846,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1614,11 +1863,11 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, @@ -1633,7 +1882,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1659,26 +1908,27 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; - SculptUndoNode *unode; SculptBrushTest test; - float (*origco)[3]; - short (*origno)[3]; + SculptOrigVertData orig_data; float (*proxy)[3]; - unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); - origco = unode->co; - origno = unode->no; + sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]); - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, origco[vd.i])) { - const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist, - ss->cache->sculpt_normal_symm, origno[vd.i], - NULL, vd.mask ? *vd.mask : 0.0f); + sculpt_orig_vert_data_update(&orig_data, &vd); + + if (sculpt_brush_test(&test, orig_data.co)) { + const float fade = bstrength * tex_strength(ss, brush, + orig_data.co, + test.dist, + ss->cache->sculpt_normal_symm, + orig_data.no, + NULL, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -1686,7 +1936,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1710,11 +1960,11 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, @@ -1727,7 +1977,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1759,11 +2009,11 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, @@ -1776,7 +2026,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1797,26 +2047,27 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; - SculptUndoNode *unode; SculptBrushTest test; - float (*origco)[3]; - short (*origno)[3]; + SculptOrigVertData orig_data; float (*proxy)[3]; - unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); - origco = unode->co; - origno = unode->no; + sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]); - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, origco[vd.i])) { - const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist, + sculpt_orig_vert_data_update(&orig_data, &vd); + + if (sculpt_brush_test(&test, orig_data.co)) { + const float fade = bstrength * tex_strength(ss, brush, + orig_data.co, + test.dist, ss->cache->sculpt_normal_symm, - origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f); + orig_data.no, + NULL, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -1824,7 +2075,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1850,36 +2101,37 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; - SculptUndoNode *unode; SculptBrushTest test; - float (*origco)[3]; - short (*origno)[3]; + SculptOrigVertData orig_data; float (*proxy)[3]; - unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); - origco = unode->co; - origno = unode->no; + sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]); - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, origco[vd.i])) { - const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist, + sculpt_orig_vert_data_update(&orig_data, &vd); + + if (sculpt_brush_test(&test, orig_data.co)) { + const float fade = bstrength * tex_strength(ss, brush, + orig_data.co, + test.dist, ss->cache->sculpt_normal_symm, - origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f); + orig_data.no, + NULL, vd.mask ? *vd.mask : 0.0f); - mul_v3_m4v3(proxy[vd.i], m, origco[vd.i]); - sub_v3_v3(proxy[vd.i], origco[vd.i]); + mul_v3_m4v3(proxy[vd.i], m, orig_data.co); + sub_v3_v3(proxy[vd.i], orig_data.co); mul_v3_fl(proxy[vd.i], fade); if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1901,25 +2153,25 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; - SculptUndoNode *unode; - float (*origco)[3], *layer_disp; + SculptOrigVertData orig_data; + float *layer_disp; /* XXX: layer brush needs conversion to proxy but its more complicated */ - /* proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */ + /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */ - unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); - origco = unode->co; - if (!unode->layer_disp) { - #pragma omp critical - unode->layer_disp = MEM_callocN(sizeof(float) * unode->totvert, "layer disp"); - } - - layer_disp = unode->layer_disp; + sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]); + #pragma omp critical + { + layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, nodes[n]); + } + sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, origco[vd.i])) { + sculpt_orig_vert_data_update(&orig_data, &vd); + + if (sculpt_brush_test(&test, orig_data.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, ss->cache->sculpt_normal_symm, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); @@ -1941,7 +2193,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode add_v3_v3(val, ss->layer_co[index]); } else { - add_v3_v3(val, origco[vd.i]); + add_v3_v3(val, orig_data.co); } sculpt_clip(sd, ss, vd.co, val); @@ -1950,7 +2202,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1967,11 +2219,11 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, @@ -1989,7 +2241,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2016,24 +2268,24 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to sculpt_brush_test_init(ss, &test); if (ss->cache->original) { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, unode->co[vd.i])) { add_v3_v3(private_fc, unode->co[vd.i]); private_count++; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } else { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, vd.co)) { add_v3_v3(private_fc, vd.co); private_count++; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } #pragma omp critical @@ -2082,8 +2334,8 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); sculpt_brush_test_init(ss, &test); - if (ss->cache->original) { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + if (ss->cache->original && unode->co) { + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, unode->co[vd.i])) { /* for area normal */ @@ -2097,10 +2349,10 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, private_count++; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } else { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, vd.co)) { /* for area normal */ @@ -2119,7 +2371,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, private_count++; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } #pragma omp critical @@ -2301,11 +2553,11 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq(&test, vd.co)) { float intr[3]; @@ -2326,7 +2578,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2373,11 +2625,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq(&test, vd.co)) { if (plane_point_side_flip(vd.co, an, fc, flip)) { @@ -2401,7 +2653,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2475,11 +2727,11 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_cube(&test, vd.co, mat)) { if (plane_point_side_flip(vd.co, sn, fc, flip)) { @@ -2503,7 +2755,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2539,11 +2791,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq(&test, vd.co)) { if (plane_point_side(vd.co, an, fc)) { @@ -2567,7 +2819,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2603,11 +2855,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq(&test, vd.co)) { if (!plane_point_side(vd.co, an, fc)) { @@ -2631,7 +2883,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2688,6 +2940,65 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]) BKE_key_convert_from_vertcos(ob, kb, vertCos); } +/* Note: we do the topology update before any brush actions to avoid + * issues with the proxies. The size of the proxy can't change, so + * topology must be updated first. */ +static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush) +{ + SculptSession *ss = ob->sculpt; + SculptSearchSphereData data; + PBVHNode **nodes = NULL; + float radius; + int n, totnode; + + /* Build a list of all nodes that are potentially within the + * brush's area of influence */ + data.ss = ss; + data.sd = sd; + + radius = ss->cache->radius * 1.25f; + + data.radius_squared = radius * radius; + data.original = ELEM4(brush->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_LAYER); + + BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); + + /* Only act if some verts are inside the brush area */ + if (totnode) { + PBVHTopologyUpdateMode mode = PBVH_Subdivide; + + if ((sd->flags & SCULPT_DYNTOPO_COLLAPSE) || + (brush->sculpt_tool == SCULPT_TOOL_SIMPLIFY)) + { + mode |= PBVH_Collapse; + } + + for (n = 0; n < totnode; n++) { + sculpt_undo_push_node(ob, nodes[n], + brush->sculpt_tool == SCULPT_TOOL_MASK ? + SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS); + BKE_pbvh_node_mark_update(nodes[n]); + + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { + BKE_pbvh_node_mark_topology_update(nodes[n]); + BKE_pbvh_bmesh_node_save_orig(nodes[n]); + } + } + + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { + BKE_pbvh_bmesh_update_topology(ss->pbvh, mode, + ss->cache->location, + ss->cache->radius); + } + + MEM_freeN(nodes); + } +} + static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) { SculptSession *ss = ob->sculpt; @@ -2704,7 +3015,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB, SCULPT_TOOL_LAYER); - BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); /* Only act if some verts are inside the brush area */ if (totnode) { @@ -2713,7 +3024,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) sculpt_undo_push_node(ob, nodes[n], brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS); - BLI_pbvh_node_mark_update(nodes[n]); + BKE_pbvh_node_mark_update(nodes[n]); } if (brush_needs_sculpt_normal(brush)) @@ -2821,7 +3132,7 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) PBVHNode **nodes; int totnode, n; - BLI_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode); + BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode); if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) { /* these brushes start from original coordinates */ @@ -2835,18 +3146,25 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) int proxy_count; float (*orco)[3]; - if (use_orco) + if (use_orco && !ss->bm) orco = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS)->co; - BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count); + BKE_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { float val[3]; int p; - if (use_orco) - copy_v3_v3(val, orco[vd.i]); + if (use_orco) { + if (ss->bm) { + copy_v3_v3(val, + BM_log_original_vert_co(ss->bm_log, + vd.bm_vert)); + } + else + copy_v3_v3(val, orco[vd.i]); + } else copy_v3_v3(val, vd.co); @@ -2858,9 +3176,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) if (ss->modifiers_active) sculpt_flush_pbvhvert_deform(ob, &vd); } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; - BLI_pbvh_node_free_proxies(nodes[n]); + BKE_pbvh_node_free_proxies(nodes[n]); } } @@ -2877,7 +3195,7 @@ static void sculpt_update_keyblock(Object *ob) /* Keyblock update happens after handling deformation caused by modifiers, * so ss->orig_cos would be updated with new stroke */ if (ss->orig_cos) vertCos = ss->orig_cos; - else vertCos = BLI_pbvh_get_vertCos(ss->pbvh); + else vertCos = BKE_pbvh_get_vertCos(ss->pbvh); if (vertCos) { sculpt_vertcos_to_key(ob, ss->kb, vertCos); @@ -2905,13 +3223,13 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) if (ss->kb) vertCos = MEM_callocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts"); - BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { sculpt_flush_pbvhvert_deform(ob, &vd); @@ -2920,7 +3238,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) copy_v3_v3(vertCos[index], ss->orig_cos[index]); } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } if (vertCos) { @@ -2978,7 +3296,10 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry); } +typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush); + static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, + BrushActionFunc action, const char symm, const int axis, const float feather) { @@ -2989,7 +3310,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X']; ss->cache->radial_symmetry_pass = i; calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather); - do_brush_action(sd, ob, brush); + action(sd, ob, brush); } } @@ -3006,7 +3327,8 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob) multires_stitch_grids(ob); } -static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob) +static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, + BrushActionFunc action) { Brush *brush = paint_brush(&sd->paint); SculptSession *ss = ob->sculpt; @@ -3017,7 +3339,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob) float feather = calc_symmetry_feather(sd, ss->cache); cache->bstrength = brush_strength(sd, cache, feather); - cache->symmetry = symm; /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ @@ -3027,23 +3348,13 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob) cache->radial_symmetry_pass = 0; calc_brushdata_symm(sd, cache, i, 0, 0, feather); - do_brush_action(sd, ob, brush); + action(sd, ob, brush); - do_radial_symmetry(sd, ob, brush, i, 'X', feather); - do_radial_symmetry(sd, ob, brush, i, 'Y', feather); - do_radial_symmetry(sd, ob, brush, i, 'Z', feather); + do_radial_symmetry(sd, ob, brush, action, i, 'X', feather); + do_radial_symmetry(sd, ob, brush, action, i, 'Y', feather); + do_radial_symmetry(sd, ob, brush, action, i, 'Z', feather); } } - - sculpt_combine_proxies(sd, ob); - - /* hack to fix noise texture tearing mesh */ - sculpt_fix_noise_tear(sd, ob); - - if (ss->modifiers_active) - sculpt_flush_stroke_deform(sd, ob); - - cache->first_time = 0; } static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss) @@ -3142,7 +3453,7 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, ss->orig_cos = (ss->kb) ? BKE_key_convert_to_vertcos(ob, ss->kb) : mesh_getVertexCos(me, NULL); crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos); - BLI_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos); + BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos); for (a = 0; a < me->totvert; ++a) { invert_m3(ss->deform_imats[a]); @@ -3152,12 +3463,12 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, else free_sculptsession_deformMats(ss); /* if pbvh is deformed, key block is already applied to it */ - if (ss->kb && !BLI_pbvh_isDeformed(ss->pbvh)) { + if (ss->kb && !BKE_pbvh_isDeformed(ss->pbvh)) { float (*vertCos)[3] = BKE_key_convert_to_vertcos(ob, ss->kb); if (vertCos) { /* apply shape keys coordinates to PBVH */ - BLI_pbvh_apply_vertCos(ss->pbvh, vertCos); + BKE_pbvh_apply_vertCos(ss->pbvh, vertCos); MEM_freeN(vertCos); } } @@ -3220,6 +3531,8 @@ static const char *sculpt_tool_name(Sculpt *sd) return "Rotate Brush"; case SCULPT_TOOL_MASK: return "Mask Brush"; + case SCULPT_TOOL_SIMPLIFY: + return "Simplify Brush"; } return "Sculpting"; @@ -3291,7 +3604,7 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss) if (ss->multires) { int i, gridsize, array_mem_size; - BLI_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL, + BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL, &gridsize, NULL, NULL); array_mem_size = cache->num_threads * sizeof(void *); @@ -3406,8 +3719,9 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio ED_view3d_global_to_vector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal); /* Initialize layer brush displacements and persistent coords */ if (brush->sculpt_tool == SCULPT_TOOL_LAYER) { - /* not supported yet for multires */ - if (!ss->multires && !ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) { + /* not supported yet for multires or dynamic topology */ + if (!ss->multires && !ss->bm && !ss->layer_co && + (brush->flag & BRUSH_PERSISTENT)) { if (!ss->layer_co) ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert, "sculpt mesh vertices copy"); @@ -3721,17 +4035,26 @@ typedef struct { static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) { - if (BLI_pbvh_node_get_tmin(node) < *tmin) { + if (BKE_pbvh_node_get_tmin(node) < *tmin) { SculptRaycastData *srd = data_v; float (*origco)[3] = NULL; + int use_origco = FALSE; if (srd->original && srd->ss->cache) { - /* intersect with coordinates from before we started stroke */ - SculptUndoNode *unode = sculpt_undo_get_node(node); - origco = (unode) ? unode->co : NULL; + if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) { + use_origco = TRUE; + } + else { + /* intersect with coordinates from before we started stroke */ + SculptUndoNode *unode = sculpt_undo_get_node(node); + origco = (unode) ? unode->co : NULL; + use_origco = origco ? TRUE : FALSE; + } } - if (BLI_pbvh_node_raycast(srd->ss->pbvh, node, origco, srd->ray_start, srd->ray_normal, &srd->dist)) { + if (BKE_pbvh_node_raycast(srd->ss->pbvh, node, origco, use_origco, + srd->ray_start, srd->ray_normal, &srd->dist)) + { srd->hit = 1; *tmin = srd->dist; } @@ -3780,7 +4103,7 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) srd.dist = dist; srd.hit = 0; srd.original = (cache) ? cache->original : 0; - BLI_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, + BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original); copy_v3_v3(out, ray_normal); @@ -3829,8 +4152,9 @@ static int sculpt_brush_stroke_init(bContext *C, wmOperator *op) return 1; } -static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) +static void sculpt_restore_mesh(Sculpt *sd, Object *ob) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); /* Restore the mesh before continuing with anchored stroke */ @@ -3839,7 +4163,7 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) || (brush->flag & BRUSH_RESTORE_MESH)) { - paint_mesh_restore_co(sd, ss); + paint_mesh_restore_co(sd, ob); } } @@ -3862,7 +4186,7 @@ static void sculpt_flush_update(bContext *C) else { rcti r; - BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL); + BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL); if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) { if (ss->cache) ss->cache->previous_r = r; @@ -3917,11 +4241,33 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; + const Brush *brush = paint_brush(&sd->paint); sculpt_stroke_modifiers_check(C, ob); sculpt_update_cache_variants(C, sd, ob, stroke, itemptr); - sculpt_restore_mesh(sd, ss); - do_symmetrical_brush_actions(sd, ob); + sculpt_restore_mesh(sd, ob); + + BKE_pbvh_bmesh_detail_size_set(ss->pbvh, + (ss->cache->radius / + (float)ss->cache->pixel_radius) * + (float)sd->detail_size); + + if (sculpt_stroke_dynamic_topology(ss, brush)) { + do_symmetrical_brush_actions(sd, ob, sculpt_topology_update); + } + + if (paint_brush(&sd->paint)->sculpt_tool != SCULPT_TOOL_SIMPLIFY) + do_symmetrical_brush_actions(sd, ob, do_brush_action); + + sculpt_combine_proxies(sd, ob); + + /* hack to fix noise texture tearing mesh */ + sculpt_fix_noise_tear(sd, ob); + + if (ss->modifiers_active) + sculpt_flush_stroke_deform(sd, ob); + + ss->cache->first_time = FALSE; /* Cleanup */ sculpt_flush_update(C); @@ -3980,7 +4326,10 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str sculpt_undo_push_end(); - BLI_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL); + BKE_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL); + + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) + BKE_pbvh_bmesh_after_stroke(ss->pbvh); /* optimization: if there is locked key and active modifiers present in */ /* the stack, keyblock is updating at each step. otherwise we could update */ @@ -4055,7 +4404,7 @@ static int sculpt_brush_stroke_cancel(bContext *C, wmOperator *op) Sculpt *sd = CTX_data_tool_settings(C)->sculpt; if (ss->cache) { - paint_mesh_restore_co(sd, ss); + paint_mesh_restore_co(sd, ob); } paint_stroke_cancel(C, op); @@ -4137,6 +4486,266 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/************************** Dynamic Topology **************************/ + +static void sculpt_dynamic_topology_triangulate(BMesh *bm) +{ + BMO_op_callf(bm, BMO_FLAG_DEFAULTS, "triangulate faces=%af"); +} + +void sculpt_pbvh_clear(Object *ob) +{ + SculptSession *ss = ob->sculpt; + DerivedMesh *dm = ob->derivedFinal; + + /* Clear out any existing DM and PBVH */ + if (ss->pbvh) + BKE_pbvh_free(ss->pbvh); + ss->pbvh = NULL; + if (dm) + dm->getPBVH(NULL, dm); + BKE_object_free_display(ob); +} + +void sculpt_update_after_dynamic_topology_toggle(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Sculpt *sd = scene->toolsettings->sculpt; + + /* Create the PBVH */ + sculpt_update_mesh_elements(scene, sd, ob, FALSE, FALSE); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); +} + +void sculpt_dynamic_topology_enable(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + Mesh *me = ob->data; + + sculpt_pbvh_clear(ob); + + ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & + SCULPT_DYNTOPO_SMOOTH_SHADING); + + /* Create triangles-only BMesh */ + ss->bm = BM_mesh_create(&bm_mesh_allocsize_default); + + BM_mesh_bm_from_me(ss->bm, me, TRUE, ob->shapenr); + sculpt_dynamic_topology_triangulate(ss->bm); + BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); + BM_mesh_normals_update(ss->bm, TRUE); + + /* Enable dynamic topology */ + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; + + /* Enable logging for undo/redo */ + ss->bm_log = BM_log_create(ss->bm); + + /* Refresh */ + sculpt_update_after_dynamic_topology_toggle(C); +} + +/* Free the sculpt BMesh and BMLog + * + * If 'unode' is given, the BMesh's data is copied out to the unode + * before the BMesh is deleted so that it can be restored from */ +void sculpt_dynamic_topology_disable(bContext *C, + SculptUndoNode *unode) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + Mesh *me = ob->data; + + sculpt_pbvh_clear(ob); + + if (unode) { + /* Free all existing custom data */ + CustomData_free(&me->vdata, me->totvert); + CustomData_free(&me->edata, me->totedge); + CustomData_free(&me->fdata, me->totface); + CustomData_free(&me->ldata, me->totloop); + CustomData_free(&me->pdata, me->totpoly); + + /* Copy over stored custom data */ + me->totvert = unode->bm_enter_totvert; + me->totloop = unode->bm_enter_totloop; + me->totpoly = unode->bm_enter_totpoly; + me->totedge = unode->bm_enter_totedge; + me->totface = 0; + CustomData_copy(&unode->bm_enter_vdata, &me->vdata, CD_MASK_MESH, + CD_DUPLICATE, unode->bm_enter_totvert); + CustomData_copy(&unode->bm_enter_edata, &me->edata, CD_MASK_MESH, + CD_DUPLICATE, unode->bm_enter_totedge); + CustomData_copy(&unode->bm_enter_ldata, &me->ldata, CD_MASK_MESH, + CD_DUPLICATE, unode->bm_enter_totloop); + CustomData_copy(&unode->bm_enter_pdata, &me->pdata, CD_MASK_MESH, + CD_DUPLICATE, unode->bm_enter_totpoly); + + mesh_update_customdata_pointers(me, FALSE); + } else { + sculptsession_bm_to_me(ob, TRUE); + } + + BM_mesh_free(ss->bm); + + /* Clear data */ + me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; + ss->bm = NULL; + BM_log_free(ss->bm_log); + ss->bm_log = NULL; + + /* Refresh */ + sculpt_update_after_dynamic_topology_toggle(C); +} + +static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + if (ss->bm) { + sculpt_undo_push_begin("Dynamic topology disable"); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END); + sculpt_dynamic_topology_disable(C, NULL); + } + else { + sculpt_undo_push_begin("Dynamic topology enable"); + sculpt_dynamic_topology_enable(C); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); + } + sculpt_undo_push_end(); + + return OPERATOR_FINISHED; +} + +static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, + wmEvent *UNUSED(event)) +{ + Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; + SculptSession *ss = ob->sculpt; + const char *msg = "Dynamic-topology sculpting will not preserve" + "vertex colors, UVs, or other customdata"; + + if (!ss->bm) { + int i; + + for (i = 0; i < CD_NUMTYPES; i++) { + if (!ELEM7(i, CD_MVERT, CD_MEDGE, CD_MFACE, + CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, + CD_ORIGINDEX) && + (CustomData_has_layer(&me->vdata, i) || + CustomData_has_layer(&me->edata, i) || + CustomData_has_layer(&me->fdata, i))) { + /* The mesh has customdata that will be lost, let the + * user confirm this is OK */ + return WM_operator_confirm_message(C, op, msg); + } + } + } + + return sculpt_dynamic_topology_toggle_exec(C, op); +} + +static void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Dynamic Topology Toggle"; + ot->idname = "SCULPT_OT_dynamic_topology_toggle"; + ot->description = "Dynamic topology alters the mesh topology while sculpting"; + + /* api callbacks */ + ot->invoke = sculpt_dynamic_topology_toggle_invoke; + ot->exec = sculpt_dynamic_topology_toggle_exec; + ot->poll = sculpt_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/************************* SCULPT_OT_optimize *************************/ + +static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + + sculpt_pbvh_clear(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +static int sculpt_and_dynamic_topology_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + + return sculpt_mode_poll(C) && ob->sculpt->bm; +} + +/* The BVH gets less optimal more quickly with dynamic topology than + * regular sculpting. There is no doubt more clever stuff we can do to + * optimize it on the fly, but for now this gives the user a nicer way + * to recalculate it than toggling modes. */ +static void SCULPT_OT_optimize(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Optimize"; + ot->idname = "SCULPT_OT_optimize"; + ot->description = "Recalculate the sculpt BVH to improve performance"; + + /* api callbacks */ + ot->exec = sculpt_optimize_exec; + ot->poll = sculpt_and_dynamic_topology_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************* Dynamic topology symmetrize ********************/ + +static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + const Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + + /* To simplify undo for symmetrize, all BMesh elements are logged + * as deleted, then after symmetrize operation all BMesh elements + * are logged as added (as opposed to attempting to store just the + * parts that symmetrize modifies) */ + sculpt_undo_push_begin("Dynamic topology symmetrize"); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); + BM_log_before_all_removed(ss->bm, ss->bm_log); + + /* Symmetrize and re-triangulate */ + BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS, + "symmetrize input=%avef direction=%i", + sd->symmetrize_direction); + sculpt_dynamic_topology_triangulate(ss->bm); + + /* Finish undo */ + BM_log_all_added(ss->bm, ss->bm_log); + sculpt_undo_push_end(); + + /* Redraw */ + sculpt_pbvh_clear(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_symmetrize(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Symmetrize"; + ot->idname = "SCULPT_OT_symmetrize"; + + /* api callbacks */ + ot->exec = sculpt_symmetrize_exec; + ot->poll = sculpt_and_dynamic_topology_poll; +} + /**** Toggle operator for turning sculpt mode on or off ****/ static void sculpt_init_session(Scene *scene, Object *ob) @@ -4222,6 +4831,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; MultiresModifierData *mmd = sculpt_multires_active(scene, ob); int flush_recalc = 0; @@ -4234,9 +4844,16 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) if (mmd) multires_force_update(ob); - if (flush_recalc) + if (flush_recalc || (ob->sculpt && ob->sculpt->bm)) DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { + /* Dynamic topology must be disabled before exiting sculpt + * mode to ensure the undo stack stays in a consistent + * state */ + sculpt_dynamic_topology_toggle_exec(C, NULL); + } + /* Leave sculptmode */ ob->mode &= ~OB_MODE_SCULPT; @@ -4257,6 +4874,9 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) ts->sculpt->flags |= SCULPT_SYMM_X; } + if (!ts->sculpt->detail_size) + ts->sculpt->detail_size = 30; + /* Create sculpt mode session data */ if (ob->sculpt) free_sculptsession(ob); @@ -4271,7 +4891,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) } BKE_paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT); - + paint_cursor_start(C, sculpt_poll); } @@ -4299,4 +4919,7 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_brush_stroke); WM_operatortype_append(SCULPT_OT_sculptmode_toggle); WM_operatortype_append(SCULPT_OT_set_persistent_base); + WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle); + WM_operatortype_append(SCULPT_OT_optimize); + WM_operatortype_append(SCULPT_OT_symmetrize); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 44068122b89..e56962a3964 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -49,6 +49,7 @@ struct Object; struct Scene; struct Sculpt; struct SculptStroke; +struct SculptUndoNode; /* Interface */ struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob); @@ -67,12 +68,22 @@ void free_sculptsession_deformMats(struct SculptSession *ss); /* Stroke */ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]); +/* Dynamic topology */ +void sculpt_pbvh_clear(Object *ob); +void sculpt_update_after_dynamic_topology_toggle(bContext *C); +void sculpt_dynamic_topology_enable(struct bContext *C); +void sculpt_dynamic_topology_disable(struct bContext *C, + struct SculptUndoNode *unode); + /* Undo */ typedef enum { SCULPT_UNDO_COORDS, SCULPT_UNDO_HIDDEN, - SCULPT_UNDO_MASK + SCULPT_UNDO_MASK, + SCULPT_UNDO_DYNTOPO_BEGIN, + SCULPT_UNDO_DYNTOPO_END, + SCULPT_UNDO_DYNTOPO_SYMMETRIZE, } SculptUndoType; typedef struct SculptUndoNode { @@ -101,8 +112,17 @@ typedef struct SculptUndoNode { int *grids; /* to restore into right location */ BLI_bitmap *grid_hidden; - /* layer brush */ - float *layer_disp; + /* bmesh */ + struct BMLogEntry *bm_entry; + int applied; + CustomData bm_enter_vdata; + CustomData bm_enter_edata; + CustomData bm_enter_ldata; + CustomData bm_enter_pdata; + int bm_enter_totvert; + int bm_enter_totedge; + int bm_enter_totloop; + int bm_enter_totpoly; /* shape keys */ char shapeName[sizeof(((KeyBlock *)0))->name]; diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 1b3fd24ae22..c828e8c8651 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -65,6 +65,7 @@ #include "GPU_buffers.h" #include "ED_sculpt.h" +#include "bmesh.h" #include "paint_intern.h" #include "sculpt_intern.h" @@ -72,10 +73,10 @@ static void update_cb(PBVHNode *node, void *rebuild) { - BLI_pbvh_node_mark_update(node); + BKE_pbvh_node_mark_update(node); if (*((int *)rebuild)) - BLI_pbvh_node_mark_rebuild_draw(node); - BLI_pbvh_node_fully_hidden_set(node, 0); + BKE_pbvh_node_mark_rebuild_draw(node); + BKE_pbvh_node_fully_hidden_set(node, 0); } static void sculpt_undo_restore_deformed(const SculptSession *ss, @@ -142,7 +143,7 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo /* pbvh uses it's own mvert array, so coords should be */ /* propagated to pbvh here */ - BLI_pbvh_apply_vertCos(ss->pbvh, vertCos); + BKE_pbvh_apply_vertCos(ss->pbvh, vertCos); MEM_freeN(vertCos); } @@ -261,6 +262,111 @@ static int sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNode return 1; } +static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, + Object *ob, + SculptSession *ss) +{ + if (unode->applied) { + BM_log_undo(ss->bm, ss->bm_log); + unode->applied = FALSE; + } + else { + BM_log_redo(ss->bm, ss->bm_log); + unode->applied = TRUE; + } + + /* A bit lame, but for now just recreate the PBVH. The alternative + * is to store changes to the PBVH in the undo stack. */ + sculpt_pbvh_clear(ob); +} + +/* Create empty sculpt BMesh and enable logging */ +static void sculpt_undo_bmesh_enable(Object *ob, + SculptUndoNode *unode) +{ + SculptSession *ss = ob->sculpt; + Mesh *me = ob->data; + + sculpt_pbvh_clear(ob); + + /* Create empty BMesh and enable logging */ + ss->bm = BM_mesh_create(&bm_mesh_allocsize_default); + BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; + + /* Restore the BMLog using saved entries */ + ss->bm_log = BM_log_from_existing_entries_create(ss->bm, + unode->bm_entry); +} + +static void sculpt_undo_bmesh_restore_begin(bContext *C, + SculptUndoNode *unode, + Object *ob, + SculptSession *ss) +{ + if (unode->applied) { + sculpt_dynamic_topology_disable(C, unode); + unode->applied = FALSE; + } + else { + sculpt_undo_bmesh_enable(ob, unode); + + /* Restore the mesh from the first log entry */ + BM_log_redo(ss->bm, ss->bm_log); + + unode->applied = TRUE; + } +} + +static void sculpt_undo_bmesh_restore_end(bContext *C, + SculptUndoNode *unode, + Object *ob, + SculptSession *ss) +{ + if (unode->applied) { + sculpt_undo_bmesh_enable(ob, unode); + + /* Restore the mesh from the last log entry */ + BM_log_undo(ss->bm, ss->bm_log); + + unode->applied = FALSE; + } + else { + /* Disable dynamic topology sculpting */ + sculpt_dynamic_topology_disable(C, NULL); + unode->applied = TRUE; + } +} + +/* Handle all dynamic-topology updates + * + * Returns TRUE if this was a dynamic-topology undo step, otherwise + * returns FALSE to indicate the non-dyntopo code should run. */ +static int sculpt_undo_bmesh_restore(bContext *C, + SculptUndoNode *unode, + Object *ob, + SculptSession *ss) +{ + switch (unode->type) { + case SCULPT_UNDO_DYNTOPO_BEGIN: + sculpt_undo_bmesh_restore_begin(C, unode, ob, ss); + return TRUE; + + case SCULPT_UNDO_DYNTOPO_END: + sculpt_undo_bmesh_restore_end(C, unode, ob, ss); + return TRUE; + + default: + if (ss->bm_log) { + sculpt_undo_bmesh_restore_generic(unode, ob, ss); + return TRUE; + } + break; + } + + return FALSE; +} + static void sculpt_undo_restore(bContext *C, ListBase *lb) { Scene *scene = CTX_data_scene(C); @@ -289,6 +395,9 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) /* call _after_ sculpt_update_mesh_elements() which may update 'ob->derivedFinal' */ dm = mesh_get_derived_final(scene, ob, 0); + if (lb->first && sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) + return; + for (unode = lb->first; unode; unode = unode->next) { if (!(strcmp(unode->idname, ob->id.name) == 0)) continue; @@ -306,9 +415,6 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) continue; } } - else { - continue; - } switch (unode->type) { case SCULPT_UNDO_COORDS: @@ -323,6 +429,12 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) if (sculpt_undo_restore_mask(C, dm, unode)) update = TRUE; break; + + case SCULPT_UNDO_DYNTOPO_BEGIN: + case SCULPT_UNDO_DYNTOPO_END: + case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: + BLI_assert(!"Dynamic topology should've already been handled"); + break; } } @@ -331,8 +443,8 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) /* we update all nodes still, should be more clever, but also * needs to work correct when exiting/entering sculpt mode and * the nodes get recreated, though in that case it could do all */ - BLI_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild); - BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw, NULL); + BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild); + BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw, NULL); if ((mmd = sculpt_multires_active(scene, ob))) { if (rebuild) @@ -374,8 +486,6 @@ static void sculpt_undo_free(ListBase *lb) MEM_freeN(unode->index); if (unode->grids) MEM_freeN(unode->grids); - if (unode->layer_disp) - MEM_freeN(unode->layer_disp); if (unode->orig_co) MEM_freeN(unode->orig_co); if (unode->vert_hidden) @@ -389,6 +499,17 @@ static void sculpt_undo_free(ListBase *lb) } if (unode->mask) MEM_freeN(unode->mask); + if (unode->bm_entry) { + BM_log_entry_drop(unode->bm_entry); + } + if (unode->bm_enter_totvert) + CustomData_free(&unode->bm_enter_vdata, unode->bm_enter_totvert); + if (unode->bm_enter_totedge) + CustomData_free(&unode->bm_enter_edata, unode->bm_enter_totedge); + if (unode->bm_enter_totloop) + CustomData_free(&unode->bm_enter_ldata, unode->bm_enter_totloop); + if (unode->bm_enter_totpoly) + CustomData_free(&unode->bm_enter_pdata, unode->bm_enter_totpoly); } } @@ -410,9 +531,9 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, BLI_bitmap *grid_hidden; int i, *grid_indices, totgrid; - grid_hidden = BLI_pbvh_grid_hidden(pbvh); + grid_hidden = BKE_pbvh_grid_hidden(pbvh); - BLI_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, + BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, NULL, NULL); unode->grid_hidden = MEM_mapallocN(sizeof(BLI_bitmap) * totgrid, @@ -439,11 +560,13 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, unode->type = type; unode->node = node; - BLI_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert); - BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, - &maxgrid, &gridsize, NULL, NULL); + if (node) { + BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert); + BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, + &maxgrid, &gridsize, NULL, NULL); - unode->totvert = totvert; + unode->totvert = totvert; + } /* we will use this while sculpting, is mapalloc slow to access then? */ @@ -468,6 +591,11 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask"); undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float) * sizeof(int)) * allvert); break; + case SCULPT_UNDO_DYNTOPO_BEGIN: + case SCULPT_UNDO_DYNTOPO_END: + case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: + BLI_assert(!"Dynamic topology should've already been handled"); + break; } BLI_addtail(lb, unode); @@ -496,7 +624,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode) SculptSession *ss = ob->sculpt; PBVHVertexIter vd; - BLI_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) + BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) { copy_v3_v3(unode->co[vd.i], vd.co); if (vd.no) copy_v3_v3_short(unode->no[vd.i], vd.no); @@ -505,7 +633,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode) if (ss->modifiers_active) copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]); } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode) @@ -521,8 +649,8 @@ static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode) int *vert_indices, allvert; int i; - BLI_pbvh_node_num_verts(pbvh, node, NULL, &allvert); - BLI_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert); + BKE_pbvh_node_num_verts(pbvh, node, NULL, &allvert); + BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert); for (i = 0; i < allvert; i++) { BLI_BITMAP_MODIFY(unode->vert_hidden, i, mvert[vert_indices[i]].flag & ME_HIDE); @@ -535,11 +663,85 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode) SculptSession *ss = ob->sculpt; PBVHVertexIter vd; - BLI_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) + BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) { unode->mask[vd.i] = *vd.mask; } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; +} + +static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, + PBVHNode *node, + SculptUndoType type) +{ + ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); + SculptUndoNode *unode = lb->first; + SculptSession *ss = ob->sculpt; + PBVHVertexIter vd; + + if (!lb->first) { + unode = MEM_callocN(sizeof(*unode), AT); + + BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname)); + unode->type = type; + unode->applied = TRUE; + + if (type == SCULPT_UNDO_DYNTOPO_END) { + unode->bm_entry = BM_log_entry_add(ss->bm_log); + BM_log_before_all_removed(ss->bm, ss->bm_log); + } + else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) { + Mesh *me = ob->data; + + /* Store a copy of the mesh's current vertices, loops, and + * polys. A full copy like this is needed because entering + * dynamic-topology immediately does topological edits + * (converting polys to triangles) that the BMLog can't + * fully restore from */ + CustomData_copy(&me->vdata, &unode->bm_enter_vdata, CD_MASK_MESH, + CD_DUPLICATE, me->totvert); + CustomData_copy(&me->edata, &unode->bm_enter_edata, CD_MASK_MESH, + CD_DUPLICATE, me->totedge); + CustomData_copy(&me->ldata, &unode->bm_enter_ldata, CD_MASK_MESH, + CD_DUPLICATE, me->totloop); + CustomData_copy(&me->pdata, &unode->bm_enter_pdata, CD_MASK_MESH, + CD_DUPLICATE, me->totpoly); + unode->bm_enter_totvert = me->totvert; + unode->bm_enter_totedge = me->totedge; + unode->bm_enter_totloop = me->totloop; + unode->bm_enter_totpoly = me->totpoly; + + unode->bm_entry = BM_log_entry_add(ss->bm_log); + BM_log_all_added(ss->bm, ss->bm_log); + } + else { + unode->bm_entry = BM_log_entry_add(ss->bm_log); + } + + BLI_addtail(lb, unode); + } + + if (node) { + switch (type) { + case SCULPT_UNDO_COORDS: + case SCULPT_UNDO_HIDDEN: + case SCULPT_UNDO_MASK: + /* Before any vertex values get modified, ensure their + * original positions are logged */ + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) { + BM_log_vert_before_modified(ss->bm, ss->bm_log, vd.bm_vert); + } + BKE_pbvh_vertex_iter_end; + break; + + case SCULPT_UNDO_DYNTOPO_BEGIN: + case SCULPT_UNDO_DYNTOPO_END: + case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: + break; + } + } + + return unode; } SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, @@ -551,7 +753,18 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, /* list is manipulated by multiple threads, so we lock */ BLI_lock_thread(LOCK_CUSTOM1); - if ((unode = sculpt_undo_get_node(node))) { + if (ss->bm || + ELEM(type, + SCULPT_UNDO_DYNTOPO_BEGIN, + SCULPT_UNDO_DYNTOPO_END)) + { + /* Dynamic topology stores only one undo node per stroke, + * regardless of the number of PBVH nodes modified */ + unode = sculpt_undo_bmesh_push(ob, node, type); + BLI_unlock_thread(LOCK_CUSTOM1); + return unode; + } + else if ((unode = sculpt_undo_get_node(node))) { BLI_unlock_thread(LOCK_CUSTOM1); return unode; } @@ -564,14 +777,14 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, if (unode->grids) { int totgrid, *grids; - BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, + BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, NULL, NULL, NULL, NULL); memcpy(unode->grids, grids, sizeof(int) * totgrid); } else { int *vert_indices, allvert; - BLI_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert); - BLI_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL); + BKE_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert); + BKE_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL); memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert); } @@ -585,6 +798,11 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, case SCULPT_UNDO_MASK: sculpt_undo_store_mask(ob, unode); break; + case SCULPT_UNDO_DYNTOPO_BEGIN: + case SCULPT_UNDO_DYNTOPO_END: + case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: + BLI_assert(!"Dynamic topology should've already been handled"); + break; } /* store active shape key */ @@ -612,10 +830,8 @@ void sculpt_undo_push_end(void) unode->no = NULL; } - if (unode->layer_disp) { - MEM_freeN(unode->layer_disp); - unode->layer_disp = NULL; - } + if (unode->node) + BKE_pbvh_node_layer_disp_free(unode->node); } undo_paint_push_end(UNDO_PAINT_MESH); diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 9bd7d2a44ca..4b1954c8889 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -82,13 +82,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - /* Update max-extent of channels here (taking into account scrollers): - * - this is done to allow the channel list to be scrollable, but must be done here - * to avoid regenerating the list again and/or also because channels list is drawn first - * - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for - * start of list offset, and the second is as a correction for the scrollers. - */ - height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2)); + height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT)); if (height > BLI_rcti_size_y(&v2d->mask)) { /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) @@ -199,13 +193,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - /* Update max-extent of channels here (taking into account scrollers): - * - this is done to allow the channel list to be scrollable, but must be done here - * to avoid regenerating the list again and/or also because channels list is drawn first - * - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for - * start of list offset, and the second is as a correction for the scrollers. - */ - height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2)); + height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT)); /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) */ diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index c5f3ccee101..e0ca589c1fb 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -219,6 +219,9 @@ static void action_channel_area_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; + /* ensure the 2d view sync works - main region has bottom scroller */ + ar->v2d.scroll = V2D_SCROLL_BOTTOM; + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ @@ -231,7 +234,6 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar) /* draw entirely, view changes should be handled here */ bAnimContext ac; View2D *v2d = &ar->v2d; - View2DScrollers *scrollers; /* clear and setup matrix */ UI_ThemeClearColor(TH_BACK); @@ -247,10 +249,7 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); - /* scrollers */ - scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY); - UI_view2d_scrollers_draw(C, v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + /* no scrollers here */ } diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 77662d8ac13..56a890c714a 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -1801,7 +1801,7 @@ static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat int found = FALSE; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (!cti) continue; @@ -1832,7 +1832,7 @@ static Object *object_solver_camera(Scene *scene, Object *ob) bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (!cti) continue; diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index fb438ae45fb..08f01b47b52 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -321,8 +321,7 @@ void file_calc_previews(const bContext *C, ARegion *ar) View2D *v2d = &ar->v2d; ED_fileselect_init_layout(sfile, ar); - /* +SCROLL_HEIGHT is bad hack to work around issue in UI_view2d_totRect_set */ - UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height + V2D_SCROLL_HEIGHT); + UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height); } static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, short dropshadow) diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index fa7c6bd472a..734c0e6c479 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -309,6 +309,12 @@ static void graph_channel_area_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; + /* make sure we keep the hide flags */ + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); + ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP); /* prevent any noise of past */ + ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; + ar->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE; + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index d02186e59dd..060a181612b 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -219,7 +219,7 @@ static void preview_cb(ScrArea *sa, struct uiBlock *block) BLI_rcti_translate(disprect, -curarea->winrct.xmin, -curarea->winrct.ymin); calc_image_view(sima, 'p'); -// printf("winrct %d %d %d %d\n", disprect->xmin, disprect->ymin,disprect->xmax, disprect->ymax); +// printf("winrct %d %d %d %d\n", disprect->xmin, disprect->ymin, disprect->xmax, disprect->ymax); /* map to image space coordinates */ mval[0] = disprect->xmin; mval[1] = disprect->ymin; areamouseco_to_ipoco(v2d, mval, &dispf.xmin, &dispf.ymin); @@ -236,7 +236,7 @@ static void preview_cb(ScrArea *sa, struct uiBlock *block) CLAMP(disprect->xmax, 0, winx); CLAMP(disprect->ymin, 0, winy); CLAMP(disprect->ymax, 0, winy); -// printf("drawrct %d %d %d %d\n", disprect->xmin, disprect->ymin,disprect->xmax, disprect->ymax); +// printf("drawrct %d %d %d %d\n", disprect->xmin, disprect->ymin, disprect->xmax, disprect->ymax); } @@ -674,6 +674,24 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char if (ima->source != IMA_SRC_GENERATED) { if (compact == 0) { /* background image view doesnt need these */ + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); + int has_alpha = TRUE; + + if (ibuf) { + int imtype = BKE_ftype_to_imtype(ibuf->ftype); + char valid_channels = BKE_imtype_valid_channels(imtype); + + has_alpha = valid_channels & IMA_CHAN_FLAG_ALPHA; + + BKE_image_release_ibuf(ima, ibuf, NULL); + } + + if (has_alpha) { + col = uiLayoutColumn(layout, FALSE); + uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE); + uiItemR(col, &imaptr, "alpha_mode", 0, "Alpha", ICON_NONE); + } + uiItemS(layout); split = uiLayoutSplit(layout, 0.0f, FALSE); @@ -694,10 +712,6 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char row = uiLayoutRow(col, FALSE); uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_fields")); uiItemR(row, &imaptr, "field_order", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - - row = uiLayoutRow(layout, FALSE); - uiItemR(row, &imaptr, "use_premultiply", 0, NULL, ICON_NONE); - uiItemR(row, &imaptr, "use_color_unpremultiply", 0, NULL, ICON_NONE); } } @@ -796,6 +810,8 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man } if (imf->imtype == R_IMF_IMTYPE_JP2) { + uiItemR(col, imfptr, "jpeg2k_codec", 0, NULL, ICON_NONE); + row = uiLayoutRow(col, FALSE); uiItemR(row, imfptr, "use_jpeg2k_cinema_preset", 0, NULL, ICON_NONE); uiItemR(row, imfptr, "use_jpeg2k_cinema_48", 0, NULL, ICON_NONE); diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index d565e6f9e9a..0534b9f4ffd 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -75,13 +75,15 @@ #include "WM_types.h" #include "RE_pipeline.h" +#include "RE_engine.h" #include "image_intern.h" -static void draw_render_info(Scene *scene, Image *ima, ARegion *ar) +static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx, float zoomy) { RenderResult *rr; - + Render *re = RE_GetRender(scene->id.name); + rr = BKE_image_acquire_renderresult(scene, ima); if (rr && rr->text) { @@ -89,6 +91,73 @@ static void draw_render_info(Scene *scene, Image *ima, ARegion *ar) } BKE_image_release_renderresult(scene, ima); + + if (re) { + int total_tiles; + rcti *tiles; + + RE_engine_get_current_tiles(re, &total_tiles, &tiles); + + if (total_tiles) { + int i, x, y; + rcti *tile; + + /* find window pixel coordinates of origin */ + UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y); + + glPushMatrix(); + glTranslatef(x, y, 0.0f); + glScalef(zoomx, zoomy, 1.0f); + + if (scene->r.mode & R_BORDER) { + glTranslatef(-scene->r.border.xmin * scene->r.xsch * scene->r.size / 100.0f, + -scene->r.border.ymin * scene->r.ysch * scene->r.size / 100.0f, + 0.0f); + } + + UI_ThemeColor(TH_FACE_SELECT); + + for (i = 0, tile = tiles; i < total_tiles; i++, tile++) { + float delta_x = 4.0f * UI_DPI_FAC / zoomx; + float delta_y = 4.0f * UI_DPI_FAC / zoomy; + + delta_x = min_ff(delta_x, tile->xmax - tile->xmin); + delta_y = min_ff(delta_y, tile->ymax - tile->ymin); + + /* left bottom corner */ + glBegin(GL_LINE_STRIP); + glVertex2f(tile->xmin, tile->ymin + delta_y); + glVertex2f(tile->xmin, tile->ymin); + glVertex2f(tile->xmin + delta_x, tile->ymin); + glEnd(); + + /* left top corner */ + glBegin(GL_LINE_STRIP); + glVertex2f(tile->xmin, tile->ymax - delta_y); + glVertex2f(tile->xmin, tile->ymax); + glVertex2f(tile->xmin + delta_x, tile->ymax); + glEnd(); + + /* right bottom corner */ + glBegin(GL_LINE_STRIP); + glVertex2f(tile->xmax - delta_x, tile->ymin); + glVertex2f(tile->xmax, tile->ymin); + glVertex2f(tile->xmax, tile->ymin + delta_y); + glEnd(); + + /* right top corner */ + glBegin(GL_LINE_STRIP); + glVertex2f(tile->xmax - delta_x, tile->ymax); + glVertex2f(tile->xmax, tile->ymax); + glVertex2f(tile->xmax, tile->ymax - delta_y); + glEnd(); + } + + MEM_freeN(tiles); + + glPopMatrix(); + } + } } /* used by node view too */ @@ -146,7 +215,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def if (channels >= 3) { glColor3ubv(red); if (fp) - BLI_snprintf(str, sizeof(str), " R:%-.4f", fp[0]); + BLI_snprintf(str, sizeof(str), " R:%-.5f", fp[0]); else if (cp) BLI_snprintf(str, sizeof(str), " R:%-3d", cp[0]); else @@ -157,7 +226,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def glColor3ubv(green); if (fp) - BLI_snprintf(str, sizeof(str), " G:%-.4f", fp[1]); + BLI_snprintf(str, sizeof(str), " G:%-.5f", fp[1]); else if (cp) BLI_snprintf(str, sizeof(str), " G:%-3d", cp[1]); else @@ -168,7 +237,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def glColor3ubv(blue); if (fp) - BLI_snprintf(str, sizeof(str), " B:%-.4f", fp[2]); + BLI_snprintf(str, sizeof(str), " B:%-.5f", fp[2]); else if (cp) BLI_snprintf(str, sizeof(str), " B:%-3d", cp[2]); else @@ -518,8 +587,8 @@ static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene, sima->curtile = ima->xrep * ima->yrep - 1; /* retrieve part of image buffer */ - dx = ibuf->x / ima->xrep; - dy = ibuf->y / ima->yrep; + dx = max_ii(ibuf->x / ima->xrep, 1); + dy = max_ii(ibuf->y / ima->yrep, 1); sx = (sima->curtile % ima->xrep) * dx; sy = (sima->curtile / ima->xrep) * dy; rect = get_part_from_buffer((unsigned int *)display_buffer, ibuf->x, sx, sy, sx + dx, sy + dy); @@ -786,7 +855,6 @@ void draw_image_main(const bContext *C, ARegion *ar) if (sima->mode == SI_MODE_PAINT) draw_image_paint_helpers(C, ar, scene, zoomx, zoomy); - /* XXX integrate this code */ #if 0 if (ibuf) { @@ -812,5 +880,5 @@ void draw_image_main(const bContext *C, ARegion *ar) /* render info */ if (ima && show_render) - draw_render_info(scene, ima, ar); + draw_render_info(scene, ima, ar, zoomx, zoomy); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 0d0fdc6be1c..f1662bc254d 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -457,7 +457,7 @@ enum { static int image_view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event) { - if (event->type == MOUSEZOOM) { + if (event->type == MOUSEZOOM || event->type == MOUSEPAN) { SpaceImage *sima = CTX_wm_space_image(C); ARegion *ar = CTX_wm_region(C); float delta, factor, location[2]; @@ -1217,7 +1217,7 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima, simopts->im_format.imtype = R_IMF_IMTYPE_PNG; } else { - simopts->im_format.imtype = BKE_ftype_to_imtype(ibuf->ftype); + BKE_imbuf_to_image_format(&simopts->im_format, ibuf); } //simopts->subimtype = scene->r.subimtype; /* XXX - this is lame, we need to make these available too! */ simopts->im_format.quality = ibuf->ftype & 0xff; @@ -1434,7 +1434,7 @@ static int image_save_as_exec(bContext *C, wmOperator *op) static int image_save_as_check(bContext *UNUSED(C), wmOperator *op) { ImageFormatData *imf = op->customdata; - return WM_operator_filesel_ensure_ext_imtype(op, imf->imtype); + return WM_operator_filesel_ensure_ext_imtype(op, imf); } static int image_save_as_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) @@ -1559,6 +1559,7 @@ static int image_save_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); SaveImageOptions simopts; + save_image_options_defaults(&simopts); if (save_image_options_init(&simopts, sima, scene, FALSE) == 0) return OPERATOR_CANCELLED; save_image_options_from_op(&simopts, op); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index b0e9f8bcf99..9492e29734d 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -292,6 +292,7 @@ static void image_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_out", PADMINUS, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEZOOM, 0, 0, 0); + WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEPAN, 0, KM_CTRL, 0); /* ctrl now works as well, shift + numpad works as arrow keys on Windows */ RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 8.0f); diff --git a/source/blender/editors/space_info/info_intern.h b/source/blender/editors/space_info/info_intern.h index 80018e849d3..62e9a3a7f73 100644 --- a/source/blender/editors/space_info/info_intern.h +++ b/source/blender/editors/space_info/info_intern.h @@ -39,11 +39,15 @@ struct ReportList; void FILE_OT_pack_all(struct wmOperatorType *ot); void FILE_OT_unpack_all(struct wmOperatorType *ot); +void FILE_OT_pack_libraries(struct wmOperatorType *ot); +void FILE_OT_unpack_libraries(struct wmOperatorType *ot); + void FILE_OT_make_paths_relative(struct wmOperatorType *ot); void FILE_OT_make_paths_absolute(struct wmOperatorType *ot); void FILE_OT_report_missing_files(struct wmOperatorType *ot); void FILE_OT_find_missing_files(struct wmOperatorType *ot); + void INFO_OT_reports_display_update(struct wmOperatorType *ot); /* info_draw.c */ diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index e902a4ea6f4..104349e172a 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -66,15 +66,70 @@ #include "info_intern.h" +/********************* pack blend file libararies operator *********************/ + +static int pack_libraries_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + + packLibraries(bmain, op->reports); + + return OPERATOR_FINISHED; +} + +void FILE_OT_pack_libraries(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Pack Blender Libraries"; + ot->idname = "FILE_OT_pack_libraries"; + ot->description = "Pack all used Blender library files into the current .blend"; + + /* api callbacks */ + ot->exec = pack_libraries_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int unpack_libraries_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + + unpackLibraries(bmain, op->reports); + + return OPERATOR_FINISHED; +} + +static int unpack_libraries_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +{ + return WM_operator_confirm_message(C, op, "Unpack Blender Libraries - creates directories, all new paths should work"); +} + +void FILE_OT_unpack_libraries(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Unpack Blender Libraries"; + ot->idname = "FILE_OT_unpack_libraries"; + ot->description = "Unpack all used Blender library files from this .blend file"; + + /* api callbacks */ + ot->invoke = unpack_libraries_invoke; + ot->exec = unpack_libraries_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + /********************* pack all operator *********************/ static int pack_all_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - + packAll(bmain, op->reports); G.fileflags |= G_AUTOPACK; - + return OPERATOR_FINISHED; } @@ -83,7 +138,7 @@ static int pack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) Main *bmain = CTX_data_main(C); Image *ima; ImBuf *ibuf; - + // first check for dirty images for (ima = bmain->image.first; ima; ima = ima->id.next) { if (ima->ibufs.first) { /* XXX FIX */ @@ -93,16 +148,16 @@ static int pack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) BKE_image_release_ibuf(ima, ibuf, NULL); break; } - + BKE_image_release_ibuf(ima, ibuf, NULL); } } - + if (ima) { uiPupMenuOkee(C, "FILE_OT_pack_all", "Some images are painted on. These changes will be lost. Continue?"); return OPERATOR_CANCELLED; } - + return pack_all_exec(C, op); } @@ -116,11 +171,12 @@ void FILE_OT_pack_all(wmOperatorType *ot) /* api callbacks */ ot->exec = pack_all_exec; ot->invoke = pack_all_invoke; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + /********************* unpack all operator *********************/ static const EnumPropertyItem unpack_all_method_items[] = { diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 5e5e0c87feb..3f73fc2605a 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -39,6 +39,7 @@ #include "DNA_scene_types.h" #include "BLI_utildefines.h" +#include "BLI_math.h" #include "BKE_anim.h" #include "BKE_blender.h" @@ -47,6 +48,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_key.h" #include "BKE_mesh.h" +#include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_tessmesh.h" @@ -62,7 +64,7 @@ typedef struct SceneStats { int totbone, totbonesel; int totobj, totobjsel; int totlamp, totlampsel; - int tottri, totmesh, totcurve; + int tottri, totmesh; char infostr[512]; } SceneStats; @@ -74,7 +76,7 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) { /* we assume derivedmesh is already built, this strictly does stats now. */ DerivedMesh *dm = ob->derivedFinal; - int totvert, totedge, totface; + int totvert, totedge, totface, totloop; stats->totmesh += totob; @@ -82,10 +84,12 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); totface = dm->getNumPolys(dm); + totloop = dm->getNumLoops(dm); stats->totvert += totvert * totob; stats->totedge += totedge * totob; stats->totface += totface * totob; + stats->tottri += poly_to_tri_count(totface, totloop) * totob; if (sel) { stats->totvertsel += totvert; @@ -103,40 +107,23 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) case OB_SURF: case OB_CURVE: case OB_FONT: - { - int tot = 0, totf = 0; - - stats->totcurve += totob; - - if (ob->disp.first) - BKE_displist_count(&ob->disp, &tot, &totf); - - tot *= totob; - totf *= totob; - - stats->totvert += tot; - stats->totface += totf; - - if (sel) { - stats->totvertsel += tot; - stats->totfacesel += totf; - } - break; - } case OB_MBALL: { - int tot = 0, totf = 0; + int totv = 0, totf = 0, tottri = 0; - BKE_displist_count(&ob->disp, &tot, &totf); + if (ob->disp.first) + BKE_displist_count(&ob->disp, &totv, &totf, &tottri); - tot *= totob; - totf *= totob; + totv *= totob; + totf *= totob; + tottri *= totob; - stats->totvert += tot; + stats->totvert += totv; stats->totface += totf; + stats->tottri += tottri; if (sel) { - stats->totvertsel += tot; + stats->totvertsel += totv; stats->totfacesel += totf; } break; @@ -260,6 +247,12 @@ static void stats_object_pose(Object *ob, SceneStats *stats) } } +static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats) +{ + stats->totvert = ob->sculpt->bm->totvert; + stats->tottri = ob->sculpt->bm->totface; +} + static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) { if (base->flag & SELECT) stats->totobjsel++; @@ -319,6 +312,12 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) } } +static int stats_is_object_dynamic_topology_sculpt(Object *ob) +{ + return (ob && (ob->mode & OB_MODE_SCULPT) && + ob->sculpt && ob->sculpt->bm); +} + /* Statistics displayed in info header. Called regularly on scene changes. */ static void stats_update(Scene *scene) { @@ -334,6 +333,10 @@ static void stats_update(Scene *scene) /* Pose Mode */ stats_object_pose(ob, &stats); } + else if (stats_is_object_dynamic_topology_sculpt(ob)) { + /* Dynamic-topology sculpt mode */ + stats_object_sculpt_dynamic_topology(ob, &stats); + } else { /* Objects */ for (base = scene->base.first; base; base = base->next) @@ -388,9 +391,12 @@ static void stats_string(Scene *scene) s += sprintf(s, "Bones:%d/%d %s", stats->totbonesel, stats->totbone, memstr); } + else if (stats_is_object_dynamic_topology_sculpt(ob)) { + s += sprintf(s, "Verts:%d | Tris:%d", stats->totvert, stats->tottri); + } else { - s += sprintf(s, "Verts:%d | Faces:%d | Objects:%d/%d | Lamps:%d/%d%s", - stats->totvert, stats->totface, stats->totobjsel, stats->totobj, stats->totlampsel, stats->totlamp, memstr); + s += sprintf(s, "Verts:%d | Faces:%d| Tris:%d | Objects:%d/%d | Lamps:%d/%d%s", + stats->totvert, stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel, stats->totlamp, memstr); } if (ob) diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c index db9be22eedb..60b04f7b029 100644 --- a/source/blender/editors/space_info/space_info.c +++ b/source/blender/editors/space_info/space_info.c @@ -178,7 +178,10 @@ static void info_main_area_draw(const bContext *C, ARegion *ar) static void info_operatortypes(void) { WM_operatortype_append(FILE_OT_pack_all); + WM_operatortype_append(FILE_OT_pack_libraries); WM_operatortype_append(FILE_OT_unpack_all); + WM_operatortype_append(FILE_OT_unpack_libraries); + WM_operatortype_append(FILE_OT_make_paths_relative); WM_operatortype_append(FILE_OT_make_paths_absolute); WM_operatortype_append(FILE_OT_report_missing_files); diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 00745062582..a7599f21ad5 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -1006,7 +1006,7 @@ static void draw_sensor_actuator(uiLayout *layout, PointerRNA *ptr) static void draw_sensor_armature(uiLayout *layout, PointerRNA *ptr) { - bSensor *sens = (bSensor*)ptr->data; + bSensor *sens = (bSensor *)ptr->data; bArmatureSensor *as = (bArmatureSensor *) sens->data; Object *ob = (Object *)ptr->id.data; PointerRNA pose_ptr, pchan_ptr; @@ -1476,7 +1476,7 @@ static void draw_actuator_action(uiLayout *layout, PointerRNA *ptr) static void draw_actuator_armature(uiLayout *layout, PointerRNA *ptr) { - bActuator *act = (bActuator*)ptr->data; + bActuator *act = (bActuator *)ptr->data; bArmatureActuator *aa = (bArmatureActuator *) act->data; Object *ob = (Object *)ptr->id.data; bConstraint *constraint = NULL; diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c index 4cd53215697..8795d655e77 100644 --- a/source/blender/editors/space_logic/space_logic.c +++ b/source/blender/editors/space_logic/space_logic.c @@ -148,7 +148,7 @@ static SpaceLink *logic_new(const bContext *C) /* not spacelink itself */ static void logic_free(SpaceLink *UNUSED(sl)) { -// Spacelogic *slogic= (SpaceLogic*) sl; +// Spacelogic *slogic= (SpaceLogic *) sl; // if (slogic->gpd) // XXX BKE_gpencil_free(slogic->gpd); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 59dd66a0207..8797cb4a459 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -399,8 +399,8 @@ static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - bNodeTree *ntree = (bNodeTree*)ptr->id.data; - bNode *node = (bNode*)ptr->data; + bNodeTree *ntree = (bNodeTree *)ptr->id.data; + bNode *node = (bNode *)ptr->data; bNodeSocket *sock = node->outputs.first; /* first socket stores normal */ PointerRNA sockptr; @@ -2152,12 +2152,12 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C active_index = RNA_int_get(ptr, "active_input_index"); /* using different collection properties if multilayer format is enabled */ if (multilayer) { - uiTemplateList(col, C, ptr, "layer_slots", ptr, "active_input_index", NULL, 0, 0, 0); + uiTemplateList(col, C, "UI_UL_list", "", ptr, "layer_slots", ptr, "active_input_index", 0, 0, 0); RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr); } else { - uiTemplateList(col, C, ptr, "file_slots", ptr, "active_input_index", NULL, 0, 0, 0); + uiTemplateList(col, C, "UI_UL_list", "", ptr, "file_slots", ptr, "active_input_index", 0, 0, 0); RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr); } diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index f386657c460..492ff0dcbd4 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -69,12 +69,15 @@ static int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, cons bNode *node; rctf cur_new; float oldwidth, oldheight, width, height; + float oldasp, asp; int tot = 0; int has_frame = FALSE; oldwidth = BLI_rctf_size_x(&ar->v2d.cur); oldheight = BLI_rctf_size_y(&ar->v2d.cur); + oldasp = oldwidth / oldheight; + BLI_rctf_init_minmax(&cur_new); if (snode->edittree) { @@ -93,6 +96,7 @@ static int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, cons if (tot) { width = BLI_rctf_size_x(&cur_new); height = BLI_rctf_size_y(&cur_new); + asp = width / height; /* for single non-frame nodes, don't zoom in, just pan view, * but do allow zooming out, this allows for big nodes to be zoomed out */ @@ -104,17 +108,15 @@ static int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, cons BLI_rctf_resize(&cur_new, oldwidth, oldheight); } else { - if (width > height) { - float newheight; - newheight = oldheight * width / oldwidth; - cur_new.ymin = cur_new.ymin - newheight / 4; - cur_new.ymax = cur_new.ymax + newheight / 4; + if (oldasp < asp) { + const float height_new = width / oldasp; + cur_new.ymin = cur_new.ymin - height_new / 2.0f; + cur_new.ymax = cur_new.ymax + height_new / 2.0f; } else { - float newwidth; - newwidth = oldwidth * height / oldheight; - cur_new.xmin = cur_new.xmin - newwidth / 4; - cur_new.xmax = cur_new.xmax + newwidth / 4; + const float width_new = height * oldasp; + cur_new.xmin = cur_new.xmin - width_new / 2.0f; + cur_new.xmax = cur_new.xmax + width_new / 2.0f; } } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 6913ebc8a11..1a058104c78 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -421,17 +421,17 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_VIEW_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &ptr, "hide", -1, 0, 0, -1, -1, NULL); uiButSetFunc(bt, restrictbutton_view_cb, scene, ob); bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_SELECT_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &ptr, "hide_select", -1, 0, 0, -1, -1, NULL); uiButSetFunc(bt, restrictbutton_sel_cb, scene, ob); bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_RENDER_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &ptr, "hide_render", -1, 0, 0, -1, -1, NULL); uiButSetFunc(bt, restrictbutton_rend_cb, scene, ob); @@ -445,15 +445,21 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); restrict_bool = group_restrict_flag(gr, OB_RESTRICT_VIEW); - bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF, (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); + bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); uiButSetFunc(bt, restrictbutton_gr_restrict_view, scene, gr); restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT); - bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF, (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); + bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); uiButSetFunc(bt, restrictbutton_gr_restrict_select, scene, gr); restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER); - bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF, (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Restrict/Allow renderability"); + bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, "Restrict/Allow renderability"); uiButSetFunc(bt, restrictbutton_gr_restrict_render, scene, gr); uiBlockSetEmboss(block, UI_EMBOSS); @@ -463,7 +469,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOGN, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, te->directdata, 0, 0, 0, 0, "Render this RenderLayer"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + te->directdata, 0, 0, 0, 0, "Render this RenderLayer"); uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL); uiBlockSetEmboss(block, UI_EMBOSS); @@ -476,13 +483,18 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar bt = uiDefIconButBitI(block, ICONTOG, passflag, 0, ICON_CHECKBOX_HLT - 1, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, layflag, 0, 0, 0, 0, "Render this Pass"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + layflag, 0, 0, 0, 0, "Render this Pass"); uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL); layflag++; /* is lay_xor */ - if (ELEM8(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT, SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT)) + if (ELEM8(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT, + SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT)) + { bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, layflag, 0, 0, 0, 0, "Exclude this Pass from Combined"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + layflag, 0, 0, 0, 0, "Exclude this Pass from Combined"); + } uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL); uiBlockSetEmboss(block, UI_EMBOSS); @@ -493,11 +505,13 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(md->mode), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob); bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability"); uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob); } else if (tselem->type == TSE_POSE_CHANNEL) { @@ -506,11 +520,13 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); uiButSetFunc(bt, restrictbutton_bone_cb, NULL, bone); bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(bone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); uiButSetFunc(bt, restrictbutton_bone_cb, NULL, NULL); } else if (tselem->type == TSE_EBONE) { @@ -518,11 +534,13 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); uiButSetFunc(bt, restrictbutton_ebone_cb, NULL, ebone); bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); uiButSetFunc(bt, restrictbutton_ebone_cb, NULL, NULL); } } @@ -535,7 +553,7 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex) { View2D *v2d = &ar->v2d; - float miny = v2d->cur.ymin - V2D_SCROLL_HEIGHT; + float miny = v2d->cur.ymin; if (miny < v2d->tot.ymin) miny = v2d->tot.ymin; UI_ThemeColorShadeAlpha(TH_BACK, -15, -200); @@ -832,7 +850,7 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo /* rna property */ if (kmi->ptr && kmi->ptr->data) { - uiDefBut(block, LABEL, 0, "(RNA property)", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->oskey, 0, 0, 0, 0, ""); xstart += butw2; + uiDefBut(block, LABEL, 0, "(RNA property)", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, NULL, 0, 0, 0, 0, ""); xstart += butw2; } (void)xstart; @@ -1515,13 +1533,13 @@ static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase * /* selection status */ if (TSELEM_OPEN(tselem, soops)) if (tselem->type == TSE_RNA_STRUCT) - glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, *starty + UI_UNIT_Y - 1); + glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); *starty -= UI_UNIT_Y; if (TSELEM_OPEN(tselem, soops)) { outliner_draw_struct_marks(ar, soops, &te->subtree, starty); if (tselem->type == TSE_RNA_STRUCT) - fdrawline(0, (float)*starty + UI_UNIT_Y, ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, (float)*starty + UI_UNIT_Y); + fdrawline(0, (float)*starty + UI_UNIT_Y, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y); } } } @@ -1590,7 +1608,7 @@ static void outliner_back(ARegion *ar) ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) { - glRecti(0, ystart, (int)ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, ystart + UI_UNIT_Y); + glRecti(0, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y); ystart -= 2 * UI_UNIT_Y; } } @@ -1601,10 +1619,8 @@ static void outliner_draw_restrictcols(ARegion *ar) /* background underneath */ UI_ThemeColor(TH_BACK); - glRecti((int)ar->v2d.cur.xmax - OL_TOGW, - (int)ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT - 1, - (int)ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, - (int)ar->v2d.cur.ymax); + glRecti((int)(ar->v2d.cur.xmax - OL_TOGW), + (int)(ar->v2d.cur.ymin - 1), (int)ar->v2d.cur.xmax, (int)ar->v2d.cur.ymax); UI_ThemeColorShade(TH_BACK, 6); ystart = (int)ar->v2d.tot.ymax; @@ -1618,22 +1634,22 @@ static void outliner_draw_restrictcols(ARegion *ar) UI_ThemeColorShadeAlpha(TH_BACK, -15, -200); /* view */ - fdrawline(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, - ar->v2d.cur.ymax, - ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, - ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT); + sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + (int)ar->v2d.cur.ymax, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + (int)ar->v2d.cur.ymin); /* render */ - fdrawline(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, - ar->v2d.cur.ymax, - ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, - ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT); + sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + (int)ar->v2d.cur.ymax, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + (int)ar->v2d.cur.ymin); /* render */ - fdrawline(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, - ar->v2d.cur.ymax, - ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, - ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT); + sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + (int)ar->v2d.cur.ymax, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + (int)ar->v2d.cur.ymin); } /* ****************************************************** */ @@ -1682,11 +1698,9 @@ void draw_outliner(const bContext *C) // XXX this isn't that great yet... if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) sizex += OL_TOGW * 3; + } - /* tweak to display last line (when list bigger than window) */ - sizey += V2D_SCROLL_HEIGHT; - /* adds vertical offset */ sizey += OL_Y_OFFSET; diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index f9fca378568..63452de18d0 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -116,8 +116,8 @@ typedef struct TreeElement { /* size constants */ #define OL_Y_OFFSET 2 -#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 3) -#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2) +#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 3.0f) +#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2.0f) #define OL_TOG_RESTRICT_RENDERX UI_UNIT_X #define OL_TOGW OL_TOG_RESTRICT_VIEWX diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index ddbc49bf995..f723fbedc7b 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -803,8 +803,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i } /* One exception */ - if (type == TSE_ID_BASE); - else if (id == NULL) return NULL; + if (type == TSE_ID_BASE) { + /* pass */ + } + else if (id == NULL) { + return NULL; + } te = MEM_callocN(sizeof(TreeElement), "tree elem"); /* add to the visual tree */ @@ -832,7 +836,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i /* pass */ } else { - te->name = id->name + 2; // default, can be overridden by Library or non-ID data + /* do here too, for blend file viewer, own ID_LI then shows file name */ + if (GS(id->name) == ID_LI) + te->name = ((Library *)id)->name; + else + te->name = id->name + 2; // default, can be overridden by Library or non-ID data te->idcode = GS(id->name); } @@ -840,7 +848,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; /* ID datablock */ - if (tsepar==NULL || tsepar->type != TSE_ID_BASE) + if (tsepar == NULL || tsepar->type != TSE_ID_BASE) outliner_add_id_contents(soops, te, tselem, id); } else if (type == TSE_ANIM_DATA) { @@ -1511,7 +1519,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) } /* make hierarchy */ ten = soops->tree.first; - ten= ten->next; /* first one is main */ + ten = ten->next; /* first one is main */ while (ten) { TreeElement *nten = ten->next, *par; tselem = TREESTORE(ten); diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index ecc09a35670..4bf88376b74 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -67,6 +67,17 @@ static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar) ListBase *lb; wmKeyMap *keymap; + /* make sure we keep the hide flags */ + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); + ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP); /* prevent any noise of past */ + ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; + ar->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE; + + ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); + ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); + ar->v2d.keeptot = V2D_KEEPTOT_STRICT; + ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f; + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ @@ -410,12 +421,6 @@ static SpaceLink *outliner_new(const bContext *UNUSED(C)) BLI_addtail(&soutliner->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; - ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM_O); - ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); - ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); - ar->v2d.keeptot = V2D_KEEPTOT_STRICT; - ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f; - return (SpaceLink *)soutliner; } diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 6219a9061f4..29a6a1f6d50 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -49,6 +49,8 @@ #include "DNA_mask_types.h" #include "DNA_userdef_types.h" +#include "BLF_translation.h" + #include "BKE_context.h" #include "BKE_global.h" #include "BKE_library.h" @@ -400,6 +402,7 @@ void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot) sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME); prop = RNA_def_enum(ot->srna, "clip", DummyRNA_NULL_items, 0, "Clip", ""); RNA_def_enum_funcs(prop, RNA_movieclip_itemf); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_MOVIECLIP); ot->prop = prop; } @@ -871,7 +874,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) if (BKE_sequence_test_overlap(ed->seqbasep, seq)) BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); } - BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* runs calc_sequence */ + BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* runs BKE_sequence_calc */ /* not sure if this is needed with update_changed_seq_and_deps. diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 409f655bb79..c6c70ccb424 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -925,7 +925,7 @@ static void set_filter_seq(Scene *scene) if (seq->type == SEQ_TYPE_MOVIE) { seq->flag |= SEQ_FILTERY; reload_sequence_new_file(scene, seq, FALSE); - calc_sequence(scene, seq); + BKE_sequence_calc(scene, seq); } } @@ -1906,6 +1906,9 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) for (seq = ed->seqbasep->first; seq; seq = seq->next) BKE_sequence_calc(scene, seq); + if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq)) + BKE_sequence_base_shuffle(ed->seqbasep, ms->parseq, scene); + BKE_sequencer_active_set(scene, ms->parseq); ms->parseq->flag |= SELECT; diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt index 6aaf4212779..a33a9abada1 100644 --- a/source/blender/editors/space_text/CMakeLists.txt +++ b/source/blender/editors/space_text/CMakeLists.txt @@ -36,12 +36,13 @@ set(INC_SYS set(SRC space_text.c + text_autocomplete.c text_draw.c text_format.c + text_format_osl.c text_format_py.c text_header.c text_ops.c - text_python.c text_format.h text_intern.h diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index 9ac66ca1698..fa3eefcc0f7 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -223,6 +223,8 @@ static void text_operatortypes(void) WM_operatortype_append(TEXT_OT_to_3d_object); WM_operatortype_append(TEXT_OT_resolve_conflict); + + WM_operatortype_append(TEXT_OT_autocomplete); } static void text_keymap(struct wmKeyConfig *keyconf) @@ -276,7 +278,7 @@ static void text_keymap(struct wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", PADMINUS, KM_PRESS, KM_CTRL, 0); RNA_string_set(kmi->ptr, "data_path", "space_data.font_size"); RNA_boolean_set(kmi->ptr, "reverse", TRUE); - + WM_keymap_add_item(keymap, "TEXT_OT_new", NKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "TEXT_OT_open", OKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "TEXT_OT_reload", RKEY, KM_PRESS, KM_ALT, 0); @@ -375,6 +377,8 @@ static void text_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "TEXT_OT_line_break", PADENTER, KM_PRESS, 0, 0); WM_keymap_add_menu(keymap, "TEXT_MT_toolbox", RIGHTMOUSE, KM_PRESS, KM_ANY, 0); + + WM_keymap_add_item(keymap, "TEXT_OT_autocomplete", SPACEKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "TEXT_OT_line_number", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); WM_keymap_add_item(keymap, "TEXT_OT_insert", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); // last! @@ -555,5 +559,6 @@ void ED_spacetype_text(void) /* register formatters */ ED_text_format_register_py(); + ED_text_format_register_osl(); } diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c new file mode 100644 index 00000000000..e406a1b7166 --- /dev/null +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -0,0 +1,541 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_text/text_autocomplete.c + * \ingroup sptext + */ + +#include <ctype.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_text_types.h" + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" + +#include "BKE_context.h" +#include "BKE_text.h" +#include "BKE_screen.h" +#include "BKE_suggestions.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "UI_interface.h" + +#include "text_format.h" +#include "text_intern.h" /* own include */ + + +/* -------------------------------------------------------------------- */ +/* Public API */ + +int text_do_suggest_select(SpaceText *st, ARegion *ar) +{ + SuggItem *item, *first, *last /* , *sel */ /* UNUSED */; + TextLine *tmp; + int l, x, y, w, h, i; + int tgti, *top; + int mval[2] = {0, 0}; + + if (!st || !st->text) return 0; + if (!texttool_text_is_active(st->text)) return 0; + + first = texttool_suggest_first(); + last = texttool_suggest_last(); + /* sel = texttool_suggest_selected(); */ /* UNUSED */ + top = texttool_suggest_top(); + + if (!last || !first) + return 0; + + /* Count the visible lines to the cursor */ + for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ; + if (l < 0) return 0; + + text_update_character_width(st); + + if (st->showlinenrs) { + x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET + TEXTXLOC - 4; + } + else { + x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4; + } + y = ar->winy - st->lheight_dpi * l - 2; + + w = SUGG_LIST_WIDTH * st->cwidth + U.widget_unit; + h = SUGG_LIST_SIZE * st->lheight_dpi + 0.4f * U.widget_unit; + + // XXX getmouseco_areawin(mval); + + if (mval[0] < x || x + w < mval[0] || mval[1] < y - h || y < mval[1]) + return 0; + + /* Work out which of the items is at the top of the visible list */ + for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ; + + /* Work out the target item index in the visible list */ + tgti = (y - mval[1] - 4) / st->lheight_dpi; + if (tgti < 0 || tgti > SUGG_LIST_SIZE) + return 1; + + for (i = tgti; i > 0 && item->next; i--, item = item->next) ; + if (item) + texttool_suggest_select(item); + return 1; +} + +void text_pop_suggest_list(void) +{ + SuggItem *item, *sel; + int *top, i; + + item = texttool_suggest_first(); + sel = texttool_suggest_selected(); + top = texttool_suggest_top(); + + i = 0; + while (item && item != sel) { + item = item->next; + i++; + } + if (i > *top + SUGG_LIST_SIZE - 1) + *top = i - SUGG_LIST_SIZE + 1; + else if (i < *top) + *top = i; +} + +/* -------------------------------------------------------------------- */ +/* Private API */ + +static void text_autocomplete_free(bContext *C, wmOperator *op); + +static GHash *text_autocomplete_build(Text *text) +{ + GHash *gh; + int seek_len = 0; + const char *seek; + texttool_text_clear(); + + texttool_text_set_active(text); + + /* first get the word we're at */ + { + const int i = text_find_identifier_start(text->curl->line, text->curc); + seek_len = text->curc - i; + seek = text->curl->line + i; + + // BLI_strncpy(seek, seek_ptr, seek_len); + } + + /* now walk over entire doc and suggest words */ + { + TextLine *linep; + + gh = BLI_ghash_str_new(__func__); + + for (linep = text->lines.first; linep; linep = linep->next) { + int i_start = 0; + int i_end = 0; + + while (i_start < linep->len) { + /* seek identifier beginning */ + while (i_start < linep->len && !text_check_identifier(linep->line[i_start])) { + i_start++; + } + i_end = i_start; + while (i_end < linep->len && text_check_identifier(linep->line[i_end])) { + i_end++; + } + + if (i_start != i_end) { + char *str_sub = &linep->line[i_start]; + const int choice_len = i_end - i_start; + + if ((choice_len > seek_len) && + (seek_len == 0 || strncmp(seek, str_sub, seek_len) == 0) && + (seek != str_sub)) + { + // printf("Adding: %s\n", s); + char str_sub_last = str_sub[choice_len]; + str_sub[choice_len] = '\0'; + if (!BLI_ghash_lookup(gh, str_sub)) { + char *str_dup = BLI_strdupn(str_sub, choice_len); + BLI_ghash_insert(gh, str_dup, str_dup); /* A 'set' would make more sense here */ + } + str_sub[choice_len] = str_sub_last; + } + } + i_start = i_end; + } + } + + { + GHashIterator *iter = BLI_ghashIterator_new(gh); + + /* get the formatter for highlighting */ + TextFormatType *tft; + tft = ED_text_format_get(text); + + for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) { + const char *s = BLI_ghashIterator_getValue(iter); + texttool_suggest_add(s, tft->format_identifier(s)); + } + BLI_ghashIterator_free(iter); + + } + } + + texttool_suggest_prefix(seek, seek_len); + + return gh; +} + +/* -- */ + +static void get_suggest_prefix(Text *text, int offset) +{ + int i, len; + char *line; + + if (!text) return; + if (!texttool_text_is_active(text)) return; + + line = text->curl->line; + i = text_find_identifier_start(line, text->curc + offset); + len = text->curc - i + offset; + texttool_suggest_prefix(line + i, len); +} + +static void confirm_suggestion(Text *text) +{ + SuggItem *sel; + int i, over = 0; + const char *line; + + if (!text) return; + if (!texttool_text_is_active(text)) return; + + sel = texttool_suggest_selected(); + if (!sel) return; + + line = text->curl->line; + i = text_find_identifier_start(line, text->curc /* - skipleft */); + over = text->curc - i; + +// for (i = 0; i < skipleft; i++) +// txt_move_left(text, 0); + for (i = 0; i < over; i++) + txt_move_left(text, 1); + + txt_insert_buf(text, sel->name); + +// for (i = 0; i < skipleft; i++) +// txt_move_right(text, 0); + + texttool_text_clear(); +} + +/* -- */ + + +static int text_autocomplete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +{ + SpaceText *st = CTX_wm_space_text(C); + Text *text = CTX_data_edit_text(C); + + st->doplugins = TRUE; + op->customdata = text_autocomplete_build(text); + + if (texttool_suggest_first()) { + + ED_area_tag_redraw(CTX_wm_area(C)); + + if (texttool_suggest_first() == texttool_suggest_last()) { + confirm_suggestion(st->text); + text_update_line_edited(st->text->curl); + text_autocomplete_free(C, op); + return OPERATOR_FINISHED; + } + else { + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; + } + } + else { + text_autocomplete_free(C, op); + return OPERATOR_CANCELLED; + } +} + +static int doc_scroll = 0; + +static int text_autocomplete_modal(bContext *C, wmOperator *op, wmEvent *event) +{ + SpaceText *st = CTX_wm_space_text(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + + int draw = 0, tools = 0, swallow = 0, scroll = 1; + Text *text = CTX_data_edit_text(C); + int retval = OPERATOR_RUNNING_MODAL; + + (void)text; + + if (st->doplugins && texttool_text_is_active(st->text)) { + if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST; + if (texttool_docs_get()) tools |= TOOL_DOCUMENT; + } + + switch (event->type) { + case LEFTMOUSE: + if (event->val == KM_PRESS) { + if (text_do_suggest_select(st, ar)) + swallow = 1; + else { + if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; + retval = OPERATOR_FINISHED; + } + draw = 1; + } + break; + case MIDDLEMOUSE: + if (event->val == KM_PRESS) { + if (text_do_suggest_select(st, ar)) { + confirm_suggestion(st->text); + text_update_line_edited(st->text->curl); + swallow = 1; + } + else { + if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; + retval = OPERATOR_FINISHED; + } + draw = 1; + } + break; + case ESCKEY: + if (event->val == KM_PRESS) { + draw = swallow = 1; + if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); + else if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; + else draw = swallow = 0; + retval = OPERATOR_CANCELLED; + } + break; + case RETKEY: + if (event->val == KM_PRESS) { + if (tools & TOOL_SUGG_LIST) { + confirm_suggestion(st->text); + text_update_line_edited(st->text->curl); + swallow = 1; + draw = 1; + } + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1; + retval = OPERATOR_FINISHED; + } + break; + case LEFTARROWKEY: + case BACKSPACEKEY: + if (event->val == KM_PRESS) { + if (tools & TOOL_SUGG_LIST) { + if (event->ctrl) { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + else { + /* Work out which char we are about to delete/pass */ + if (st->text->curl && st->text->curc > 0) { + char ch = st->text->curl->line[st->text->curc - 1]; + if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) { + get_suggest_prefix(st->text, -1); + text_pop_suggest_list(); + } + else { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + } + else { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + } + } + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; + } + break; + case RIGHTARROWKEY: + if (event->val == KM_PRESS) { + if (tools & TOOL_SUGG_LIST) { + if (event->ctrl) { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + else { + /* Work out which char we are about to pass */ + if (st->text->curl && st->text->curc < st->text->curl->len) { + char ch = st->text->curl->line[st->text->curc + 1]; + if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) { + get_suggest_prefix(st->text, 1); + text_pop_suggest_list(); + } + else { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + } + else { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + } + } + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; + } + break; + case PAGEDOWNKEY: + scroll = SUGG_LIST_SIZE - 1; + case WHEELDOWNMOUSE: + case DOWNARROWKEY: + if (event->val == KM_PRESS) { + if (tools & TOOL_DOCUMENT) { + doc_scroll++; + swallow = 1; + draw = 1; + } + else if (tools & TOOL_SUGG_LIST) { + SuggItem *sel = texttool_suggest_selected(); + if (!sel) { + texttool_suggest_select(texttool_suggest_first()); + } + else { + while (sel && sel != texttool_suggest_last() && sel->next && scroll--) { + texttool_suggest_select(sel->next); + sel = sel->next; + } + } + text_pop_suggest_list(); + swallow = 1; + draw = 1; + } + } + break; + case PAGEUPKEY: + scroll = SUGG_LIST_SIZE - 1; + case WHEELUPMOUSE: + case UPARROWKEY: + if (event->val == KM_PRESS) { + if (tools & TOOL_DOCUMENT) { + if (doc_scroll > 0) doc_scroll--; + swallow = 1; + draw = 1; + } + else if (tools & TOOL_SUGG_LIST) { + SuggItem *sel = texttool_suggest_selected(); + while (sel && sel != texttool_suggest_first() && sel->prev && scroll--) { + texttool_suggest_select(sel->prev); + sel = sel->prev; + } + text_pop_suggest_list(); + swallow = 1; + draw = 1; + } + } + break; + case RIGHTSHIFTKEY: + case LEFTSHIFTKEY: + break; +#if 0 + default: + if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw = 1; + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1; +#endif + } + + if (draw) { + ED_area_tag_redraw(CTX_wm_area(C)); + } + +// if (swallow) { +// retval = OPERATOR_RUNNING_MODAL; +// } + + if (texttool_suggest_first()) { + if (retval != OPERATOR_RUNNING_MODAL) { + text_autocomplete_free(C, op); + } + return retval; + } + else { + text_autocomplete_free(C, op); + return OPERATOR_FINISHED; + } +} + +static void text_autocomplete_free(bContext *C, wmOperator *op) +{ + GHash *gh = op->customdata; + if (gh) { + BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); + op->customdata = NULL; + } + + /* other stuff */ + { + SpaceText *st = CTX_wm_space_text(C); + st->doplugins = FALSE; + texttool_text_clear(); + } +} + +static int text_autocomplete_cancel(bContext *C, wmOperator *op) +{ + text_autocomplete_free(C, op); + return OPERATOR_CANCELLED; +} + +void TEXT_OT_autocomplete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Text Auto Complete"; + ot->description = "Show a list of used text in the open document"; + ot->idname = "TEXT_OT_autocomplete"; + + /* api callbacks */ + ot->invoke = text_autocomplete_invoke; + ot->cancel = text_autocomplete_cancel; + ot->modal = text_autocomplete_modal; + ot->poll = text_space_edit_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING; +} diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 7d4c9e5af98..c264368e714 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -77,26 +77,17 @@ static int text_font_draw(SpaceText *UNUSED(st), int x, int y, const char *str) static int text_font_draw_character(SpaceText *st, int x, int y, char c) { - char str[2]; - str[0] = c; - str[1] = '\0'; - BLF_position(mono, x, y, 0); - BLF_draw(mono, str, 1); + BLF_draw(mono, &c, 1); return st->cwidth; } static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char *c) { - char str[BLI_UTF8_MAX + 1]; - size_t len = BLI_str_utf8_size_safe(c); - memcpy(str, c, len); - str[len] = '\0'; - + const size_t len = BLI_str_utf8_size_safe(c); BLF_position(mono, x, y, 0); - BLF_draw(mono, str, len); - + BLF_draw(mono, c, len); return st->cwidth; } @@ -117,27 +108,33 @@ static void txt_format_text(SpaceText *st) static void format_draw_color(char formatchar) { switch (formatchar) { - case '_': /* Whitespace */ + case FMT_TYPE_WHITESPACE: break; - case '!': /* Symbols */ - UI_ThemeColorBlend(TH_TEXT, TH_BACK, 0.5f); + case FMT_TYPE_SYMBOL: + UI_ThemeColor(TH_SYNTAX_S); break; - case '#': /* Comments */ + case FMT_TYPE_COMMENT: UI_ThemeColor(TH_SYNTAX_C); break; - case 'n': /* Numerals */ + case FMT_TYPE_NUMERAL: UI_ThemeColor(TH_SYNTAX_N); break; - case 'l': /* Strings */ + case FMT_TYPE_STRING: UI_ThemeColor(TH_SYNTAX_L); break; - case 'v': /* Specials: class, def */ + case FMT_TYPE_DIRECTIVE: + UI_ThemeColor(TH_SYNTAX_D); + break; + case FMT_TYPE_SPECIAL: UI_ThemeColor(TH_SYNTAX_V); break; - case 'b': /* Keywords: for, print, etc. */ + case FMT_TYPE_RESERVED: + UI_ThemeColor(TH_SYNTAX_R); + break; + case FMT_TYPE_KEYWORD: UI_ThemeColor(TH_SYNTAX_B); break; - case 'q': /* Other text (identifiers) */ + case FMT_TYPE_DEFAULT: default: UI_ThemeColor(TH_TEXT); break; @@ -359,6 +356,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w FlattenString fs; int basex, i, a, start, end, max, lines; /* view */ int mi, ma, mstart, mend; /* mem */ + char fmt_prev = 0xff; flatten_string(st, &fs, str); str = fs.buf; @@ -382,7 +380,9 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w /* Draw the visible portion of text on the overshot line */ for (a = start, ma = mstart; a < end; a++, ma += BLI_str_utf8_size_safe(str + ma)) { - if (st->showsyntax && format) format_draw_color(format[a]); + if (st->showsyntax && format) { + if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); + } x += text_font_draw_character_utf8(st, x, y, str + ma); } y -= st->lheight_dpi + TXT_LINE_SPACING; @@ -400,8 +400,9 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w /* Draw the remaining text */ for (a = start, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) { - if (st->showsyntax && format) - format_draw_color(format[a]); + if (st->showsyntax && format) { + if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); + } x += text_font_draw_character_utf8(st, x, y, str + ma); } @@ -432,15 +433,18 @@ static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int dra if (st->showsyntax && format) { int a, str_shift = 0; + char fmt_prev = 0xff; format = format + cshift; for (a = 0; a < amount; a++) { - format_draw_color(format[a]); + if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]); x += text_font_draw_character_utf8(st, x, y, in + str_shift); str_shift += BLI_str_utf8_size_safe(in + str_shift); } } - else text_font_draw(st, x, y, in); + else { + text_font_draw(st, x, y, in); + } } else { while (w-- && *acc++ < maxwidth) @@ -890,7 +894,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar) /* top = */ /* UNUSED */ y = ar->winy - st->lheight_dpi * l - 2; boxw = DOC_WIDTH * st->cwidth + 20; - boxh = (DOC_HEIGHT + 1) * st->lheight_dpi; + boxh = (DOC_HEIGHT + 1) * (st->lheight_dpi + TXT_LINE_SPACING); /* Draw panel */ UI_ThemeColor(TH_BACK); @@ -953,9 +957,11 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) SuggItem *item, *first, *last, *sel; TextLine *tmp; char str[SUGG_LIST_WIDTH + 1]; - int w, boxw = 0, boxh, i, l, x, y, b, *top; + int w, boxw = 0, boxh, i, l, x, y, *top; + const int lheight = st->lheight_dpi + TXT_LINE_SPACING; + const int margin_x = 2; - if (!st || !st->text) return; + if (!st->text) return; if (!texttool_text_is_active(st->text)) return; first = texttool_suggest_first(); @@ -977,14 +983,20 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) else { x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4; } - y = ar->winy - st->lheight_dpi * l - 2; + /* offset back so the start of the text lines up with the suggestions, + * not essential but makes suggestions easier to follow */ + x -= st->cwidth * (st->text->curc - text_find_identifier_start(st->text->curl->line, st->text->curc)); + y = ar->winy - lheight * l - 2; boxw = SUGG_LIST_WIDTH * st->cwidth + 20; - boxh = SUGG_LIST_SIZE * st->lheight_dpi + 8; + boxh = SUGG_LIST_SIZE * lheight + 8; + /* not needed but stands out nicer */ + uiDrawBoxShadow(220, x, y - boxh, x + boxw, y); + UI_ThemeColor(TH_SHADE1); glRecti(x - 1, y + 1, x + boxw + 1, y - boxh - 1); - UI_ThemeColor(TH_BACK); + UI_ThemeColorShade(TH_BACK, 16); glRecti(x, y, x + boxw, y - boxh); /* Set the top 'item' of the visible list */ @@ -992,7 +1004,7 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) for (i = 0; i < SUGG_LIST_SIZE && item; i++, item = item->next) { - y -= st->lheight_dpi; + y -= lheight; BLI_strncpy(str, item->name, SUGG_LIST_WIDTH); @@ -1000,21 +1012,11 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) if (item == sel) { UI_ThemeColor(TH_SHADE2); - glRecti(x + 16, y - 3, x + 16 + w, y + st->lheight_dpi - 3); + glRecti(x + margin_x, y - 3, x + margin_x + w, y + lheight - 3); } - b = 1; /* b=1 color block, text is default. b=0 no block, color text */ - switch (item->type) { - case 'k': UI_ThemeColor(TH_SYNTAX_B); b = 0; break; - case 'm': UI_ThemeColor(TH_TEXT); break; - case 'f': UI_ThemeColor(TH_SYNTAX_L); break; - case 'v': UI_ThemeColor(TH_SYNTAX_N); break; - case '?': UI_ThemeColor(TH_TEXT); b = 0; break; - } - if (b) { - glRecti(x + 8, y + 2, x + 11, y + 5); - UI_ThemeColor(TH_TEXT); - } - text_draw(st, str, 0, 0, 1, x + 16, y - 1, NULL); + + format_draw_color(item->type); + text_draw(st, str, 0, 0, 1, x + margin_x, y - 1, NULL); if (item == last) break; } @@ -1027,7 +1029,7 @@ static void draw_cursor(SpaceText *st, ARegion *ar) Text *text = st->text; int vcurl, vcurc, vsell, vselc, hidden = 0; int x, y, w, i; - int lheight = st->lheight_dpi + TXT_LINE_SPACING; + const int lheight = st->lheight_dpi + TXT_LINE_SPACING; /* Draw the selection */ if (text->curl != text->sell || text->curc != text->selc) { @@ -1168,7 +1170,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar) stack = 0; /* Don't highlight backets if syntax HL is off or bracket in string or comment. */ - if (!linep->format || linep->format[fc] == 'l' || linep->format[fc] == '#') + if (!linep->format || linep->format[fc] == FMT_TYPE_STRING || linep->format[fc] == FMT_TYPE_COMMENT) return; if (b > 0) { @@ -1177,7 +1179,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar) c += BLI_str_utf8_size_safe(linep->line + c); while (linep) { while (c < linep->len) { - if (linep->format && linep->format[fc] != 'l' && linep->format[fc] != '#') { + if (linep->format && linep->format[fc] != FMT_TYPE_STRING && linep->format[fc] != FMT_TYPE_COMMENT) { b = text_check_bracket(linep->line[c]); if (b == find) { if (stack == 0) { @@ -1206,7 +1208,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar) if (c > 0) c -= linep->line + c - BLI_str_prev_char_utf8(linep->line + c); while (linep) { while (fc >= 0) { - if (linep->format && linep->format[fc] != 'l' && linep->format[fc] != '#') { + if (linep->format && linep->format[fc] != FMT_TYPE_STRING && linep->format[fc] != FMT_TYPE_COMMENT) { b = text_check_bracket(linep->line[c]); if (b == find) { if (stack == 0) { @@ -1271,7 +1273,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar) void draw_text_main(SpaceText *st, ARegion *ar) { Text *text = st->text; - TextFormatType *tft = ED_text_format_get(text); + TextFormatType *tft; TextLine *tmp; rcti scroll, back; char linenr[12]; @@ -1299,6 +1301,7 @@ void draw_text_main(SpaceText *st, ARegion *ar) calc_text_rcts(st, ar, &scroll, &back); /* scroll will hold the entire bar size */ /* update syntax formatting if needed */ + tft = ED_text_format_get(text); tmp = text->lines.first; lineno = 0; for (i = 0; i < st->top && tmp; i++) { diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c index 0b3856f4414..294f94dd4b7 100644 --- a/source/blender/editors/space_text/text_format.c +++ b/source/blender/editors/space_text/text_format.c @@ -113,6 +113,14 @@ void flatten_string_free(FlattenString *fs) MEM_freeN(fs->accum); } +/* takes a string within fs->buf and returns its length */ +int flatten_string_strlen(FlattenString *fs, const char *str) +{ + const int len = (fs->pos - (int)(str - fs->buf)) - 1; + BLI_assert(strlen(str) == len); + return len; +} + /* Ensures the format string for the given line is long enough, reallocating * as needed. Allocation is done here, alone, to ensure consistency. */ int text_check_format_len(TextLine *line, unsigned int len) @@ -139,10 +147,16 @@ void ED_text_format_register(TextFormatType *tft) BLI_addtail(&tft_lb, tft); } -TextFormatType *ED_text_format_get(Text *UNUSED(text)) +TextFormatType *ED_text_format_get(Text *text) { /* NOTE: once more types are added we'll need to return some type based on 'text' * for now this function is more of a placeholder */ - return tft_lb.first; + /* XXX, wrong, but OK for testing */ + if (text && BLI_testextensie(text->id.name + 2, ".osl")) { + return tft_lb.last; + } + else { + return tft_lb.first; + } } diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h index 7b5b326db6a..e593e41d42c 100644 --- a/source/blender/editors/space_text/text_format.h +++ b/source/blender/editors/space_text/text_format.h @@ -41,8 +41,24 @@ typedef struct FlattenString { int pos, len; } FlattenString; +/* format continuation flags (stored just after the NULL terminator) */ +enum { + FMT_CONT_NOP = 0, /* no continuation */ + FMT_CONT_QUOTESINGLE = (1 << 0), /* single quotes */ + FMT_CONT_QUOTEDOUBLE = (1 << 1), /* double quotes */ + FMT_CONT_TRIPLE = (1 << 2), /* triplets of quotes: """ or ''' */ + FMT_CONT_QUOTESINGLE_TRIPLE = (FMT_CONT_TRIPLE | FMT_CONT_QUOTESINGLE), + FMT_CONT_QUOTEDOUBLE_TRIPLE = (FMT_CONT_TRIPLE | FMT_CONT_QUOTEDOUBLE), + FMT_CONT_COMMENT_C = (1 << 3), /* multi-line comments, OSL only (C style) */ + FMT_CONT_COMMENT_CXX = (1 << 4), /* single-line comments, OSL only (C++ style) */ +}; +#define FMT_CONT_ALL \ + (FMT_CONT_QUOTESINGLE | FMT_CONT_QUOTEDOUBLE | FMT_CONT_TRIPLE | FMT_CONT_COMMENT_C | FMT_CONT_COMMENT_CXX) + int flatten_string(struct SpaceText *st, FlattenString *fs, const char *in); void flatten_string_free(FlattenString *fs); +int flatten_string_strlen(FlattenString *fs, const char *str); + int text_check_format_len(TextLine *line, unsigned int len); @@ -50,28 +66,43 @@ int text_check_format_len(TextLine *line, unsigned int len); typedef struct TextFormatType { struct TextFormatType *next, *prev; + char (*format_identifier)(const char *string); + /* Formats the specified line. If do_next is set, the process will move on to * the succeeding line if it is affected (eg. multiline strings). Format strings * may contain any of the following characters: - * '_' Whitespace - * '#' Comment text - * '!' Punctuation and other symbols - * 'n' Numerals - * 'l' String letters - * 'v' Special variables (class, def) - * 'b' Built-in names (print, for, etc.) - * 'q' Other text (identifiers, etc.) + * * It is terminated with a null-terminator '\0' followed by a continuation - * flag indicating whether the line is part of a multi-line string. */ + * flag indicating whether the line is part of a multi-line string. + * + * See: FMT_TYPE_ enums below + */ void (*format_line)(SpaceText *st, TextLine *line, int do_next); const char **ext; /* NULL terminated extensions */ } TextFormatType; +enum { + FMT_TYPE_WHITESPACE = '_', /* Whitespace */ + FMT_TYPE_COMMENT = '#', /* Comment text */ + FMT_TYPE_SYMBOL = '!', /* Punctuation and other symbols */ + FMT_TYPE_NUMERAL = 'n', /* Numerals */ + FMT_TYPE_STRING = 'l', /* String letters */ + FMT_TYPE_DIRECTIVE = 'd', /* Decorator / Preprocessor directive */ + FMT_TYPE_SPECIAL = 'v', /* Special variables (class, def) */ + FMT_TYPE_RESERVED = 'r', /* Reserved keywords currently not in use, but still prohibited (OSL -> switch e.g.) */ + FMT_TYPE_KEYWORD = 'b', /* Built-in names (return, for, etc.) */ + FMT_TYPE_DEFAULT = 'q', /* Regular text (identifiers, etc.) */ +}; + TextFormatType *ED_text_format_get(Text *text); void ED_text_format_register(TextFormatType *tft); /* formatters */ void ED_text_format_register_py(void); +void ED_text_format_register_osl(void); + +#define STR_LITERAL_STARTSWITH(str, str_literal, len_var) \ + (strncmp(str, str_literal, len_var = (sizeof(str_literal) - 1)) == 0) #endif /* __TEXT_FORMAT_H__ */ diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c new file mode 100644 index 00000000000..3120e88163e --- /dev/null +++ b/source/blender/editors/space_text/text_format_osl.c @@ -0,0 +1,335 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_text/text_format_osl.c + * \ingroup sptext + */ + +#include <string.h> + +#include "BLI_blenlib.h" + +#include "DNA_text_types.h" +#include "DNA_space_types.h" + +#include "BKE_text.h" + +#include "text_format.h" + +/* *** Local Functions (for format_line) *** */ + +static int txtfmt_osl_find_builtinfunc(const char *string) +{ + int i, len; + /* list is from + * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf + */ + if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "closure", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "color", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "continue", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "do", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "emit", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "float", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "illuminance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "illuminate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "int", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "matrix", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "normal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "output", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "point", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "public", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "string", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "struct", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vector", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "void", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; + return i; +} + +static int txtfmt_osl_find_reserved(const char *string) +{ + int i, len; + /* list is from... + * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf + */ + if (STR_LITERAL_STARTSWITH(string, "bool", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "catch", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "char", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "const", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "delete", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "double", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "enum", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "extern", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "friend", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "goto", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "long", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "new", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "operator", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "private", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "protected", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "short", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "signed", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sizeof", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "static", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "template", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "this", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "throw", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "try", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "typedef", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uniform", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "union", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "unsigned", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "varying", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "virtual", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "volatile", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; + return i; +} + +/* Checks the specified source string for a OSL special name. This name must + * start at the beginning of the source string and must be followed by a non- + * identifier (see text_check_identifier(char)) or null character. + * + * If a special name is found, the length of the matching name is returned. + * Otherwise, -1 is returned. */ + +static int txtfmt_osl_find_specialvar(const char *string) +{ + int i, len; + + /* OSL shader types */ + if (STR_LITERAL_STARTSWITH(string, "shader", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "surface", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "volume", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; + return i; +} + +/* matches py 'txtfmt_osl_find_decorator' */ +static int txtfmt_osl_find_preprocessor(const char *string) +{ + if (string[0] == '#') { + int i = 1; + /* Whitespace is ok '# foo' */ + while (text_check_whitespace(string[i])) { + i++; + } + while (text_check_identifier(string[i])) { + i++; + } + return i; + } + return -1; +} + +static char txtfmt_osl_format_identifier(const char *str) +{ + char fmt; + if ((txtfmt_osl_find_specialvar(str)) != -1) fmt = FMT_TYPE_SPECIAL; + else if ((txtfmt_osl_find_builtinfunc(str)) != -1) fmt = FMT_TYPE_KEYWORD; + else if ((txtfmt_osl_find_reserved(str)) != -1) fmt = FMT_TYPE_RESERVED; + else if ((txtfmt_osl_find_preprocessor(str)) != -1) fmt = FMT_TYPE_DIRECTIVE; + else fmt = FMT_TYPE_DEFAULT; + return fmt; +} + +static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const int do_next) +{ + FlattenString fs; + const char *str; + char *fmt; + char cont_orig, cont, find, prev = ' '; + int len, i; + + /* Get continuation from previous line */ + if (line->prev && line->prev->format != NULL) { + fmt = line->prev->format; + cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + BLI_assert((FMT_CONT_ALL & cont) == cont); + } + else { + cont = FMT_CONT_NOP; + } + + /* Get original continuation from this line */ + if (line->format != NULL) { + fmt = line->format; + cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig); + } + else { + cont_orig = 0xFF; + } + + len = flatten_string(st, &fs, line->line); + str = fs.buf; + if (!text_check_format_len(line, len)) { + flatten_string_free(&fs); + return; + } + fmt = line->format; + + while (*str) { + /* Handle escape sequences by skipping both \ and next char */ + if (*str == '\\') { + *fmt = prev; fmt++; str++; + if (*str == '\0') break; + *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str); + continue; + } + /* Handle continuations */ + else if (cont) { + /* C-Style comments */ + if (cont & FMT_CONT_COMMENT_CXX) { + *fmt = FMT_TYPE_COMMENT; + } + else if (cont & FMT_CONT_COMMENT_C) { + if (*str == '*' && *(str + 1) == '/') { + *fmt = FMT_TYPE_COMMENT; fmt++; str++; + *fmt = FMT_TYPE_COMMENT; + cont = FMT_CONT_NOP; + } + else { + *fmt = FMT_TYPE_COMMENT; + } + /* Handle other comments */ + } + else { + find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\''; + if (*str == find) cont = 0; + *fmt = FMT_TYPE_STRING; + } + + str += BLI_str_utf8_size_safe(str) - 1; + } + /* Not in a string... */ + else { + /* Deal with comments first */ + if (*str == '/' && *(str + 1) == '/') { + cont = FMT_CONT_COMMENT_CXX; + *fmt = FMT_TYPE_COMMENT; + } + /* C-Style (multi-line) comments */ + else if (*str == '/' && *(str + 1) == '*') { + cont = FMT_CONT_COMMENT_C; + *fmt = FMT_TYPE_COMMENT; fmt++; str++; + *fmt = FMT_TYPE_COMMENT; + } + else if (*str == '"' || *str == '\'') { + /* Strings */ + find = *str; + cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE; + *fmt = FMT_TYPE_STRING; + } + /* Whitespace (all ws. has been converted to spaces) */ + else if (*str == ' ') { + *fmt = FMT_TYPE_WHITESPACE; + } + /* Numbers (digits not part of an identifier and periods followed by digits) */ + else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) || + (*str == '.' && text_check_digit(*(str + 1)))) + { + *fmt = FMT_TYPE_NUMERAL; + } + /* Punctuation */ + else if ((*str != '#') && text_check_delim(*str)) { + *fmt = FMT_TYPE_SYMBOL; + } + /* Identifiers and other text (no previous ws. or delims. so text continues) */ + else if (prev == FMT_TYPE_DEFAULT) { + str += BLI_str_utf8_size_safe(str) - 1; + *fmt = FMT_TYPE_DEFAULT; + } + /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */ + else { + /* Special vars(v) or built-in keywords(b) */ + /* keep in sync with 'txtfmt_osl_format_identifier()' */ + if ((i = txtfmt_osl_find_specialvar(str)) != -1) prev = FMT_TYPE_SPECIAL; + else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) prev = FMT_TYPE_KEYWORD; + else if ((i = txtfmt_osl_find_reserved(str)) != -1) prev = FMT_TYPE_RESERVED; + else if ((i = txtfmt_osl_find_preprocessor(str)) != -1) prev = FMT_TYPE_DIRECTIVE; + + if (i > 0) { + memset(fmt, prev, i); + i--; fmt += i; str += i; + } + else { + str += BLI_str_utf8_size_safe(str) - 1; + *fmt = FMT_TYPE_DEFAULT; + } + } + } + prev = *fmt; fmt++; str++; + } + + /* Terminate and add continuation char */ + *fmt = '\0'; fmt++; + *fmt = cont; + + /* If continuation has changed and we're allowed, process the next line */ + if (cont != cont_orig && do_next && line->next) { + txtfmt_osl_format_line(st, line->next, do_next); + } + + flatten_string_free(&fs); +} + +void ED_text_format_register_osl(void) +{ + static TextFormatType tft = {0}; + static const char *ext[] = {"osl", NULL}; + + tft.format_identifier = txtfmt_osl_format_identifier; + tft.format_line = txtfmt_osl_format_line; + tft.ext = ext; + + ED_text_format_register(&tft); +} diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c index 2a0f483d80c..cbccc6a770f 100644 --- a/source/blender/editors/space_text/text_format_py.c +++ b/source/blender/editors/space_text/text_format_py.c @@ -41,7 +41,6 @@ /* *** Local Functions (for format_line) *** */ - /* Checks the specified source string for a Python built-in function name. This * name must start at the beginning of the source string and must be followed by * a non-identifier (see text_check_identifier(char)) or null character. @@ -53,38 +52,53 @@ * http://docs.python.org/py3k/reference/lexical_analysis.html#keywords */ -static int txtfmt_py_find_builtinfunc(char *string) +static int txtfmt_py_find_builtinfunc(const char *string) { - int a, i; - const char *builtinfuncs[] = { - /* "False", "None", "True", */ /* see find_bool() */ - "and", "as", "assert", "break", - "class", "continue", "def", "del", "elif", "else", "except", - "finally", "for", "from", "global", "if", "import", "in", - "is", "lambda", "nonlocal", "not", "or", "pass", "raise", - "return", "try", "while", "with", "yield", - }; - - for (a = 0; a < sizeof(builtinfuncs) / sizeof(builtinfuncs[0]); a++) { - i = 0; - while (1) { - /* If we hit the end of a keyword... (eg. "def") */ - if (builtinfuncs[a][i] == '\0') { - /* If we still have identifier chars in the source (eg. "definate") */ - if (text_check_identifier(string[i])) - i = -1; /* No match */ - break; /* Next keyword if no match, otherwise we're done */ - - /* If chars mismatch, move on to next keyword */ - } - else if (string[i] != builtinfuncs[a][i]) { - i = -1; - break; /* Break inner loop, start next keyword */ - } - i++; - } - if (i > 0) break; /* If we have a match, we're done */ - } + int i, len; + /* list is from... + * ", ".join(['"%s"' % kw + * for kw in __import__("keyword").kwlist + * if kw not in {"False", "None", "True", "def", "class"}]) + * + * ... and for this code: + * print("\n".join(['else if (STR_LITERAL_STARTSWITH(string, "%s", len)) i = len;' % kw + * for kw in __import__("keyword").kwlist + * if kw not in {"False", "None", "True", "def", "class"}])) + */ + + if (STR_LITERAL_STARTSWITH(string, "and", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "as", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "assert", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "continue", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "del", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "elif", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "except", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "finally", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "from", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "global", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "import", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "in", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "is", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "nonlocal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "not", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "or", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pass", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "raise", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "try", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "with", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "yield", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; return i; } @@ -95,25 +109,28 @@ static int txtfmt_py_find_builtinfunc(char *string) * If a special name is found, the length of the matching name is returned. * Otherwise, -1 is returned. */ -static int txtfmt_py_find_specialvar(char *string) +static int txtfmt_py_find_specialvar(const char *string) { - int i = 0; - /* Check for "def" */ - if (string[0] == 'd' && string[1] == 'e' && string[2] == 'f') - i = 3; - /* Check for "class" */ - else if (string[0] == 'c' && string[1] == 'l' && string[2] == 'a' && string[3] == 's' && string[4] == 's') - i = 5; + int i, len; + + if (STR_LITERAL_STARTSWITH(string, "def", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "class", len)) i = len; + else i = 0; + /* If next source char is an identifier (eg. 'i' in "definate") no match */ if (i == 0 || text_check_identifier(string[i])) return -1; return i; } -static int txtfmt_py_find_decorator(char *string) +static int txtfmt_py_find_decorator(const char *string) { if (string[0] == '@') { int i = 1; + /* Whitespace is ok '@ foo' */ + while (text_check_whitespace(string[i])) { + i++; + } while (text_check_identifier(string[i])) { i++; } @@ -122,46 +139,57 @@ static int txtfmt_py_find_decorator(char *string) return -1; } -static int txtfmt_py_find_bool(char *string) +static int txtfmt_py_find_bool(const char *string) { - int i = 0; - /* Check for "False" */ - if (string[0] == 'F' && string[1] == 'a' && string[2] == 'l' && string[3] == 's' && string[4] == 'e') - i = 5; - /* Check for "True" */ - else if (string[0] == 'T' && string[1] == 'r' && string[2] == 'u' && string[3] == 'e') - i = 4; - /* Check for "None" */ - else if (string[0] == 'N' && string[1] == 'o' && string[2] == 'n' && string[3] == 'e') - i = 4; - /* If next source char is an identifier (eg. 'i' in "definate") no match */ + int i, len; + + if (STR_LITERAL_STARTSWITH(string, "None", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "True", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "False", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */ if (i == 0 || text_check_identifier(string[i])) return -1; return i; } -static void txtfmt_py_format_line(SpaceText *st, TextLine *line, int do_next) +static char txtfmt_py_format_identifier(const char *str) +{ + char fmt; + if ((txtfmt_py_find_specialvar(str)) != -1) fmt = FMT_TYPE_SPECIAL; + else if ((txtfmt_py_find_builtinfunc(str)) != -1) fmt = FMT_TYPE_KEYWORD; + else if ((txtfmt_py_find_decorator(str)) != -1) fmt = FMT_TYPE_RESERVED; + else fmt = FMT_TYPE_DEFAULT; + return fmt; +} + +static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const int do_next) { FlattenString fs; - char *str, *fmt, orig, cont, find, prev = ' '; + const char *str; + char *fmt; + char cont_orig, cont, find, prev = ' '; int len, i; /* Get continuation from previous line */ if (line->prev && line->prev->format != NULL) { fmt = line->prev->format; cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + BLI_assert((FMT_CONT_ALL & cont) == cont); } else { - cont = 0; + cont = FMT_CONT_NOP; } /* Get original continuation from this line */ if (line->format != NULL) { fmt = line->format; - orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig); } else { - orig = 0xFF; + cont_orig = 0xFF; } len = flatten_string(st, &fs, line->line); @@ -183,93 +211,90 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, int do_next) /* Handle continuations */ else if (cont) { /* Triple strings ("""...""" or '''...''') */ - if (cont & TXT_TRISTR) { - find = (cont & TXT_DBLQUOTSTR) ? '"' : '\''; + if (cont & FMT_CONT_TRIPLE) { + find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\''; if (*str == find && *(str + 1) == find && *(str + 2) == find) { - *fmt = 'l'; fmt++; str++; - *fmt = 'l'; fmt++; str++; - cont = 0; + *fmt = FMT_TYPE_STRING; fmt++; str++; + *fmt = FMT_TYPE_STRING; fmt++; str++; + cont = FMT_CONT_NOP; } /* Handle other strings */ } else { - find = (cont & TXT_DBLQUOTSTR) ? '"' : '\''; - if (*str == find) cont = 0; + find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\''; + if (*str == find) cont = FMT_CONT_NOP; } - *fmt = 'l'; + *fmt = FMT_TYPE_STRING; str += BLI_str_utf8_size_safe(str) - 1; } /* Not in a string... */ else { /* Deal with comments first */ - if (prev == '#' || *str == '#') { - *fmt = '#'; + if (prev == FMT_TYPE_COMMENT || *str == '#') { + *fmt = FMT_TYPE_COMMENT; str += BLI_str_utf8_size_safe(str) - 1; } else if (*str == '"' || *str == '\'') { /* Strings */ find = *str; - cont = (*str == '"') ? TXT_DBLQUOTSTR : TXT_SNGQUOTSTR; + cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE; if (*(str + 1) == find && *(str + 2) == find) { - *fmt = 'l'; fmt++; str++; - *fmt = 'l'; fmt++; str++; - cont |= TXT_TRISTR; + *fmt = FMT_TYPE_STRING; fmt++; str++; + *fmt = FMT_TYPE_STRING; fmt++; str++; + cont |= FMT_CONT_TRIPLE; } - *fmt = 'l'; + *fmt = FMT_TYPE_STRING; } /* Whitespace (all ws. has been converted to spaces) */ - else if (*str == ' ') - *fmt = '_'; + else if (*str == ' ') { + *fmt = FMT_TYPE_WHITESPACE; + } /* Numbers (digits not part of an identifier and periods followed by digits) */ - else if ((prev != 'q' && text_check_digit(*str)) || (*str == '.' && text_check_digit(*(str + 1)))) - *fmt = 'n'; + else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) || + (*str == '.' && text_check_digit(*(str + 1)))) + { + *fmt = FMT_TYPE_NUMERAL; + } /* Booleans */ - else if (prev != 'q' && (i = txtfmt_py_find_bool(str)) != -1) + else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_py_find_bool(str)) != -1) { if (i > 0) { - while (i > 1) { - *fmt = 'n'; fmt++; str++; - i--; - } - *fmt = 'n'; + memset(fmt, FMT_TYPE_NUMERAL, i); + i--; fmt += i; str += i; } else { str += BLI_str_utf8_size_safe(str) - 1; - *fmt = 'q'; + *fmt = FMT_TYPE_DEFAULT; } + } /* Punctuation */ - else if (text_check_delim(*str)) - *fmt = '!'; + else if ((*str != '@') && text_check_delim(*str)) { + *fmt = FMT_TYPE_SYMBOL; + } /* Identifiers and other text (no previous ws. or delims. so text continues) */ - else if (prev == 'q') { + else if (prev == FMT_TYPE_DEFAULT) { str += BLI_str_utf8_size_safe(str) - 1; - *fmt = 'q'; + *fmt = FMT_TYPE_DEFAULT; } /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */ else { /* Special vars(v) or built-in keywords(b) */ - if ((i = txtfmt_py_find_specialvar(str)) != -1) - prev = 'v'; - else if ((i = txtfmt_py_find_builtinfunc(str)) != -1) - prev = 'b'; - else if ((i = txtfmt_py_find_decorator(str)) != -1) - prev = 'v'; /* could have a new color for this */ + /* keep in sync with 'txtfmt_py_format_identifier()' */ + if ((i = txtfmt_py_find_specialvar(str)) != -1) prev = FMT_TYPE_SPECIAL; + else if ((i = txtfmt_py_find_builtinfunc(str)) != -1) prev = FMT_TYPE_KEYWORD; + else if ((i = txtfmt_py_find_decorator(str)) != -1) prev = FMT_TYPE_DIRECTIVE; + if (i > 0) { - while (i > 1) { - *fmt = prev; fmt++; str++; - i--; - } - *fmt = prev; + memset(fmt, prev, i); + i--; fmt += i; str += i; } else { str += BLI_str_utf8_size_safe(str) - 1; - *fmt = 'q'; + *fmt = FMT_TYPE_DEFAULT; } } } - prev = *fmt; - fmt++; - str++; + prev = *fmt; fmt++; str++; } /* Terminate and add continuation char */ @@ -277,7 +302,7 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, int do_next) *fmt = cont; /* If continuation has changed and we're allowed, process the next line */ - if (cont != orig && do_next && line->next) { + if (cont != cont_orig && do_next && line->next) { txtfmt_py_format_line(st, line->next, do_next); } @@ -289,7 +314,8 @@ void ED_text_format_register_py(void) static TextFormatType tft = {0}; static const char *ext[] = {"py", NULL}; - tft.format_line = txtfmt_py_format_line; + tft.format_identifier = txtfmt_py_format_identifier; + tft.format_line = txtfmt_py_format_line; tft.ext = ext; ED_text_format_register(&tft); diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h index c7f9512737f..799bc49b624 100644 --- a/source/blender/editors/space_text/text_intern.h +++ b/source/blender/editors/space_text/text_intern.h @@ -143,6 +143,11 @@ void TEXT_OT_to_3d_object(struct wmOperatorType *ot); void TEXT_OT_resolve_conflict(struct wmOperatorType *ot); +int text_space_edit_poll(struct bContext *C); + +/* text_autocomplete.c */ +void TEXT_OT_autocomplete(struct wmOperatorType *ot); + /* space_text.c */ extern const char *text_context_dir[]; /* doc access */ diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 01041c0e385..21966ef614c 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -98,7 +98,7 @@ static int text_edit_poll(bContext *C) return 1; } -static int text_space_edit_poll(bContext *C) +int text_space_edit_poll(bContext *C) { SpaceText *st = CTX_wm_space_text(C); Text *text = CTX_data_edit_text(C); @@ -1931,6 +1931,8 @@ static int text_jump_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) void TEXT_OT_jump(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Jump"; ot->idname = "TEXT_OT_jump"; @@ -1942,7 +1944,8 @@ void TEXT_OT_jump(wmOperatorType *ot) ot->poll = text_edit_poll; /* properties */ - RNA_def_int(ot->srna, "line", 1, 1, INT_MAX, "Line", "Line number to jump to", 1, 10000); + prop = RNA_def_int(ot->srna, "line", 1, 1, INT_MAX, "Line", "Line number to jump to", 1, 10000); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_TEXT); } /******************* delete operator **********************/ diff --git a/source/blender/editors/space_text/text_python.c b/source/blender/editors/space_text/text_python.c deleted file mode 100644 index 1201302dad0..00000000000 --- a/source/blender/editors/space_text/text_python.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2008 Blender Foundation. - * All rights reserved. - * - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_text/text_python.c - * \ingroup sptext - */ - -#include <ctype.h> - -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_text_types.h" -#include "DNA_userdef_types.h" - -#include "BKE_suggestions.h" -#include "BKE_text.h" - -#include "BLI_blenlib.h" - -#include "WM_types.h" - -#include "text_intern.h" - -int text_do_suggest_select(SpaceText *st, ARegion *ar) -{ - SuggItem *item, *first, *last /* , *sel */ /* UNUSED */; - TextLine *tmp; - int l, x, y, w, h, i; - int tgti, *top; - int mval[2] = {0, 0}; - - if (!st || !st->text) return 0; - if (!texttool_text_is_active(st->text)) return 0; - - first = texttool_suggest_first(); - last = texttool_suggest_last(); - /* sel = texttool_suggest_selected(); */ /* UNUSED */ - top = texttool_suggest_top(); - - if (!last || !first) - return 0; - - /* Count the visible lines to the cursor */ - for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ; - if (l < 0) return 0; - - text_update_character_width(st); - - if (st->showlinenrs) { - x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET + TEXTXLOC - 4; - } - else { - x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4; - } - y = ar->winy - st->lheight_dpi * l - 2; - - w = SUGG_LIST_WIDTH * st->cwidth + U.widget_unit; - h = SUGG_LIST_SIZE * st->lheight_dpi + 0.4f * U.widget_unit; - - // XXX getmouseco_areawin(mval); - - if (mval[0] < x || x + w < mval[0] || mval[1] < y - h || y < mval[1]) - return 0; - - /* Work out which of the items is at the top of the visible list */ - for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ; - - /* Work out the target item index in the visible list */ - tgti = (y - mval[1] - 4) / st->lheight_dpi; - if (tgti < 0 || tgti > SUGG_LIST_SIZE) - return 1; - - for (i = tgti; i > 0 && item->next; i--, item = item->next) ; - if (item) - texttool_suggest_select(item); - return 1; -} - -void text_pop_suggest_list(void) -{ - SuggItem *item, *sel; - int *top, i; - - item = texttool_suggest_first(); - sel = texttool_suggest_selected(); - top = texttool_suggest_top(); - - i = 0; - while (item && item != sel) { - item = item->next; - i++; - } - if (i > *top + SUGG_LIST_SIZE - 1) - *top = i - SUGG_LIST_SIZE + 1; - else if (i < *top) - *top = i; -} - -static void get_suggest_prefix(Text *text, int offset) -{ - int i, len; - char *line, tmp[256]; - - if (!text) return; - if (!texttool_text_is_active(text)) return; - - line = text->curl->line; - for (i = text->curc - 1 + offset; i >= 0; i--) - if (!text_check_identifier(line[i])) - break; - i++; - len = text->curc - i + offset; - if (len > 255) { - printf("Suggestion prefix too long\n"); - len = 255; - } - BLI_strncpy(tmp, line + i, len); - tmp[len] = '\0'; - texttool_suggest_prefix(tmp); -} - -static void confirm_suggestion(Text *text, int skipleft) -{ - SuggItem *sel; - int i, over = 0; - char *line; - - if (!text) return; - if (!texttool_text_is_active(text)) return; - - sel = texttool_suggest_selected(); - if (!sel) return; - - line = text->curl->line; - i = text->curc - skipleft - 1; - while (i >= 0) { - if (!text_check_identifier(line[i])) - break; - over++; - i--; - } - - for (i = 0; i < skipleft; i++) - txt_move_left(text, 0); - for (i = 0; i < over; i++) - txt_move_left(text, 1); - - txt_insert_buf(text, sel->name); - - for (i = 0; i < skipleft; i++) - txt_move_right(text, 0); - - texttool_text_clear(); -} - -// XXX -#define LR_SHIFTKEY 0 -#define LR_ALTKEY 0 -#define LR_CTRLKEY 0 - -// XXX -static int doc_scroll = 0; - -static short UNUSED_FUNCTION(do_texttools) (SpaceText * st, char ascii, unsigned short evnt, short val) -{ - ARegion *ar = NULL; // XXX - int qual = 0; // XXX - int draw = 0, tools = 0, swallow = 0, scroll = 1; - if (!texttool_text_is_active(st->text)) return 0; - if (!st->text || st->text->id.lib) return 0; - - if (st->doplugins && texttool_text_is_active(st->text)) { - if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST; - if (texttool_docs_get()) tools |= TOOL_DOCUMENT; - } - - if (ascii) { - if (tools & TOOL_SUGG_LIST) { - if ((ascii != '_' && ascii != '*' && ispunct(ascii)) || text_check_whitespace(ascii)) { - confirm_suggestion(st->text, 0); - text_update_line_edited(st->text->curl); - } - else if ((st->overwrite && txt_replace_char(st->text, ascii)) || txt_add_char(st->text, ascii)) { - get_suggest_prefix(st->text, 0); - text_pop_suggest_list(); - swallow = 1; - draw = 1; - } - } - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1; - - } - else if (val == 1 && evnt) { - switch (evnt) { - case LEFTMOUSE: - if (text_do_suggest_select(st, ar)) - swallow = 1; - else { - if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; - } - draw = 1; - break; - case MIDDLEMOUSE: - if (text_do_suggest_select(st, ar)) { - confirm_suggestion(st->text, 0); - text_update_line_edited(st->text->curl); - swallow = 1; - } - else { - if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; - } - draw = 1; - break; - case ESCKEY: - draw = swallow = 1; - if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); - else if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; - else draw = swallow = 0; - break; - case RETKEY: - if (tools & TOOL_SUGG_LIST) { - confirm_suggestion(st->text, 0); - text_update_line_edited(st->text->curl); - swallow = 1; - draw = 1; - } - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1; - break; - case LEFTARROWKEY: - case BACKSPACEKEY: - if (tools & TOOL_SUGG_LIST) { - if (qual) - texttool_suggest_clear(); - else { - /* Work out which char we are about to delete/pass */ - if (st->text->curl && st->text->curc > 0) { - char ch = st->text->curl->line[st->text->curc - 1]; - if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) { - get_suggest_prefix(st->text, -1); - text_pop_suggest_list(); - } - else - texttool_suggest_clear(); - } - else - texttool_suggest_clear(); - } - } - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; - break; - case RIGHTARROWKEY: - if (tools & TOOL_SUGG_LIST) { - if (qual) - texttool_suggest_clear(); - else { - /* Work out which char we are about to pass */ - if (st->text->curl && st->text->curc < st->text->curl->len) { - char ch = st->text->curl->line[st->text->curc + 1]; - if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) { - get_suggest_prefix(st->text, 1); - text_pop_suggest_list(); - } - else - texttool_suggest_clear(); - } - else - texttool_suggest_clear(); - } - } - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; - break; - case PAGEDOWNKEY: - scroll = SUGG_LIST_SIZE - 1; - case WHEELDOWNMOUSE: - case DOWNARROWKEY: - if (tools & TOOL_DOCUMENT) { - doc_scroll++; - swallow = 1; - draw = 1; - break; - } - else if (tools & TOOL_SUGG_LIST) { - SuggItem *sel = texttool_suggest_selected(); - if (!sel) { - texttool_suggest_select(texttool_suggest_first()); - } - else { - while (sel && sel != texttool_suggest_last() && sel->next && scroll--) { - texttool_suggest_select(sel->next); - sel = sel->next; - } - } - text_pop_suggest_list(); - swallow = 1; - draw = 1; - break; - } - case PAGEUPKEY: - scroll = SUGG_LIST_SIZE - 1; - case WHEELUPMOUSE: - case UPARROWKEY: - if (tools & TOOL_DOCUMENT) { - if (doc_scroll > 0) doc_scroll--; - swallow = 1; - draw = 1; - break; - } - else if (tools & TOOL_SUGG_LIST) { - SuggItem *sel = texttool_suggest_selected(); - while (sel && sel != texttool_suggest_first() && sel->prev && scroll--) { - texttool_suggest_select(sel->prev); - sel = sel->prev; - } - text_pop_suggest_list(); - swallow = 1; - draw = 1; - break; - } - case RIGHTSHIFTKEY: - case LEFTSHIFTKEY: - break; - default: - if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw = 1; - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1; - } - } - - if (draw) { - // XXX redraw_alltext(); - } - - return swallow; -} diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index 1ea3876f5cc..5ebbebec35b 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -105,14 +105,16 @@ static SpaceLink *userpref_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void userpref_main_area_init(wmWindowManager *wm, ARegion *ar) { + /* do not use here, the properties changed in userprefs do a system-wide refresh, then scroller jumps back */ + /* ar->v2d.flag &= ~V2D_IS_INITIALISED; */ + + ar->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE; + ED_region_panels_init(wm, ar); } static void userpref_main_area_draw(const bContext *C, ARegion *ar) { - /* this solves "vibrating UI" bug #25422 */ - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy); - ED_region_panels(C, ar, 1, NULL, -1); } diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index e36654323fd..fa72f28cc44 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -396,6 +396,7 @@ static void draw_textured_end(void) glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); /* XXX, bad patch - GPU_default_lights() calls * glLightfv(GL_POSITION, ...) which @@ -1018,7 +1019,7 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, const short do_light = (v3d->drawtype >= OB_SOLID); /* hide faces in face select mode */ - if (draw_flags & DRAW_FACE_SELECT) + if (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) facemask = wpaint__setSolidDrawOptions_facemask; if (ob->mode & OB_MODE_WEIGHT_PAINT) { @@ -1066,12 +1067,18 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, draw_mesh_face_select(rv3d, me, dm); } else if ((do_light == FALSE) || (ob->dtx & OB_DRAWWIRE)) { + const int use_depth = (v3d->flag & V3D_ZBUF_SELECT); /* weight paint in solid mode, special case. focus on making the weights clear * rather than the shading, this is also forced in wire view */ - bglPolygonOffset(rv3d->dist, 1.0); - glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ + if (use_depth) { + bglPolygonOffset(rv3d->dist, 1.0); + glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ + } + else { + glDisable(GL_DEPTH_TEST); + } glEnable(GL_BLEND); glColor4ub(255, 255, 255, 96); @@ -1080,8 +1087,14 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, dm->drawEdges(dm, 1, 1); - bglPolygonOffset(rv3d->dist, 0.0); - glDepthMask(1); + if (use_depth) { + bglPolygonOffset(rv3d->dist, 0.0); + glDepthMask(1); + } + else { + glEnable(GL_DEPTH_TEST); + } + glDisable(GL_LINE_STIPPLE); glDisable(GL_BLEND); } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 3722e6797f8..ebb5fd30666 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -101,7 +101,7 @@ typedef enum eWireDrawMode { } eWireDrawMode; typedef struct drawDMVerts_userData { - BMEditMesh *em; /* BMESH BRANCH ONLY */ + BMEditMesh *em; int sel; BMVert *eve_act; @@ -119,7 +119,7 @@ typedef struct drawDMVerts_userData { } drawDMVerts_userData; typedef struct drawDMEdgesSel_userData { - BMEditMesh *em; /* BMESH BRANCH ONLY */ + BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; @@ -132,8 +132,8 @@ typedef struct drawDMFacesSel_userData { unsigned char *cols[3]; #endif - DerivedMesh *dm; /* BMESH BRANCH ONLY */ - BMEditMesh *em; /* BMESH BRANCH ONLY */ + DerivedMesh *dm; + BMEditMesh *em; BMFace *efa_act; int *orig_index_mf_to_mpoly; @@ -2629,10 +2629,10 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, BMEditMesh *em, UnitS /* make the precision of the display value proportionate to the gridsize */ - if (grid < 0.01f) conv_float = "%.6g"; - else if (grid < 0.1f) conv_float = "%.5g"; - else if (grid < 1.0f) conv_float = "%.4g"; - else if (grid < 10.0f) conv_float = "%.3g"; + if (grid <= 0.01f) conv_float = "%.6g"; + else if (grid <= 0.1f) conv_float = "%.5g"; + else if (grid <= 1.0f) conv_float = "%.4g"; + else if (grid <= 10.0f) conv_float = "%.3g"; else conv_float = "%.2g"; if (me->drawflag & ME_DRAWEXTRA_EDGELEN) { @@ -3312,11 +3312,15 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D } if (is_obact && paint_vertsel_test(ob)) { - + const int use_depth = (v3d->flag & V3D_ZBUF_SELECT); glColor3f(0.0f, 0.0f, 0.0f); glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - + + if (!use_depth) glDisable(GL_DEPTH_TEST); + else bglPolygonOffset(rv3d->dist, 1.0); drawSelectedVertices(dm, ob->data); + if (!use_depth) glEnable(GL_DEPTH_TEST); + else bglPolygonOffset(rv3d->dist, 0.0); glPointSize(1.0f); } @@ -6949,10 +6953,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short UI_make_axis_color(col1, col2, 'Z'); glColor3ubv(col2); - cob = constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); for (curcon = list->first; curcon; curcon = curcon->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -7006,7 +7010,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short } } - constraints_clear_evalob(cob); + BKE_constraints_clear_evalob(cob); } } @@ -7167,7 +7171,21 @@ static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index) return DM_DRAW_OPTION_SKIP; } } -static void bbs_mesh_solid(Scene *scene, Object *ob) + +static void bbs_mesh_solid_verts(Scene *scene, Object *ob) +{ + Mesh *me = ob->data; + DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); + glColor3ub(0, 0, 0); + + dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_enable_material, NULL, me, 0); + + bbs_obmode_mesh_verts(ob, dm, 1); + bm_vertoffs = me->totvert + 1; + dm->release(dm); +} + +static void bbs_mesh_solid_faces(Scene *scene, Object *ob) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); Mesh *me = (Mesh *)ob->data; @@ -7232,18 +7250,10 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec /* currently vertex select only supports weight paint */ (ob->mode & OB_MODE_WEIGHT_PAINT)) { - DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); - glColor3ub(0, 0, 0); - - dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_enable_material, NULL, me, 0); - - - bbs_obmode_mesh_verts(ob, dm, 1); - bm_vertoffs = me->totvert + 1; - dm->release(dm); + bbs_mesh_solid_verts(scene, ob); } else { - bbs_mesh_solid(scene, ob); + bbs_mesh_solid_faces(scene, ob); } } break; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 4ade47fbdc7..1d87895d64a 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -520,14 +520,8 @@ static int view3d_ima_ob_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop) { ID *id = (ID *)drag->poin; - PointerRNA ptr; - /* need to put name in sub-operator in macro */ - ptr = RNA_pointer_get(drop->ptr, "OBJECT_OT_add_named"); - if (ptr.data) - RNA_string_set(&ptr, "name", id->name + 2); - else - RNA_string_set(drop->ptr, "name", id->name + 2); + RNA_string_set(drop->ptr, "name", id->name + 2); } static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop) @@ -561,7 +555,7 @@ static void view3d_dropboxes(void) { ListBase *lb = WM_dropboxmap_find("View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW); - WM_dropbox_add(lb, "OBJECT_OT_add_named_cursor", view3d_ob_drop_poll, view3d_ob_drop_copy); + WM_dropbox_add(lb, "OBJECT_OT_add_named", view3d_ob_drop_poll, view3d_ob_drop_copy); WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", view3d_mat_drop_poll, view3d_id_drop_copy); WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_ob_drop_poll, view3d_id_path_drop_copy); WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 7475f65317a..4ccf26e12b1 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -2596,10 +2596,10 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, linearrgb_to_srgb_v3_v3(backcol, &scene->world->horr); } - glClearColor(backcol[0], backcol[1], backcol[2], 0.0); + glClearColor(backcol[0], backcol[1], backcol[2], 0.0f); } else { - UI_ThemeClearColor(TH_BACK); + UI_ThemeClearColor(TH_BACK); } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 78c3f4e4f4a..e984a3f5cfd 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -921,7 +921,8 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event) } if (event->type == MOUSEPAN) { - viewrotate_apply(vod, event->prevx, event->prevy); + /* invert it, trackpad scroll then follows how you mapped it globally */ + viewrotate_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy); ED_view3d_depth_tag_update(rv3d); viewops_data_free(C, op); @@ -1008,17 +1009,20 @@ void ndof_to_quat(struct wmNDOFMotionData *ndof, float q[4]) */ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event) { - ViewOpsData *vod = op->customdata; if (event->type != NDOF_MOTION) return OPERATOR_CANCELLED; else { View3D *v3d = CTX_wm_view3d(C); + ViewOpsData *vod; RegionView3D *rv3d = CTX_wm_region_view3d(C); wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata; ED_view3d_camera_lock_init(v3d, rv3d); + viewops_data_create(C, op, event); + vod = op->customdata; + rv3d->rot_angle = 0.f; /* off by default, until changed later this function */ if (ndof->progress != P_FINISHING) { @@ -1138,8 +1142,10 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event) } } + viewops_data_free(C, op); + ED_view3d_camera_lock_sync(v3d, rv3d); - + ED_region_tag_redraw(CTX_wm_region(C)); return OPERATOR_FINISHED; @@ -1161,6 +1167,181 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot) ot->flag = 0; } + +static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + + if (event->type != NDOF_MOTION) + return OPERATOR_CANCELLED; + else { + ViewOpsData *vod; + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata; + + ED_view3d_camera_lock_init(v3d, rv3d); + + rv3d->rot_angle = 0.f; /* off by default, until changed later this function */ + + viewops_data_create(C, op, event); + vod = op->customdata; + + if (ndof->progress != P_FINISHING) { + const float dt = ndof->dt; + + /* tune these until everything feels right */ + const float rot_sensitivity = 1.f; + + const float zoom_sensitivity = 1.f; + + const float pan_sensitivity = 1.f; + const int has_rotation = rv3d->viewlock != RV3D_LOCKED && !is_zero_v3(ndof->rvec); + + float view_inv[4]; + invert_qt_qt(view_inv, rv3d->viewquat); + + /* #define DEBUG_NDOF_MOTION */ + #ifdef DEBUG_NDOF_MOTION + printf("ndof: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f delivered to 3D view\n", + ndof->tx, ndof->ty, ndof->tz, ndof->rx, ndof->ry, ndof->rz, ndof->dt); + #endif + + if (ndof->tz) { + /* Zoom! + * velocity should be proportional to the linear velocity attained by rotational motion of same strength + * [got that?] + * proportional to arclength = radius * angle + */ + float zoom_distance = zoom_sensitivity * rv3d->dist * dt * ndof->tz; + + if (U.ndof_flag & NDOF_ZOOM_INVERT) + zoom_distance = -zoom_distance; + + rv3d->dist += zoom_distance; + } + + if (rv3d->viewlock == RV3D_LOCKED) { + /* rotation not allowed -- explore panning options instead */ + float pan_vec[3] = {ndof->tx, ndof->ty, 0.0f}; + mul_v3_fl(pan_vec, pan_sensitivity * rv3d->dist * dt); + + /* transform motion from view to world coordinates */ + invert_qt_qt(view_inv, rv3d->viewquat); + mul_qt_v3(view_inv, pan_vec); + + /* move center of view opposite of hand motion (this is camera mode, not object mode) */ + sub_v3_v3(rv3d->ofs, pan_vec); + } + + if (has_rotation) { + + rv3d->view = RV3D_VIEW_USER; + + if (U.ndof_flag & NDOF_TURNTABLE) { + + /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */ + float angle, rot[4]; + float xvec[3] = {1, 0, 0}; + + /* Determine the direction of the x vector (for rotating up and down) */ + mul_qt_v3(view_inv, xvec); + + /* Perform the up/down rotation */ + angle = rot_sensitivity * dt * ndof->rx; + if (U.ndof_flag & NDOF_TILT_INVERT_AXIS) + angle = -angle; + rot[0] = cos(angle); + mul_v3_v3fl(rot + 1, xvec, sin(angle)); + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot); + + /* Perform the orbital rotation */ + angle = rot_sensitivity * dt * ndof->ry; + if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS) + angle = -angle; + + /* update the onscreen doo-dad */ + rv3d->rot_angle = angle; + rv3d->rot_axis[0] = 0; + rv3d->rot_axis[1] = 0; + rv3d->rot_axis[2] = 1; + + rot[0] = cos(angle); + rot[1] = rot[2] = 0.0; + rot[3] = sin(angle); + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot); + + } + else { + float rot[4]; + float axis[3]; + float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis); + + if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS) + axis[2] = -axis[2]; + + if (U.ndof_flag & NDOF_TILT_INVERT_AXIS) + axis[0] = -axis[0]; + + if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS) + axis[1] = -axis[1]; + + + /* transform rotation axis from view to world coordinates */ + mul_qt_v3(view_inv, axis); + + /* update the onscreen doo-dad */ + rv3d->rot_angle = angle; + copy_v3_v3(rv3d->rot_axis, axis); + + axis_angle_to_quat(rot, axis, angle); + + /* apply rotation */ + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot); + + } + + /* rotate around custom center */ + if (vod && vod->use_dyn_ofs) { + float q1[4]; + + /* compute the post multiplication quat, to rotate the offset correctly */ + conjugate_qt_qt(q1, vod->oldquat); + mul_qt_qtqt(q1, q1, rv3d->viewquat); + + conjugate_qt(q1); /* conj == inv for unit quat */ + copy_v3_v3(rv3d->ofs, vod->ofs); + sub_v3_v3(rv3d->ofs, vod->dyn_ofs); + mul_qt_v3(q1, rv3d->ofs); + add_v3_v3(rv3d->ofs, vod->dyn_ofs); + } + } + } + + viewops_data_free(C, op); + + ED_view3d_camera_lock_sync(v3d, rv3d); + + ED_region_tag_redraw(CTX_wm_region(C)); + + return OPERATOR_FINISHED; + } +} + +void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "NDOF Orbit View with zoom"; + ot->description = "Explore every angle of an object using the 3D mouse"; + ot->idname = "VIEW3D_OT_ndof_orbit_zoom"; + + /* api callbacks */ + ot->invoke = ndof_orbit_zoom_invoke; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = 0; +} + /* -- "pan" navigation * -- zoom or dolly? */ @@ -1197,8 +1378,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) mul_v3_fl(pan_vec, pan_sensitivity * rv3d->dist * dt); #else /* ------------------------------------------------------- dolly with Z */ - float speed = 10.f; /* blender units per second */ - /* ^^ this is ok for default cube scene, but should scale with.. something */ + float speed = rv3d->dist; /* uses distance from pivot to define dolly */ /* tune these until everything feels right */ const float forward_sensitivity = 1.f; @@ -1261,8 +1441,9 @@ void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot) */ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event) { - if (event->type != NDOF_MOTION) + if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; + } else { ViewOpsData *vod; @@ -1282,23 +1463,14 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event) const float dt = ndof->dt; float view_inv[4]; - float speed = 10.f; /* blender units per second */ - /* ^^ this is ok for default cube scene, but should scale with.. something */ + float speed = rv3d->dist; /* uses distance from pivot to define dolly */ /* tune these until everything feels right */ const float forward_sensitivity = 1.f; const float vertical_sensitivity = 0.4f; const float lateral_sensitivity = 0.6f; - float pan_vec[3]; const float rot_sensitivity = 1.f; -#if 0 - const float zoom_sensitivity = 1.f; - const float pan_sensitivity = 1.f; - float rot[4]; - float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis); - float axis[3]; -#endif /* inverse view */ invert_qt_qt(view_inv, rv3d->viewquat); @@ -1389,7 +1561,7 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event) } /* rotate around custom center */ - if (vod && vod->use_dyn_ofs) { + if (vod->use_dyn_ofs) { float q1[4]; /* compute the post multiplication quat, to rotate the offset correctly */ @@ -1404,10 +1576,13 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event) } } + + viewops_data_free(C, op); + ED_view3d_camera_lock_sync(v3d, rv3d); ED_region_tag_redraw(CTX_wm_region(C)); - viewops_data_free(C, op); + return OPERATOR_FINISHED; } } @@ -3677,17 +3852,21 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) /* ***************** 3d cursor cursor op ******************* */ -/* mx my in region coords */ -static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +/* cursor position in vec, result in vec, mval in region coords */ +/* note: cannot use event->mval here (called by object_add() */ +void ED_view3d_cursor3d_position(bContext *C, float *fp, int mx, int my) { Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); - float *fp = give_cursor(scene, v3d); float mval_fl[2]; + int mval[2]; int flip; + mval[0] = mx - ar->winrct.xmin; + mval[1] = my - ar->winrct.ymin; + flip = initgrabz(rv3d, fp[0], fp[1], fp[2]); /* reset the depth based on the view offset (we _know_ the offset is infront of us) */ @@ -3702,20 +3881,20 @@ static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent * if (U.uiflag & USER_ZBUF_CURSOR) { /* maybe this should be accessed some other way */ view3d_operator_needs_opengl(C); - if (ED_view3d_autodist(scene, ar, v3d, event->mval, fp)) + if (ED_view3d_autodist(scene, ar, v3d, mval, fp)) depth_used = TRUE; } if (depth_used == FALSE) { float dvec[3]; - VECSUB2D(mval_fl, mval_fl, event->mval); + VECSUB2D(mval_fl, mval_fl, mval); ED_view3d_win_to_delta(ar, mval_fl, dvec); sub_v3_v3(fp, dvec); } } else { - const float dx = ((float)(event->mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2); - const float dy = ((float)(event->mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2); + const float dx = ((float)(mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2); + const float dy = ((float)(mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2); const float fz = (rv3d->persmat[0][3] * fp[0] + rv3d->persmat[1][3] * fp[1] + rv3d->persmat[2][3] * fp[2] + @@ -3726,11 +3905,21 @@ static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent * fp[2] = (rv3d->persinv[0][2] * dx + rv3d->persinv[1][2] * dy + rv3d->persinv[2][2] * fz) - rv3d->ofs[2]; } +} + +static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +{ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + float *fp = give_cursor(scene, v3d); + + ED_view3d_cursor3d_position(C, fp, event->x, event->y); + if (v3d && v3d->localvd) WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); else WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); - + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 79bf003a563..2b30e4e6b81 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -487,11 +487,17 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) block = uiLayoutGetBlock(row); if (v3d->twflag & V3D_USE_MANIPULATOR) { - but = uiDefIconButBitC(block, TOG, V3D_MANIP_TRANSLATE, B_MAN_TRANS, ICON_MAN_TRANS, 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, TIP_("Translate manipulator - Shift-Click for multiple modes")); + but = uiDefIconButBitC(block, TOG, V3D_MANIP_TRANSLATE, B_MAN_TRANS, ICON_MAN_TRANS, + 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, + TIP_("Translate manipulator - Shift-Click for multiple modes")); uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ - but = uiDefIconButBitC(block, TOG, V3D_MANIP_ROTATE, B_MAN_ROT, ICON_MAN_ROT, 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, TIP_("Rotate manipulator - Shift-Click for multiple modes")); + but = uiDefIconButBitC(block, TOG, V3D_MANIP_ROTATE, B_MAN_ROT, ICON_MAN_ROT, + 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, + TIP_("Rotate manipulator - Shift-Click for multiple modes")); uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ - but = uiDefIconButBitC(block, TOG, V3D_MANIP_SCALE, B_MAN_SCALE, ICON_MAN_SCALE, 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, TIP_("Scale manipulator - Shift-Click for multiple modes")); + but = uiDefIconButBitC(block, TOG, V3D_MANIP_SCALE, B_MAN_SCALE, ICON_MAN_SCALE, + 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, + TIP_("Scale manipulator - Shift-Click for multiple modes")); uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ } @@ -500,7 +506,8 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) } str_menu = BIF_menustringTransformOrientation(C, "Orientation"); - but = uiDefButC(block, MENU, B_MAN_MODE, str_menu, 0, 0, 70 * dpi_fac, UI_UNIT_Y, &v3d->twmode, 0, 0, 0, 0, TIP_("Transform Orientation")); + but = uiDefButC(block, MENU, B_MAN_MODE, str_menu, 0, 0, 70 * dpi_fac, UI_UNIT_Y, &v3d->twmode, 0, 0, 0, 0, + TIP_("Transform Orientation")); uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ MEM_freeN((void *)str_menu); } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index f8a7cdde8a5..a6daf610052 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -77,6 +77,7 @@ void VIEW3D_OT_zoom_camera_1_to_1(struct wmOperatorType *ot); void VIEW3D_OT_move(struct wmOperatorType *ot); void VIEW3D_OT_rotate(struct wmOperatorType *ot); void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot); +void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot); void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot); void VIEW3D_OT_ndof_all(struct wmOperatorType *ot); void VIEW3D_OT_view_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index a0b36e57d69..81e890c37ee 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -27,6 +27,7 @@ #include "DNA_curve_types.h" #include "DNA_lattice_types.h" #include "DNA_meta_types.h" +#include "DNA_mesh_types.h" #include "DNA_armature_types.h" #include "DNA_object_types.h" @@ -47,6 +48,12 @@ #include "ED_object.h" #include "ED_view3d.h" +typedef struct foreachScreenObjectVert_userData { + void (*func)(void *userData, MVert *mv, const float screen_co_b[2], int index); + void *userData; + ViewContext vc; + eV3DProjTest clip_flag; +} foreachScreenObjectVert_userData; typedef struct foreachScreenVert_userData { void (*func)(void *userData, BMVert *eve, const float screen_co_b[2], int index); @@ -79,6 +86,46 @@ typedef struct foreachScreenFace_userData { /* ------------------------------------------------------------------------ */ + +static void meshobject_foreachScreenVert__mapFunc(void *userData, int index, const float co[3], + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + foreachScreenObjectVert_userData *data = userData; + struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index]; + + if (!(mv->flag & ME_HIDE)) { + float screen_co[2]; + + if (ED_view3d_project_float_object(data->vc.ar, co, screen_co, data->clip_flag) != V3D_PROJ_RET_OK) { + return; + } + + data->func(data->userData, mv, screen_co, index); + } +} + +void meshobject_foreachScreenVert( + ViewContext *vc, + void (*func)(void *userData, MVert *eve, const float screen_co[2], int index), + void *userData, eV3DProjTest clip_flag) +{ + foreachScreenObjectVert_userData data; + DerivedMesh *dm = mesh_get_derived_deform(vc->scene, vc->obact, CD_MASK_BAREMESH); + + data.vc = *vc; + data.func = func; + data.userData = userData; + data.clip_flag = clip_flag; + + if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { + ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ + } + + dm->foreachMappedVert(dm, meshobject_foreachScreenVert__mapFunc, &data); + + dm->release(dm); +} + static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3], const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) { diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 4101ced616a..615ae71cf9b 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -131,6 +131,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_zoom); WM_operatortype_append(VIEW3D_OT_zoom_camera_1_to_1); WM_operatortype_append(VIEW3D_OT_dolly); + WM_operatortype_append(VIEW3D_OT_ndof_orbit_zoom); WM_operatortype_append(VIEW3D_OT_ndof_orbit); WM_operatortype_append(VIEW3D_OT_ndof_pan); WM_operatortype_append(VIEW3D_OT_ndof_all); @@ -195,34 +196,6 @@ void view3d_keymap(wmKeyConfig *keyconf) /* only for region 3D window */ keymap = WM_keymap_find(keyconf, "3D View", SPACE_VIEW3D, 0); - - /* NDOF: begin */ - /* note: positioned here so keymaps show keyboard keys if assigned */ - /* 3D mouse */ - WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit", NDOF_MOTION, 0, KM_CTRL, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_pan", NDOF_MOTION, 0, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, 0, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_LEFT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_LEFT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BOTTOM, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BOTTOM); - - /* 3D mouse align */ - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT); - RNA_boolean_set(kmi->ptr, "align_active", TRUE); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT); - RNA_boolean_set(kmi->ptr, "align_active", TRUE); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP); - RNA_boolean_set(kmi->ptr, "align_active", TRUE); - /* NDOF: end */ - - kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0); RNA_boolean_set(kmi->ptr, "release_confirm", TRUE); /* @@ -248,9 +221,9 @@ void view3d_keymap(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, KM_ALT, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, 0, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEROTATE, 0, 0, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_move", MOUSEPAN, 0, 0, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_move", MOUSEPAN, 0, KM_SHIFT, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEZOOM, 0, 0, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0); @@ -331,6 +304,34 @@ void view3d_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "VIEW3D_OT_localview", PADSLASHKEY, KM_PRESS, 0, 0); + /* NDOF: begin */ + /* note: positioned here so keymaps show keyboard keys if assigned */ + /* 3D mouse */ + WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit_zoom", NDOF_MOTION, 0, 0, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit", NDOF_MOTION, 0, KM_CTRL, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_pan", NDOF_MOTION, 0, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, KM_CTRL | KM_SHIFT, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_LEFT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_LEFT); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BOTTOM, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BOTTOM); + + /* 3D mouse align */ + kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT); + RNA_boolean_set(kmi->ptr, "align_active", TRUE); + kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT); + RNA_boolean_set(kmi->ptr, "align_active", TRUE); + kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP); + RNA_boolean_set(kmi->ptr, "align_active", TRUE); + /* NDOF: end */ + + /* layers, shift + alt are properties set in invoke() */ RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ACCENTGRAVEKEY, KM_PRESS, 0, 0)->ptr, "nr", 0); RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ONEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 1); diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index d4bdf6c3177..c428cb02236 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -110,7 +110,7 @@ eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base) /* perspmat is typically... * - 'rv3d->perspmat', is_local == FALSE - * - 'rv3d->perspmatob', is_local == TRUE + * - 'rv3d->persmatob', is_local == TRUE */ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar, float perspmat[4][4], const int is_local, /* normally hidden */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index d37042fa2ec..dac887f7f13 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -70,6 +70,7 @@ #include "BKE_paint.h" #include "BKE_tessmesh.h" #include "BKE_tracking.h" +#include "BKE_utildefines.h" #include "BIF_gl.h" @@ -741,67 +742,19 @@ static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short m mball_foreachScreenElem(vc, do_lasso_select_mball__doSelectElem, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } -static int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int extend) +static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) { - Mesh *me; - MVert *mvert; - struct ImBuf *ibuf; - unsigned int *rt; - int a, index; - char *selar; - int sx = BLI_rcti_size_x(rect) + 1; - int sy = BLI_rcti_size_y(rect) + 1; - - me = vc->obact->data; - - if (me == NULL || me->totvert == 0 || sx * sy <= 0) - return OPERATOR_CANCELLED; - - selar = MEM_callocN(me->totvert + 1, "selar"); - - if (extend == 0 && select) - paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE); - - view3d_validate_backbuf(vc); - - ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect); - rt = ibuf->rect; - glReadPixels(rect->xmin + vc->ar->winrct.xmin, rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); - if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf); - - a = sx * sy; - while (a--) { - if (*rt) { - index = WM_framebuffer_to_index(*rt); - if (index <= me->totvert) selar[index] = 1; - } - rt++; - } + LassoSelectUserData *data = userData; - mvert = me->mvert; - for (a = 1; a <= me->totvert; a++, mvert++) { - if (selar[a]) { - if ((mvert->flag & ME_HIDE) == 0) { - if (select) mvert->flag |= SELECT; - else mvert->flag &= ~SELECT; - } - } + if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) + { + BKE_BIT_TEST_SET(mv->flag, data->select, SELECT); } - - IMB_freeImBuf(ibuf); - MEM_freeN(selar); - -#ifdef __APPLE__ - glReadBuffer(GL_BACK); -#endif - - paintvert_flush_flags(vc->obact); - - return OPERATOR_FINISHED; } - static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { + const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT); Object *ob = vc->obact; Mesh *me = ob ? ob->data : NULL; rcti rect; @@ -811,14 +764,31 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh if (extend == 0 && select) paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE); /* flush selection at the end */ - bm_vertoffs = me->totvert + 1; /* max index array */ BLI_lasso_boundbox(&rect, mcords, moves); - EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - edbm_backbuf_check_and_select_verts_obmode(me, select); + if (use_zbuf) { + bm_vertoffs = me->totvert + 1; /* max index array */ - EDBM_backbuf_free(); + EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + + edbm_backbuf_check_and_select_verts_obmode(me, select); + + EDBM_backbuf_free(); + } + else { + LassoSelectUserData data; + rcti rect; + + BLI_lasso_boundbox(&rect, mcords, moves); + + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + + ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); + + meshobject_foreachScreenVert(vc, do_lasso_select_meshobject__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + + } paintvert_flush_flags(ob); } @@ -1217,31 +1187,42 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int } } +static int selectbuffer_has_bones(const unsigned int *buffer, const unsigned int hits) +{ + unsigned int i; + for (i = 0; i < hits; i++) { + if (buffer[(4 * i) + 3] & 0xFFFF0000) { + return TRUE; + } + } + return FALSE; +} + /* we want a select buffer with bones, if there are... */ /* so check three selection levels and compare */ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2]) { rcti rect; int offs; - short a, hits15, hits9 = 0, hits5 = 0; - short has_bones15 = 0, has_bones9 = 0, has_bones5 = 0; + short hits15, hits9 = 0, hits5 = 0; + short has_bones15 = FALSE, has_bones9 = FALSE, has_bones5 = FALSE; BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14); hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); if (hits15 > 0) { - for (a = 0; a < hits15; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones15 = 1; + has_bones15 = selectbuffer_has_bones(buffer, hits15); offs = 4 * hits15; BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9); hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect); if (hits9 > 0) { - for (a = 0; a < hits9; a++) if (buffer[offs + 4 * a + 3] & 0xFFFF0000) has_bones9 = 1; + has_bones9 = selectbuffer_has_bones(buffer + offs, hits9); offs += 4 * hits9; BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5); hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect); if (hits5 > 0) { - for (a = 0; a < hits5; a++) if (buffer[offs + 4 * a + 3] & 0xFFFF0000) has_bones5 = 1; + has_bones5 = selectbuffer_has_bones(buffer + offs, hits5); } } @@ -1383,10 +1364,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) hits = mixed_bones_object_selectbuffer(&vc, buffer, mval); if (hits > 0) { - int a, has_bones = 0; - - for (a = 0; a < hits; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones = 1; - + const int has_bones = selectbuffer_has_bones(buffer, hits); basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones); } @@ -1420,7 +1398,6 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); Base *base, *startbase = NULL, *basact = NULL, *oldbasact = NULL; - int a; float dist = 100.0f; int retval = 0; short hits; @@ -1473,10 +1450,8 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese hits = mixed_bones_object_selectbuffer(&vc, buffer, mval); if (hits > 0) { - int has_bones = 0; - /* note: bundles are handling in the same way as bones */ - for (a = 0; a < hits; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones = 1; + const int has_bones = selectbuffer_has_bones(buffer, hits); /* note; shift+alt goes to group-flush-selecting */ if (has_bones == 0 && enumerate) { @@ -1502,7 +1477,7 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese } /* index of bundle is 1<<16-based. if there's no "bone" index - * in height word, this buffer value belongs to camera,. not to bundle */ + * in height word, this buffer value belongs to camera. not to bundle */ if (buffer[4 * i + 3] & 0xFFFF0000) { MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, 0); MovieTracking *tracking = &clip->tracking; @@ -1670,6 +1645,85 @@ int edge_inside_circle(const float cent[2], float radius, const float screen_co_ return FALSE; } +static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) +{ + BoxSelectUserData *data = userData; + + if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { + BKE_BIT_TEST_SET(mv->flag, data->select, SELECT); + } +} +static int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int extend) +{ + const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT); + Mesh *me; + MVert *mvert; + struct ImBuf *ibuf; + unsigned int *rt; + int a, index; + char *selar; + int sx = BLI_rcti_size_x(rect) + 1; + int sy = BLI_rcti_size_y(rect) + 1; + + me = vc->obact->data; + + if (me == NULL || me->totvert == 0 || sx * sy <= 0) + return OPERATOR_CANCELLED; + + + if (extend == 0 && select) + paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE); + + if (use_zbuf) { + selar = MEM_callocN(me->totvert + 1, "selar"); + view3d_validate_backbuf(vc); + + ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect); + rt = ibuf->rect; + glReadPixels(rect->xmin + vc->ar->winrct.xmin, rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); + if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf); + + a = sx * sy; + while (a--) { + if (*rt) { + index = WM_framebuffer_to_index(*rt); + if (index <= me->totvert) selar[index] = 1; + } + rt++; + } + + mvert = me->mvert; + for (a = 1; a <= me->totvert; a++, mvert++) { + if (selar[a]) { + if ((mvert->flag & ME_HIDE) == 0) { + if (select) mvert->flag |= SELECT; + else mvert->flag &= ~SELECT; + } + } + } + + IMB_freeImBuf(ibuf); + MEM_freeN(selar); + +#ifdef __APPLE__ + glReadBuffer(GL_BACK); +#endif + } + else { + BoxSelectUserData data; + + view3d_userdata_boxselect_init(&data, vc, rect, select); + + ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); + + meshobject_foreachScreenVert(vc, do_paintvert_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + } + + paintvert_flush_flags(vc->obact); + + return OPERATOR_FINISHED; +} + static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) { BoxSelectUserData *data = userData; @@ -2142,11 +2196,14 @@ void VIEW3D_OT_select_border(wmOperatorType *ot) /* gets called via generic mouse select operator */ static int mouse_weight_paint_vertex_select(bContext *C, const int mval[2], short extend, short deselect, short toggle, Object *obact) { + View3D *v3d = CTX_wm_view3d(C); + const int use_zbuf = (v3d->flag & V3D_ZBUF_SELECT); + Mesh *me = obact->data; /* already checked for NULL */ unsigned int index = 0; MVert *mv; - if (ED_mesh_pick_vert(C, me, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) { + if (ED_mesh_pick_vert(C, obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, use_zbuf)) { mv = &me->mvert[index]; if (extend) { mv->flag |= SELECT; @@ -2366,22 +2423,39 @@ static void paint_facesel_circle_select(ViewContext *vc, int select, const int m } } +static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) +{ + CircleSelectUserData *data = userData; + if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { + BKE_BIT_TEST_SET(mv->flag, data->select, SELECT); + } +} static void paint_vertsel_circle_select(ViewContext *vc, int select, const int mval[2], float rad) { + const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT); Object *ob = vc->obact; - Mesh *me = ob ? ob->data : NULL; + Mesh *me = ob->data; /* int bbsel; */ /* UNUSED */ /* CircleSelectUserData data = {NULL}; */ /* UNUSED */ - if (me) { + + if (use_zbuf) { bm_vertoffs = me->totvert + 1; /* max index array */ /* bbsel = */ /* UNUSED */ EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); edbm_backbuf_check_and_select_verts_obmode(me, select == LEFTMOUSE); EDBM_backbuf_free(); + } + else { + CircleSelectUserData data; - paintvert_flush_flags(ob); + ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */ + + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + meshobject_foreachScreenVert(vc, paint_vertsel_circle_select_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } + + paintvert_flush_flags(ob); } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b2ee17b8a8b..3b443e8bbac 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -686,6 +686,9 @@ static void view_editmove(unsigned short UNUSED(event)) #define TFM_MODAL_EDGESLIDE_UP 24 #define TFM_MODAL_EDGESLIDE_DOWN 25 +/* for analog input, like trackpad */ +#define TFM_MODAL_PROPSIZE 26 + /* called in transform_ops.c, on each regeneration of keymaps */ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) { @@ -715,6 +718,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) {TFM_MODAL_AUTOIK_LEN_DEC, "AUTOIK_CHAIN_LEN_DOWN", 0, "Decrease Max AutoIK Chain Length", ""}, {TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""}, {TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""}, + {TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""}, {0, NULL, 0, NULL, NULL} }; @@ -750,6 +754,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN); WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP); WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN); + WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE); WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP); WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_DOWN); @@ -1024,6 +1029,19 @@ int transformEvent(TransInfo *t, wmEvent *event) removeSnapPoint(t); t->redraw |= TREDRAW_HARD; break; + + case TFM_MODAL_PROPSIZE: + /* MOUSEPAN usage... */ + if (t->flag & T_PROP_EDIT) { + float fac = 1.0f + 0.005f *(event->y - event->prevy); + t->prop_size *= fac; + if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) + t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); + calculatePropRatio(t); + } + t->redraw |= TREDRAW_HARD; + break; + case TFM_MODAL_PROPSIZE_UP: if (t->flag & T_PROP_EDIT) { t->prop_size *= 1.1f; @@ -1500,7 +1518,6 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) glTranslatef(mval[0], mval[1], 0); glLineWidth(3.0); - glBegin(GL_LINES); drawArrow(UP, 5, 10, 5); drawArrow(DOWN, 5, 10, 5); glLineWidth(1.0); @@ -2258,8 +2275,8 @@ static void protectedQuaternionBits(short protectflag, float *quat, float *oldqu static void constraintTransLim(TransInfo *t, TransData *td) { if (td->con) { - bConstraintTypeInfo *ctiLoc = get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT); - bConstraintTypeInfo *ctiDist = get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT); + bConstraintTypeInfo *ctiLoc = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT); + bConstraintTypeInfo *ctiDist = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT); bConstraintOb cob = {NULL}; bConstraint *con; @@ -2309,7 +2326,7 @@ static void constraintTransLim(TransInfo *t, TransData *td) } /* get constraint targets if needed */ - get_constraint_targets_for_solving(con, &cob, &targets, ctime); + BKE_get_constraint_targets_for_solving(con, &cob, &targets, ctime); /* do constraint */ cti->evaluate_constraint(con, &cob, &targets); @@ -2361,7 +2378,7 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td) static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) { if (td->con) { - bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT); + bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT); bConstraintOb cob; bConstraint *con; int do_limit = FALSE; @@ -2428,7 +2445,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) static void constraintSizeLim(TransInfo *t, TransData *td) { if (td->con && td->ext) { - bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT); + bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT); bConstraintOb cob = {NULL}; bConstraint *con; float size_sign[3], size_abs[3]; @@ -2721,6 +2738,18 @@ int handleEventShear(TransInfo *t, wmEvent *event) status = 1; } + else if (event->type == XKEY && event->val == KM_PRESS) { + initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); + t->customData = NULL; + + status = 1; + } + else if (event->type == YKEY && event->val == KM_PRESS) { + initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); + t->customData = (void *)1; + + status = 1; + } return status; } @@ -2754,7 +2783,7 @@ int Shear(TransInfo *t, const int UNUSED(mval[2])) } else { /* default header print */ - sprintf(str, "Shear: %.3f %s", value, t->proptext); + sprintf(str, "Shear: %.3f %s (Press X or Y to set shear axis)", value, t->proptext); } t->values[0] = value; diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 7da47425370..12b0341d395 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -835,7 +835,7 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan) } } - con = add_pose_constraint(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC); + con = BKE_add_pose_constraint(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC); pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET); /* for draw, but also for detecting while pose solving */ data = con->data; if (targetless) { @@ -4090,7 +4090,7 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count /* Meta's can only directly be moved between channels since they * don't have their start and length set directly (children affect that) * since this Meta is nested we don't need any of its data in fact. - * calc_sequence() will update its settings when run on the toplevel meta */ + * BKE_sequence_calc() will update its settings when run on the toplevel meta */ *flag = 0; *count = 0; *recursive = TRUE; @@ -4268,8 +4268,8 @@ static void freeSeqData(TransInfo *t) { int overlap = 0; + seq_prev = NULL; for (a = 0; a < t->total; a++, td++) { - seq_prev = NULL; seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) { overlap = 1; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 8f1d6a7b46e..2591c61c5ab 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -61,6 +61,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "BIK_api.h" + #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_armature.h" @@ -847,6 +849,8 @@ static void recalcData_view3d(TransInfo *t) /* old optimize trick... this enforces to bypass the depgraph */ if (!(arm->flag & ARM_DELAYDEFORM)) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ + /* transformation of pose may affect IK tree, make sure it is rebuilt */ + BIK_clear_data(ob->pose); } else BKE_pose_where_is(t->scene, ob); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index c9c4f7e2c7b..4bd6496e083 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -764,7 +764,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], EditBone *ebone; int ok = FALSE; - /* grr,.but better then duplicate code */ + /* grr. but better then duplicate code */ #define EBONE_CALC_NORMAL_PLANE { \ float tmat[3][3]; \ float vec[3]; \ diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index 1753a564a3c..1dc7e0c90e8 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -162,15 +162,18 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) } } else { - int do_glob_undo = FALSE; - + /* Note: we used to do a fall-through here where if the + * mode-specific undo system had no more steps to undo (or + * redo), the global undo would run. + * + * That was inconsistent with editmode, and also makes for + * unecessarily tricky interaction with the other undo + * systems. */ if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { - if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname)) - do_glob_undo = TRUE; + ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname); } else if (obact && obact->mode & OB_MODE_SCULPT) { - if (!ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname)) - do_glob_undo = TRUE; + ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname); } else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { if (step == 1) @@ -178,24 +181,17 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) else PE_redo(CTX_data_scene(C)); } - else { - do_glob_undo = TRUE; - } - - if (do_glob_undo) { - if (U.uiflag & USER_GLOBALUNDO) { - // note python defines not valid here anymore. - //#ifdef WITH_PYTHON - // XXX BPY_scripts_clear_pyobjects(); - //#endif - if (undoname) - BKE_undo_name(C, undoname); - else - BKE_undo_step(C, step); + else if (U.uiflag & USER_GLOBALUNDO) { + // note python defines not valid here anymore. + //#ifdef WITH_PYTHON + // XXX BPY_scripts_clear_pyobjects(); + //#endif + if (undoname) + BKE_undo_name(C, undoname); + else + BKE_undo_step(C, step); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); - } - + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); } } diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 27bbba11e75..4d52282d540 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -73,6 +73,7 @@ void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditM /* utility tool functions */ void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit); +void uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, float *aspx, float *aspy); /* operators */ diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index bd50857c8b8..8c3eaa1192f 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -136,6 +136,7 @@ typedef struct UvEdge { /* stitch state object */ typedef struct StitchState { + float aspect; /* use limit flag */ char use_limit; /* limit to operator, same as original operator */ @@ -285,10 +286,12 @@ static int getNumOfIslandUvs(UvElementMap *elementMap, int island) } } -static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2]) +static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2], float aspect) { float uv_rotation_result[2]; + uv[1] /= aspect; + uv[0] -= medianPoint[0]; uv[1] -= medianPoint[1]; @@ -297,6 +300,8 @@ static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2]) uv[0] = uv_rotation_result[0] + medianPoint[0]; uv[1] = uv_rotation_result[1] + medianPoint[1]; + + uv[1] *= aspect; } /* check if two uvelements are stitchable. This should only operate on -different- separate UvElements */ @@ -413,9 +418,11 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements; island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements; island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements; + island_stitch_data[i].medianPoint[1] /= state->aspect; } island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements; island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements; + numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); element = &state->element_map->buf[state->element_map->islandIndices[i]]; for (j = 0; j < numOfIslandUVs; j++, element++) { @@ -429,7 +436,7 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition if (final) { - stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, luv->uv); + stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, luv->uv, state->aspect); add_v2_v2(luv->uv, island_stitch_data[i].translation); } @@ -438,7 +445,7 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition int face_preview_pos = preview_position[BM_elem_index_get(element->l->f)].data_position; stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, - preview->preview_polys + face_preview_pos + 2 * element->tfindex); + preview->preview_polys + face_preview_pos + 2 * element->tfindex, state->aspect); add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->tfindex, island_stitch_data[i].translation); @@ -461,15 +468,12 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *sta int index1, index2; float rotation; MLoopUV *luv1, *luv2; - BMLoop *l1, *l2; element1 = state->uvs[edge->uv1]; element2 = state->uvs[edge->uv2]; - l1 = element1->l; - luv1 = CustomData_bmesh_get(&state->em->bm->ldata, l1->head.data, CD_MLOOPUV); - l2 = element2->l; - luv2 = CustomData_bmesh_get(&state->em->bm->ldata, l2->head.data, CD_MLOOPUV); + luv1 = CustomData_bmesh_get(&state->em->bm->ldata, element1->l->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&state->em->bm->ldata, element2->l->head.data, CD_MLOOPUV); if (state->mode == STITCH_VERT) { index1 = uvfinal_map[element1 - state->element_map->buf]; @@ -484,14 +488,18 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *sta uv1[0] = luv2->uv[0] - luv1->uv[0]; uv1[1] = luv2->uv[1] - luv1->uv[1]; + uv1[1] /= state->aspect; + uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0]; uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1]; + uv2[1] /= state->aspect; + normalize_v2(uv1); normalize_v2(uv2); - edgecos = uv1[0] * uv2[0] + uv1[1] * uv2[1]; - edgesin = uv1[0] * uv2[1] - uv2[0] * uv1[1]; + edgecos = dot_v2v2(uv1, uv2); + edgesin = cross_v2v2(uv1, uv2); rotation = (edgesin > 0.0f) ? +acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))) : @@ -536,7 +544,9 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat negate_v2_v2(normal, state->normals + index_tmp2 * 2); edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2); edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2); - rotation += (edgesin > 0.0f) ? acosf(edgecos) : -acosf(edgecos); + rotation += (edgesin > 0.0f) ? + +acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))) : + -acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); } } @@ -837,13 +847,13 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) int previous_island = state->static_island; BMFace *efa; BMIter iter; - UVVertAverage *final_position; + UVVertAverage *final_position = NULL; char stitch_midpoints = state->midpoints; /* used to map uv indices to uvaverage indices for selection */ - unsigned int *uvfinal_map; + unsigned int *uvfinal_map = NULL; /* per face preview position in preview buffer */ - PreviewPosition *preview_position; + PreviewPosition *preview_position = NULL; /* cleanup previous preview */ stitch_preview_delete(state->stitch_preview); @@ -1157,6 +1167,14 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) } } + /* take mean position here. For edge case, this can't be done inside the loop for shared uvverts */ + if (state->mode == STITCH_EDGE && stitch_midpoints) { + for (i = 0; i < state->total_separate_uvs; i++) { + final_position[i].uv[0] /= final_position[i].count; + final_position[i].uv[1] /= final_position[i].count; + } + } + /* second pass, calculate island rotation and translation before modifying any uvs */ if (state->snap_islands) { if (state->mode == STITCH_VERT) { @@ -1211,11 +1229,6 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) for (i = 0; i < state->total_separate_uvs; i++) { UvElement *element = state->uvs[i]; - if (stitch_midpoints) { - final_position[i].uv[0] /= final_position[i].count; - final_position[i].uv[1] /= final_position[i].count; - } - if (element->flag & STITCH_STITCHABLE) { BMLoop *l; MLoopUV *luv; @@ -1419,18 +1432,19 @@ static void stitch_switch_selection_mode(StitchState *state) MEM_freeN(old_selection_stack); } -static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal) +static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal, float aspect) { BMLoop *l1 = edge->element->l; - BMLoop *l2 = l1->next; MLoopUV *luv1, *luv2; float tangent[2]; luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV); - luv2 = CustomData_bmesh_get(&em->bm->ldata, l2->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV); sub_v2_v2v2(tangent, luv2->uv, luv1->uv); + tangent[1] /= aspect; + normal[0] = tangent[1]; normal[1] = -tangent[0]; @@ -1447,6 +1461,8 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *ar glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); + glPointSize(pointsize * 2.0f); + glEnable(GL_BLEND); UI_ThemeColor4(TH_STITCH_PREVIEW_ACTIVE); @@ -1462,19 +1478,18 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *ar glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE); glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]); + #if 0 + glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); + UI_ThemeColor4(TH_STITCH_PREVIEW_VERT); + glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]); + #endif index += stitch_preview->uvs_per_polygon[i]; } - glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); -#if 0 - UI_ThemeColor4(TH_STITCH_PREVIEW_VERT); - glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris * 3); -#endif glDisable(GL_BLEND); /* draw vert preview */ if (state->mode == STITCH_VERT) { - glPointSize(pointsize * 2.0f); UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE); glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable); glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable); @@ -1541,7 +1556,7 @@ static int stitch_init(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; ARegion *ar = CTX_wm_region(C); - + float aspx, aspy; Object *obedit = CTX_data_edit_object(C); if (!ar) @@ -1595,6 +1610,9 @@ static int stitch_init(bContext *C, wmOperator *op) return 0; } + uvedit_get_aspect(scene, obedit, em, &aspx, &aspy); + state->aspect = aspx / aspy; + /* Entirely possible if redoing last operator that static island is bigger than total number of islands. * This ensures we get no hang in the island checking code in stitch_stitch_process_data. */ state->static_island %= state->element_map->totalIslands; @@ -1720,15 +1738,16 @@ static int stitch_init(bContext *C, wmOperator *op) * the winding of the polygon (assuming counter-clockwise flow). */ for (i = 0; i < total_edges; i++) { + UvEdge *edge = edges + i; float normal[2]; - if (edges[i].flag & STITCH_BOUNDARY) { - stitch_calculate_edge_normal(em, edges + i, normal); + if (edge->flag & STITCH_BOUNDARY) { + stitch_calculate_edge_normal(em, edge, normal, state->aspect); - add_v2_v2(state->normals + edges[i].uv1 * 2, normal); - add_v2_v2(state->normals + edges[i].uv2 * 2, normal); + add_v2_v2(state->normals + edge->uv1 * 2, normal); + add_v2_v2(state->normals + edge->uv2 * 2, normal); - normalize_v2(state->normals + edges[i].uv1 * 2); - normalize_v2(state->normals + edges[i].uv2 * 2); + normalize_v2(state->normals + edge->uv1 * 2); + normalize_v2(state->normals + edge->uv2 * 2); } } diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 2ca711a4a6a..81f548b2b5d 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -196,7 +196,7 @@ static int uvedit_have_selection(Scene *scene, BMEditMesh *em, short implicit) return 0; } -static void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, float *aspy) +void uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, float *aspy) { int sloppy = TRUE; int selected = FALSE; @@ -238,7 +238,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMEditMesh if (correct_aspect) { float aspx, aspy; - ED_uvedit_get_aspect(scene, ob, em, &aspx, &aspy); + uvedit_get_aspect(scene, ob, em, &aspx, &aspy); if (aspx != aspy) param_aspect_ratio(handle, aspx, aspy); @@ -423,7 +423,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B if (correct_aspect) { float aspx, aspy; - ED_uvedit_get_aspect(scene, ob, em, &aspx, &aspy); + uvedit_get_aspect(scene, ob, em, &aspx, &aspy); if (aspx != aspy) param_aspect_ratio(handle, aspx, aspy); @@ -1047,7 +1047,7 @@ static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em) BMFace *efa; float scale, aspx, aspy; - ED_uvedit_get_aspect(scene, ob, em, &aspx, &aspy); + uvedit_get_aspect(scene, ob, em, &aspx, &aspy); if (aspx == aspy) return; @@ -1563,7 +1563,6 @@ static int cylinder_project_exec(bContext *C, wmOperator *op) uv_map_transform(C, op, center, rotmat); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) continue; @@ -1573,6 +1572,7 @@ static int cylinder_project_exec(bContext *C, wmOperator *op) uv_cylinder_project(luv->uv, l->v->co, center, rotmat); } + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); uv_map_mirror(em, efa, tf); } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 356b752466e..f80761c3cc7 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -117,6 +117,10 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render* re, int render_count) : Str freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG; BKE_scene_disable_color_management(freestyle_scene); + // Render layer + SceneRenderLayer *srl = (SceneRenderLayer *)freestyle_scene->r.layers.first; + srl->layflag = SCE_LAY_SOLID | SCE_LAY_ZTRA; + BKE_scene_set_background(G.main, freestyle_scene); // Camera diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 9ce42d9e0bb..6abc41759e7 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -28,6 +28,7 @@ set(INC ../blenkernel ../blenlib ../blenloader + ../bmesh ../imbuf ../makesdna ../makesrna diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 36fbd818f11..9f6f80585ab 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -39,12 +39,15 @@ #define DEBUG_VBO(X) #endif +struct BMesh; struct CCGElem; struct CCGKey; struct CustomData; struct DMFlagMat; struct DerivedMesh; +struct GHash; struct GPUVertPointLink; +struct PBVH; typedef struct GPUBuffer { int size; /* in bytes */ @@ -168,12 +171,21 @@ void GPU_update_mesh_buffers(GPU_Buffers *buffers, MVert *mvert, GPU_Buffers *GPU_build_grid_buffers(int *grid_indices, int totgrid, unsigned int **grid_hidden, int gridsize); +GPU_Buffers *GPU_build_bmesh_buffers(int smooth_shading); + +void GPU_update_bmesh_buffers(GPU_Buffers *buffers, + struct BMesh *bm, + struct GHash *bm_faces, + struct GHash *bm_unique_verts, + struct GHash *bm_other_verts); + void GPU_update_grid_buffers(GPU_Buffers *buffers, struct CCGElem **grids, const struct DMFlagMat *grid_flag_mats, int *grid_indices, int totgrid, const struct CCGKey *key, int show_diffuse_color); -void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial); +void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial, + int wireframe); int GPU_buffers_diffuse_changed(GPU_Buffers *buffers, int show_diffuse_color); diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript index aeb7edc2c56..f7db3dfeaa0 100644 --- a/source/blender/gpu/SConscript +++ b/source/blender/gpu/SConscript @@ -33,7 +33,7 @@ sources += env.Glob('shaders/*.c') defs = [ 'GLEW_STATIC' ] incs = '../blenlib ../blenkernel ../makesdna ../makesrna ../include ../blenloader ../nodes ../nodes/intern' -incs += ' #/extern/glew/include #intern/guardedalloc #intern/smoke/extern ../imbuf .' +incs += ' #/extern/glew/include #intern/guardedalloc #intern/smoke/extern ../imbuf ../bmesh .' if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index daf97c4841f..5f9f68e9c99 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -57,6 +57,8 @@ #include "GPU_buffers.h" #include "GPU_draw.h" +#include "bmesh.h" + typedef enum { GPU_BUFFER_VERTEX_STATE = 1, GPU_BUFFER_NORMAL_STATE = 2, @@ -1269,6 +1271,8 @@ struct GPU_Buffers { int totgrid; int has_hidden; + int use_bmesh; + unsigned int tot_tri, tot_quad; /* The PBVH ensures that either all faces in the node are @@ -1862,6 +1866,254 @@ GPU_Buffers *GPU_build_grid_buffers(int *grid_indices, int totgrid, #undef FILL_QUAD_BUFFER +/* Output a BMVert into a VertexBufferFormat array + * + * The vertex is skipped if hidden, otherwise the output goes into + * index '*v_index' in the 'vert_data' array and '*v_index' is + * incremented. + */ +static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, BMesh *bm, + VertexBufferFormat *vert_data, + int *v_index, + const float fno[3], + const float *fmask) +{ + VertexBufferFormat *vd = &vert_data[*v_index]; + float *mask; + + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + /* TODO: should use material color */ + float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; + + /* Set coord, normal, and mask */ + copy_v3_v3(vd->co, v->co); + normal_float_to_short_v3(vd->no, fno ? fno : v->no); + mask = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_PAINT_MASK); + gpu_color_from_mask_copy(fmask ? *fmask : *mask, + diffuse_color, + vd->color); + + + /* Assign index for use in the triangle index buffer */ + BM_elem_index_set(v, (*v_index)); /* set_dirty! */ + + (*v_index)++; + } +} + +/* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */ +static int gpu_bmesh_vert_visible_count(GHash *bm_unique_verts, + GHash *bm_other_verts) +{ + GHashIterator gh_iter; + int totvert = 0; + + GHASH_ITER (gh_iter, bm_unique_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + totvert++; + } + GHASH_ITER (gh_iter, bm_other_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + totvert++; + } + + return totvert; +} + +/* Return TRUE if all vertices in the face are visible, FALSE otherwise */ +static int gpu_bmesh_face_visible(BMFace *f) +{ + BMIter bm_iter; + BMVert *v; + + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + return FALSE; + } + + return TRUE; +} + +/* Return the total number of visible faces */ +static int gpu_bmesh_face_visible_count(GHash *bm_faces) +{ + GHashIterator gh_iter; + int totface = 0; + + GHASH_ITER (gh_iter, bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + if (gpu_bmesh_face_visible(f)) + totface++; + } + + return totface; +} + +/* Creates a vertex buffer (coordinate, normal, color) and, if smooth + shading, an element index buffer. */ +void GPU_update_bmesh_buffers(GPU_Buffers *buffers, + BMesh *bm, + GHash *bm_faces, + GHash *bm_unique_verts, + GHash *bm_other_verts) +{ + VertexBufferFormat *vert_data; + void *tri_data; + int tottri, totvert, maxvert = 0; + + if (!buffers->vert_buf || (buffers->smooth && !buffers->index_buf)) + return; + + /* Count visible triangles */ + tottri = gpu_bmesh_face_visible_count(bm_faces); + + if (buffers->smooth) { + /* Count visible vertices */ + totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts); + } + else + totvert = tottri * 3; + + /* Initialize vertex buffer */ + glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, + sizeof(VertexBufferFormat) * totvert, + NULL, GL_STATIC_DRAW_ARB); + + /* Fill vertex buffer */ + vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + if (vert_data) { + GHashIterator gh_iter; + int v_index = 0; + + if (buffers->smooth) { + /* Vertices get an index assigned for use in the triangle + index buffer */ + bm->elem_index_dirty |= BM_VERT; + + GHASH_ITER (gh_iter, bm_unique_verts) { + gpu_bmesh_vert_to_buffer_copy(BLI_ghashIterator_getKey(&gh_iter), + bm, vert_data, &v_index, NULL, NULL); + } + + GHASH_ITER (gh_iter, bm_other_verts) { + gpu_bmesh_vert_to_buffer_copy(BLI_ghashIterator_getKey(&gh_iter), + bm, vert_data, &v_index, NULL, NULL); + } + + maxvert = v_index; + } + else { + GHASH_ITER (gh_iter, bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + BLI_assert(f->len == 3); + + if (gpu_bmesh_face_visible(f)) { + BMVert *v[3]; + float fmask = 0; + int i; + + BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void**)v, 3); + + /* Average mask value */ + for (i = 0; i < 3; i++) { + fmask += *((float*)CustomData_bmesh_get(&bm->vdata, + v[i]->head.data, + CD_PAINT_MASK)); + } + fmask /= 3.0f; + + for (i = 0; i < 3; i++) { + gpu_bmesh_vert_to_buffer_copy(v[i], bm, vert_data, + &v_index, f->no, &fmask); + } + } + } + + buffers->tot_tri = tottri; + } + + glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + } + else { + /* Memory map failed */ + glDeleteBuffersARB(1, &buffers->vert_buf); + buffers->vert_buf = 0; + return; + } + + if (buffers->smooth) { + const int use_short = (maxvert < USHRT_MAX); + + /* Initialize triangle index buffer */ + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, + (use_short ? + sizeof(unsigned short) : + sizeof(unsigned int)) * 3 * tottri, + NULL, GL_STATIC_DRAW_ARB); + + /* Fill triangle index buffer */ + tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + if (tri_data) { + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, bm_faces) { + BMIter bm_iter; + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BMVert *v; + + if (gpu_bmesh_face_visible(f)) { + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + if (use_short) { + unsigned short *elem = tri_data; + (*elem) = BM_elem_index_get(v); + elem++; + tri_data = elem; + } + else { + unsigned int *elem = tri_data; + (*elem) = BM_elem_index_get(v); + elem++; + tri_data = elem; + } + } + } + } + + glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); + + buffers->tot_tri = tottri; + buffers->index_type = (use_short ? + GL_UNSIGNED_SHORT : + GL_UNSIGNED_INT); + } + else { + /* Memory map failed */ + glDeleteBuffersARB(1, &buffers->index_buf); + buffers->index_buf = 0; + } + } +} + +GPU_Buffers *GPU_build_bmesh_buffers(int smooth_shading) +{ + GPU_Buffers *buffers; + + buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers"); + if (smooth_shading) + glGenBuffersARB(1, &buffers->index_buf); + glGenBuffersARB(1, &buffers->vert_buf); + buffers->use_bmesh = TRUE; + buffers->smooth = smooth_shading; + + return buffers; +} + static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers) { const MVert *mvert = buffers->mvert; @@ -2060,7 +2312,8 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers) } } -void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) +void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial, + int wireframe) { if (buffers->totface) { const MFace *f = &buffers->mface[buffers->face_indices[0]]; @@ -2077,14 +2330,19 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) if (buffers->vert_buf) { glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - gpu_colors_enable(VBO_ENABLED); + if (!wireframe) { + glEnableClientState(GL_NORMAL_ARRAY); + gpu_colors_enable(VBO_ENABLED); + } glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); if (buffers->index_buf) glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); + if (wireframe) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + if (buffers->tot_quad) { char *offset = 0; int i, last = buffers->has_hidden ? 1 : buffers->totgrid; @@ -2117,13 +2375,18 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) glDrawArrays(GL_TRIANGLES, 0, totelem); } + if (wireframe) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); if (buffers->index_buf) glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - gpu_colors_disable(VBO_ENABLED); + if (!wireframe) { + glDisableClientState(GL_NORMAL_ARRAY); + gpu_colors_disable(VBO_ENABLED); + } } /* fallbacks if we are out of memory or VBO is disabled */ else if (buffers->totface) { diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 07462302700..254899e6e07 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -92,7 +92,7 @@ void GPU_render_text(MTFace *tface, int mode, float *v1, float *v2, float *v3, float *v4, int glattrib) { if ((mode & GEMAT_TEXT) && (textlen>0) && tface->tpage) { - Image* ima = (Image*)tface->tpage; + Image* ima = (Image *)tface->tpage; int index, character; float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance; float advance_tab; @@ -556,8 +556,9 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int if (do_color_management) { srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(float)*4, "floar_buf_col_cor"); IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float, - ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, 0, + ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); + IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y); /* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */ IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y); frect= srgb_frect + texwinsy*ibuf->x + texwinsx; @@ -581,8 +582,9 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int if (do_color_management) { frect = srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(*srgb_frect)*4, "floar_buf_col_cor"); IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float, - ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, 0, + ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); + IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y); /* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */ IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y); } @@ -813,7 +815,7 @@ void GPU_create_gl_tex_compressed(unsigned int *bind, unsigned int *pix, int x, glBindTexture(GL_TEXTURE_2D, *bind); if (GPU_upload_dxt_texture(ibuf) == 0) { - glDeleteTextures(1, (GLuint*)bind); + glDeleteTextures(1, (GLuint *)bind); GPU_create_gl_tex(bind, pix, NULL, x, y, mipmap, 0, ima); } #endif diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 7a0ac29c9ab..bc859d0ec07 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -134,8 +134,8 @@ void GPU_extensions_init(void) glGetIntegerv(GL_BLUE_BITS, &b); GG.colordepth = r+g+b; /* assumes same depth for RGB */ - vendor = (const char*)glGetString(GL_VENDOR); - renderer = (const char*)glGetString(GL_RENDERER); + vendor = (const char *)glGetString(GL_VENDOR); + renderer = (const char *)glGetString(GL_RENDERER); if (strstr(vendor, "ATI")) { GG.device = GPU_DEVICE_ATI; @@ -916,7 +916,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object); GPU_shader_bind(blur_shader); - GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float*)scaleh); + GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scaleh); GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex); glViewport(0, 0, GPU_texture_opengl_width(blurtex), GPU_texture_opengl_height(blurtex)); @@ -942,7 +942,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); glViewport(0, 0, GPU_texture_opengl_width(tex), GPU_texture_opengl_height(tex)); - GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float*)scalev); + GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scalev); GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); GPU_texture_bind(blurtex, 0); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 2039f01a740..a2fc1eb05ec 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -1035,8 +1035,7 @@ static void do_material_tex(GPUShadeInput *shi) GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, FALSE), &tin, &trgb); rgbnor= TEX_RGB; - if (tex->imaflag & TEX_USEALPHA) - talpha= 1; + talpha= 1; } else { continue; diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index 75aaa23369b..67f0694797b 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -372,7 +372,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though * strictly speaking, it is a posechannel) */ - get_constraint_target_matrix(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); + BKE_get_constraint_target_matrix(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); /* and set and transform goal */ mult_m4_m4m4(goal, goalinv, rootmat); @@ -383,7 +383,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) /* same for pole vector target */ if (data->poletar) { - get_constraint_target_matrix(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); + BKE_get_constraint_target_matrix(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); if (data->flag & CONSTRAINT_IK_SETANGLE) { /* don't solve IK when we are setting the pole angle */ diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index 903080d5b79..e1ef7d92bd0 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -370,7 +370,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co static bool is_cartesian_constraint(bConstraint *con) { - //bKinematicConstraint* data=(bKinematicConstraint*)con->data; + //bKinematicConstraint* data=(bKinematicConstraint *)con->data; return true; } @@ -551,7 +551,7 @@ static bool target_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Fram bConstraint *constraint = (bConstraint *)target->blenderConstraint; float tarmat[4][4]; - get_constraint_target_matrix(target->blscene, constraint, 0, CONSTRAINT_OBTYPE_OBJECT, target->owner, tarmat, 1.0); + BKE_get_constraint_target_matrix(target->blscene, constraint, 0, CONSTRAINT_OBTYPE_OBJECT, target->owner, tarmat, 1.0); // rootmat contains the target pose in world coordinate // if enforce is != 1.0, blend the target position with the end effector position @@ -620,7 +620,7 @@ static bool base_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Frame& IK_Channel &rootchan = ikscene->channels[0]; // get polar target matrix in world space - get_constraint_target_matrix(ikscene->blscene, ikscene->polarConstraint, 1, CONSTRAINT_OBTYPE_OBJECT, ikscene->blArmature, mat, 1.0); + BKE_get_constraint_target_matrix(ikscene->blscene, ikscene->polarConstraint, 1, CONSTRAINT_OBTYPE_OBJECT, ikscene->blArmature, mat, 1.0); // convert to armature space mult_m4_m4m4(polemat, imat, mat); // get the target in world space (was computed before as target object are defined before base object) @@ -864,7 +864,7 @@ static bool joint_callback(const iTaSC::Timestamp& timestamp, iTaSC::ConstraintV } // build array of joint corresponding to IK chain -static int convert_channels(IK_Scene *ikscene, PoseTree *tree) +static int convert_channels(IK_Scene *ikscene, PoseTree *tree, float ctime) { IK_Channel *ikchan; bPoseChannel *pchan; @@ -877,6 +877,14 @@ static int convert_channels(IK_Scene *ikscene, PoseTree *tree) ikchan->parent = (a > 0) ? tree->parent[a] : -1; ikchan->owner = ikscene->blArmature; + // the constraint and channels must be applied before we build the iTaSC scene, + // this is because some of the pose data (e.g. pose head) don't have corresponding + // joint angles and can't be applied to the iTaSC armature dynamically + if (!(pchan->flag & POSE_DONE)) + BKE_pose_where_is_bone(ikscene->blscene, ikscene->blArmature, pchan, ctime, 1); + // tell blender that this channel was controlled by IK, it's cleared on each BKE_pose_where_is() + pchan->flag |= (POSE_DONE | POSE_CHAIN); + /* set DoF flag */ flag = 0; if (!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP) && @@ -1049,7 +1057,7 @@ static void BKE_pose_rest(IK_Scene *ikscene) } } -static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) +static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, float ctime) { PoseTree *tree = (PoseTree *)pchan->iktree.first; PoseTarget *target; @@ -1068,6 +1076,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) float length; bool ret = true, ingame; double *rot; + float start[3]; if (tree->totchannel == 0) return NULL; @@ -1126,7 +1135,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) std::vector<double> weights; double weight[3]; // build the array of joints corresponding to the IK chain - convert_channels(ikscene, tree); + convert_channels(ikscene, tree, ctime); if (ingame) { // in the GE, set the initial joint angle to match the current pose // this will update the jointArray in ikscene @@ -1137,17 +1146,37 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) BKE_pose_rest(ikscene); } rot = ikscene->jointArray(0); + for (a = 0, ikchan = ikscene->channels; a < tree->totchannel; ++a, ++ikchan) { pchan = ikchan->pchan; bone = pchan->bone; KDL::Frame tip(iTaSC::F_identity); + // compute the position and rotation of the head from previous segment Vector3 *fl = bone->bone_mat; KDL::Rotation brot( fl[0][0], fl[1][0], fl[2][0], fl[0][1], fl[1][1], fl[2][1], fl[0][2], fl[1][2], fl[2][2]); - KDL::Vector bpos(bone->head[0], bone->head[1], bone->head[2]); + // if the bone is disconnected, the head is movable in pose mode + // take that into account by using pose matrix instead of bone + // Note that pose is expressed in armature space, convert to previous bone space + { + float R_parmat[3][3]; + float iR_parmat[3][3]; + if (pchan->parent) + copy_m3_m4(R_parmat, pchan->parent->pose_mat); + else + unit_m3(R_parmat); + if (pchan->parent) + sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail); + else + start[0] = start[1] = start[2] = 0.0f; + invert_m3_m3(iR_parmat, R_parmat); + normalize_m3(iR_parmat); + mul_m3_v3(iR_parmat, start); + } + KDL::Vector bpos(start[0], start[1], start[2]); bpos *= ikscene->blScale; KDL::Frame head(brot, bpos); @@ -1155,7 +1184,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) length = bone->length * ikscene->blScale; parent = (a > 0) ? ikscene->channels[tree->parent[a]].tail : root; // first the fixed segment to the bone head - if (head.p.Norm() > KDL::epsilon || head.M.GetRot().Norm() > KDL::epsilon) { + if (!(ikchan->pchan->bone->flag & BONE_CONNECTED) || head.M.GetRot().Norm() > KDL::epsilon) { joint = bone->name; joint += ":H"; ret = arm->addSegment(joint, parent, KDL::Joint::None, 0.0, head); @@ -1497,7 +1526,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) return ikscene; } -static void create_scene(Scene *scene, Object *ob) +static void create_scene(Scene *scene, Object *ob, float ctime) { bPoseChannel *pchan; @@ -1508,7 +1537,7 @@ static void create_scene(Scene *scene, Object *ob) if (tree) { IK_Data *ikdata = get_ikdata(ob->pose); // convert tree in iTaSC::Scene - IK_Scene *ikscene = convert_tree(scene, ob, pchan); + IK_Scene *ikscene = convert_tree(scene, ob, pchan, ctime); if (ikscene) { ikscene->next = ikdata->first; ikdata->first = ikscene; @@ -1732,15 +1761,21 @@ void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime) count += initialize_scene(ob, pchan); } // if at least one tree, create the scenes from the PoseTree stored in the channels - if (count) - create_scene(scene, ob); - itasc_update_param(ob->pose); + // postpone until execute_tree: this way the pose constraint are included + //if (count) + // create_scene(scene, ob, ctime); + //itasc_update_param(ob->pose); // make sure we don't rebuilt until the user changes something important ob->pose->flag &= ~POSE_WAS_REBUILT; } void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime) { + if (!ob->pose->ikdata) { + // IK tree not yet created, no it now + create_scene(scene, ob, ctime); + itasc_update_param(ob->pose); + } if (ob->pose->ikdata) { IK_Data *ikdata = (IK_Data *)ob->pose->ikdata; bItasc *ikparam = (bItasc *) ob->pose->ikparam; diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index 0653956e113..1e33f8da363 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -138,6 +138,7 @@ struct ColormanageProcessor *IMB_colormanagement_display_processor_new(const str const struct ColorManagedDisplaySettings *display_settings); struct ColormanageProcessor *IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace); void IMB_colormanagement_processor_apply_v4(struct ColormanageProcessor *cm_processor, float pixel[4]); +void IMB_colormanagement_processor_apply_v4_predivide(struct ColormanageProcessor *cm_processor, float pixel[4]); void IMB_colormanagement_processor_apply_v3(struct ColormanageProcessor *cm_processor, float pixel[3]); void IMB_colormanagement_processor_apply(struct ColormanageProcessor *cm_processor, float *buffer, int width, int height, int channels, int predivide); diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index db1404813b1..850060ef4d5 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -373,7 +373,6 @@ void IMB_rect_from_float(struct ImBuf *ibuf); * Changed part will be stored in buffer. This is expected to be used for texture painting updates */ void IMB_partial_rect_from_float(struct ImBuf *ibuf, float *buffer, int x, int y, int w, int h, int is_data); void IMB_float_from_rect(struct ImBuf *ibuf); -void IMB_float_from_rect_simple(struct ImBuf *ibuf); /* no profile conversion */ /* note, check that the conversion exists, only some are supported */ float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc); void IMB_color_to_bw(struct ImBuf *ibuf); @@ -393,6 +392,8 @@ void IMB_buffer_byte_from_byte(unsigned char *rect_to, const unsigned char *rect int profile_to, int profile_from, int predivide, int width, int height, int stride_to, int stride_from); void IMB_buffer_float_clamp(float *buf, int width, int height); +void IMB_buffer_float_unpremultiply(float *buf, int width, int height); +void IMB_buffer_float_premultiply(float *buf, int width, int height); /** * Change the ordering of the color bytes pointed to by rect from @@ -467,6 +468,7 @@ void IMB_flipy(struct ImBuf *ibuf); /* Premultiply alpha */ void IMB_premultiply_alpha(struct ImBuf *ibuf); +void IMB_unpremultiply_alpha(struct ImBuf *ibuf); /** * diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 28e62d496b2..49e2e7fc80d 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -167,14 +167,15 @@ typedef struct ImBuf { #define IB_animdeinterlace (1 << 9) #define IB_tiles (1 << 10) #define IB_tilecache (1 << 11) -#define IB_premul (1 << 12) -#define IB_cm_predivide (1 << 13) +#define IB_alphamode_premul (1 << 12) /* indicates whether image on disk have premul alpha */ +#define IB_alphamode_detect (1 << 13) /* if this flag is set, alpha mode would be guessed from file */ +#define IB_ignore_alpha (1 << 14) /* ignore alpha on load and substitude it with 1.0f */ /* * The bit flag is stored in the ImBuf.ftype variable. - * Note that the lower 10 bits is used for storing custom flags + * Note that the lower 11 bits is used for storing custom flags */ -#define IB_CUSTOM_FLAGS_MASK 0x3ff +#define IB_CUSTOM_FLAGS_MASK 0x400 #define PNG (1 << 30) #define TGA (1 << 28) @@ -217,8 +218,12 @@ typedef struct ImBuf { #define JP2_YCC (1 << 15) #define JP2_CINE (1 << 14) #define JP2_CINE_48FPS (1 << 13) +#define JP2_JP2 (1 << 12) +#define JP2_J2K (1 << 11) #endif +#define PNG_16BIT (1 << 10) + #define RAWTGA (TGA | 1) #define JPG_STD (JPG | (0 << 8)) diff --git a/source/blender/imbuf/intern/IMB_filter.h b/source/blender/imbuf/intern/IMB_filter.h index eaedb160c94..6bd5f44307f 100644 --- a/source/blender/imbuf/intern/IMB_filter.h +++ b/source/blender/imbuf/intern/IMB_filter.h @@ -41,6 +41,9 @@ void imb_filterx(struct ImBuf *ibuf); void IMB_premultiply_rect(unsigned int *rect, char planes, int w, int h); void IMB_premultiply_rect_float(float *rect_float, char planes, int w, int h); +void IMB_unpremultiply_rect(unsigned int *rect, char planes, int w, int h); +void IMB_unpremultiply_rect_float(float *rect_float, char planes, int w, int h); + void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1); #endif diff --git a/source/blender/imbuf/intern/IMB_metadata.h b/source/blender/imbuf/intern/IMB_metadata.h index a68d7a7813e..f731fd69620 100644 --- a/source/blender/imbuf/intern/IMB_metadata.h +++ b/source/blender/imbuf/intern/IMB_metadata.h @@ -42,7 +42,7 @@ typedef struct ImMetaData { int len; } ImMetaData; -/** The metadata is a list of key/value pairs (both char*) that can me +/** The metadata is a list of key/value pairs (both char *) that can me * saved in the header of several image formats. * Apart from some common keys like * 'Software' and 'Description' (png standard) we'll use keys within the diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c index c8bc3f8ebb8..ba84063f317 100644 --- a/source/blender/imbuf/intern/cineon/cineon_dpx.c +++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c @@ -95,6 +95,9 @@ static struct ImBuf *imb_load_dpx_cineon(unsigned char *mem, size_t size, int us if (flags & IB_rect) IMB_rect_from_float(ibuf); + if (flags & IB_alphamode_detect) + ibuf->flags |= IB_alphamode_premul; + return ibuf; } diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 1c68a466ade..bcfddfe425a 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -189,7 +189,6 @@ typedef struct ColormnaageCacheData { int flag; /* view flags of cached buffer */ float exposure; /* exposure value cached buffer is calculated with */ float gamma; /* gamma value cached buffer is calculated with */ - int predivide; /* predivide flag of cached buffer */ CurveMapping *curve_mapping; /* curve mapping used for cached buffer */ int curve_mapping_timestamp; /* time stamp of curve mapping used for cached buffer */ } ColormnaageCacheData; @@ -323,7 +322,6 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV ColormanageCacheKey key; ImBuf *cache_ibuf; int view_flag = 1 << (view_settings->view - 1); - int predivide = ibuf->flags & IB_cm_predivide; CurveMapping *curve_mapping = view_settings->curve_mapping; int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0; @@ -353,7 +351,6 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV if (cache_data->exposure != view_settings->exposure || cache_data->gamma != view_settings->gamma || - cache_data->predivide != predivide || cache_data->flag != view_settings->flag || cache_data->curve_mapping != curve_mapping || cache_data->curve_mapping_timestamp != curve_mapping_timestamp) @@ -379,7 +376,6 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting ImBuf *cache_ibuf; ColormnaageCacheData *cache_data; int view_flag = 1 << (view_settings->view - 1); - int predivide = ibuf->flags & IB_cm_predivide; struct MovieCache *moviecache = colormanage_moviecache_ensure(ibuf); CurveMapping *curve_mapping = view_settings->curve_mapping; int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0; @@ -400,7 +396,6 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting cache_data = MEM_callocN(sizeof(ColormnaageCacheData), "color manage cache imbuf data"); cache_data->exposure = view_settings->exposure; cache_data->gamma = view_settings->gamma; - cache_data->predivide = predivide; cache_data->flag = view_settings->flag; cache_data->curve_mapping = curve_mapping; cache_data->curve_mapping_timestamp = curve_mapping_timestamp; @@ -897,13 +892,12 @@ void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace) if (ibuf->rect_float) { const char *to_colorspace = global_role_scene_linear; - int predivide = ibuf->flags & IB_cm_predivide; if (ibuf->rect) imb_freerectImBuf(ibuf); IMB_colormanagement_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, predivide); + from_colorspace, to_colorspace, TRUE); } } @@ -1130,7 +1124,6 @@ typedef struct DisplayBufferThread { int channels; float dither; - int predivide; int is_data; const char *byte_colorspace; @@ -1158,7 +1151,6 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l DisplayBufferInitData *init_data = (DisplayBufferInitData *) init_data_v; ImBuf *ibuf = init_data->ibuf; - int predivide = ibuf->flags & IB_cm_predivide; int channels = ibuf->channels; float dither = ibuf->dither; int is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA; @@ -1189,7 +1181,6 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l handle->channels = channels; handle->dither = dither; - handle->predivide = predivide; handle->is_data = is_data; handle->byte_colorspace = init_data->byte_colorspace; @@ -1206,7 +1197,6 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle) int buffer_size = channels * width * height; - int predivide = handle->predivide; int is_data = handle->is_data; int is_data_display = handle->cm_processor->is_data_result; @@ -1224,16 +1214,25 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle) /* first convert byte buffer to float, keep in image space */ for (i = 0, fp = linear_buffer, cp = byte_buffer; - i < channels * width * height; - i++, fp++, cp++) + i < width * height; + i++, fp += channels, cp += channels) { - *fp = (float)(*cp) / 255.0f; + if (channels == 3) { + rgb_uchar_to_float(fp, cp); + } + else if (channels == 4) { + rgba_uchar_to_float(fp, cp); + straight_to_premul_v4(fp, fp); + } + else { + BLI_assert(!"Buffers of 3 or 4 channels are only supported here"); + } } if (!is_data && !is_data_display) { /* convert float buffer to scene linear space */ IMB_colormanagement_transform(linear_buffer, width, height, channels, - from_colorspace, to_colorspace, predivide); + from_colorspace, to_colorspace, TRUE); } } else if (handle->float_colorspace) { @@ -1249,7 +1248,7 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle) memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float)); IMB_colormanagement_transform(linear_buffer, width, height, channels, - from_colorspace, to_colorspace, predivide); + from_colorspace, to_colorspace, TRUE); } else { /* some processors would want to modify float original buffer @@ -1277,13 +1276,12 @@ static void *do_display_buffer_apply_thread(void *handle_v) int width = handle->width; int height = handle->tot_line; float dither = handle->dither; - int predivide = handle->predivide; int is_data = handle->is_data; if (cm_processor == NULL) { if (display_buffer_byte) { IMB_buffer_byte_from_byte(display_buffer_byte, handle->byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB, - FALSE, width, height, width, width); + FALSE, width, height, width, width); } if (display_buffer) { @@ -1301,7 +1299,7 @@ static void *do_display_buffer_apply_thread(void *handle_v) } else { /* apply processor */ - IMB_colormanagement_processor_apply(cm_processor, linear_buffer, width, height, channels, predivide); + IMB_colormanagement_processor_apply(cm_processor, linear_buffer, width, height, channels, TRUE); } /* copy result to output buffers */ @@ -1309,7 +1307,7 @@ static void *do_display_buffer_apply_thread(void *handle_v) /* do conversion */ IMB_buffer_byte_from_float(display_buffer_byte, linear_buffer, channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, - predivide, width, height, width, width); + TRUE, width, height, width, width); } if (display_buffer) @@ -1663,7 +1661,7 @@ static void colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorMan if (global_tot_display == 0 || global_tot_view == 0) { IMB_buffer_float_from_float(ibuf->rect_float, ibuf->rect_float, ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, - ibuf->flags & IB_cm_predivide, ibuf->x, ibuf->y, ibuf->x, ibuf->x); + TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); } else { colormanage_display_buffer_process_ex(ibuf, ibuf->rect_float, (unsigned char *)ibuf->rect, @@ -2326,7 +2324,6 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe { int x, y; int channels = ibuf->channels; - int predivide = ibuf->flags & IB_cm_predivide; float dither = ibuf->dither; ColorSpace *rect_colorspace = ibuf->rect_colorspace; float *display_buffer_float = NULL; @@ -2350,13 +2347,11 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe else if (byte_buffer) { rgba_uchar_to_float(pixel, byte_buffer + linear_index); IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, rect_colorspace); + straight_to_premul_v4(pixel, pixel); } if (!is_data) { - if (predivide) - IMB_colormanagement_processor_apply_v4(cm_processor, pixel); - else - IMB_colormanagement_processor_apply_v4(cm_processor, pixel); + IMB_colormanagement_processor_apply_v4_predivide(cm_processor, pixel); } if (display_buffer_float) { @@ -2365,7 +2360,9 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe copy_v4_v4(display_buffer_float + index, pixel); } else { - rgba_float_to_uchar(display_buffer + display_index, pixel); + float pixel_straight[4]; + premul_to_straight_v4(pixel_straight, pixel); + rgba_float_to_uchar(display_buffer + display_index, pixel_straight); } } } @@ -2389,7 +2386,6 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, /* update byte buffer created by legacy color management */ unsigned char *rect = (unsigned char *) ibuf->rect; - int predivide = ibuf->flags & IB_cm_predivide; int channels = ibuf->channels; int width = xmax - xmin; int height = ymax - ymin; @@ -2397,7 +2393,7 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, int linear_index = ((ymin - offset_y) * stride + (xmin - offset_x)) * channels; IMB_buffer_byte_from_float(rect + rect_index, linear_buffer + linear_index, channels, ibuf->dither, - IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, predivide, width, height, ibuf->x, stride); + IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE, width, height, ibuf->x, stride); } if (ibuf->display_buffer_flags) { @@ -2503,6 +2499,15 @@ void IMB_colormanagement_processor_apply_v4(ColormanageProcessor *cm_processor, OCIO_processorApplyRGBA(cm_processor->processor, pixel); } +void IMB_colormanagement_processor_apply_v4_predivide(ColormanageProcessor *cm_processor, float pixel[4]) +{ + if (cm_processor->curve_mapping) + curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel); + + if (cm_processor->processor) + OCIO_processorApplyRGBA_predivide(cm_processor->processor, pixel); +} + void IMB_colormanagement_processor_apply_v3(ColormanageProcessor *cm_processor, float pixel[3]) { if (cm_processor->curve_mapping) diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp index 5459cffe590..c41bbd594b3 100644 --- a/source/blender/imbuf/intern/dds/dds_api.cpp +++ b/source/blender/imbuf/intern/dds/dds_api.cpp @@ -164,7 +164,7 @@ struct ImBuf *imb_load_dds(unsigned char *mem, size_t size, int flags, char colo } if (ibuf->dds_data.fourcc != FOURCC_DDS) { - ibuf->dds_data.data = (unsigned char*)dds.readData(ibuf->dds_data.size); + ibuf->dds_data.data = (unsigned char *)dds.readData(ibuf->dds_data.size); /* flip compressed texture */ FlipDXTCImage(dds.width(), dds.height(), dds.mipmapCount(), dds.fourCC(), ibuf->dds_data.data); diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index f049c404e2d..f0d8b7cac72 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -39,6 +39,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_allocimbuf.h" +#include "IMB_filter.h" #include "IMB_colormanagement.h" #include "IMB_colormanagement_intern.h" @@ -249,11 +250,25 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, uchar *to = rect_to + stride_to * y * 4; if (profile_to == profile_from) { + float straight[4]; + /* no color space conversion */ - if (dither) { + if (dither && predivide) { + for (x = 0; x < width; x++, from += 4, to += 4) { + premul_to_straight_v4(straight, from); + float_to_byte_dither_v4(to, straight, di); + } + } + else if (dither) { for (x = 0; x < width; x++, from += 4, to += 4) float_to_byte_dither_v4(to, from, di); } + else if (predivide) { + for (x = 0; x < width; x++, from += 4, to += 4) { + premul_to_straight_v4(straight, from); + rgba_float_to_uchar(to, straight); + } + } else { for (x = 0; x < width; x++, from += 4, to += 4) rgba_float_to_uchar(to, from); @@ -262,10 +277,12 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, else if (profile_to == IB_PROFILE_SRGB) { /* convert from linear to sRGB */ unsigned short us[4]; + float straight[4]; if (dither && predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { - linearrgb_to_srgb_ushort4_predivide(us, from); + premul_to_straight_v4(straight, from); + linearrgb_to_srgb_ushort4(us, from); ushort_to_byte_dither_v4(to, us, di); } } @@ -277,7 +294,8 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, } else if (predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { - linearrgb_to_srgb_ushort4_predivide(us, from); + premul_to_straight_v4(straight, from); + linearrgb_to_srgb_ushort4(us, from); ushort_to_byte_v4(to, us); } } @@ -526,7 +544,6 @@ void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from, void IMB_rect_from_float(ImBuf *ibuf) { - int predivide = (ibuf->flags & IB_cm_predivide); float *buffer; const char *from_colorspace; @@ -548,7 +565,10 @@ void IMB_rect_from_float(ImBuf *ibuf) buffer = MEM_dupallocN(ibuf->rect_float); /* first make float buffer in byte space */ - IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, predivide); + IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, TRUE); + + /* convert from float's premul alpha to byte's straight alpha */ + IMB_unpremultiply_rect_float(buffer, ibuf->planes, ibuf->x, ibuf->y); /* convert float to byte */ IMB_buffer_byte_from_float((unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, @@ -565,7 +585,6 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w { float *rect_float; uchar *rect_byte; - int predivide = (ibuf->flags & IB_cm_predivide); int profile_from = IB_PROFILE_LINEAR_RGB; /* verify we have a float buffer */ @@ -588,12 +607,12 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w /* and do color space conversion to byte */ IMB_buffer_byte_from_float(rect_byte, rect_float, - 4, ibuf->dither, IB_PROFILE_SRGB, profile_from, predivide, + 4, ibuf->dither, IB_PROFILE_SRGB, profile_from, TRUE, w, h, ibuf->x, w); } else { IMB_buffer_float_from_float(buffer, rect_float, - ibuf->channels, IB_PROFILE_SRGB, profile_from, predivide, + ibuf->channels, IB_PROFILE_SRGB, profile_from, TRUE, w, h, w, ibuf->x); /* XXX: need to convert to image buffer's rect space */ @@ -608,8 +627,6 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w void IMB_float_from_rect(ImBuf *ibuf) { - int predivide = (ibuf->flags & IB_cm_predivide); - /* verify if we byte and float buffers */ if (ibuf->rect == NULL) return; @@ -634,22 +651,12 @@ void IMB_float_from_rect(ImBuf *ibuf) /* then make float be in linear space */ IMB_colormanagement_colorspace_to_scene_linear(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - ibuf->rect_colorspace, predivide); - - BLI_unlock_thread(LOCK_COLORMANAGE); -} - -/* no profile conversion */ -void IMB_float_from_rect_simple(ImBuf *ibuf) -{ - int predivide = (ibuf->flags & IB_cm_predivide); + ibuf->rect_colorspace, FALSE); - if (ibuf->rect_float == NULL) - imb_addrectfloatImBuf(ibuf); + /* byte buffer is straight alpha, float should always be premul */ + IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y); - IMB_buffer_float_from_byte(ibuf->rect_float, (uchar *)ibuf->rect, - IB_PROFILE_SRGB, IB_PROFILE_SRGB, predivide, - ibuf->x, ibuf->y, ibuf->x, ibuf->x); + BLI_unlock_thread(LOCK_COLORMANAGE); } /* use when you need to get a buffer with a certain profile @@ -660,7 +667,6 @@ void IMB_float_from_rect_simple(ImBuf *ibuf) */ float *IMB_float_profile_ensure(ImBuf *ibuf, int profile, int *alloc) { - int predivide = (ibuf->flags & IB_cm_predivide); int profile_from = IB_PROFILE_LINEAR_RGB; int profile_to; @@ -686,12 +692,13 @@ float *IMB_float_profile_ensure(ImBuf *ibuf, int profile, int *alloc) if (ibuf->rect_float == NULL) { IMB_buffer_float_from_byte(fbuf, (uchar *)ibuf->rect, - profile_to, profile_from, predivide, + profile_to, profile_from, FALSE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); + IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y); } else { IMB_buffer_float_from_float(fbuf, ibuf->rect_float, - 4, profile_to, profile_from, predivide, + 4, profile_to, profile_from, TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); } @@ -727,6 +734,26 @@ void IMB_buffer_float_clamp(float *buf, int width, int height) } } +void IMB_buffer_float_unpremultiply(float *buf, int width, int height) +{ + int total = width * height; + float *cp = buf; + while (total--) { + premul_to_straight_v4(cp, cp); + cp += 4; + } +} + +void IMB_buffer_float_premultiply(float *buf, int width, int height) +{ + int total = width * height; + float *cp = buf; + while (total--) { + straight_to_premul_v4(cp, cp); + cp += 4; + } +} + /**************************** alter saturation *****************************/ void IMB_saturation(ImBuf *ibuf, float sat) diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c index 678b2908b96..51fee232034 100644 --- a/source/blender/imbuf/intern/filter.c +++ b/source/blender/imbuf/intern/filter.c @@ -599,3 +599,67 @@ void IMB_premultiply_alpha(ImBuf *ibuf) IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y); } +void IMB_unpremultiply_rect(unsigned int *rect, char planes, int w, int h) +{ + char *cp; + int x, y; + float val; + + if (planes == 24) { /* put alpha at 255 */ + cp = (char *)(rect); + + for (y = 0; y < h; y++) + for (x = 0; x < w; x++, cp += 4) + cp[3] = 255; + } + else { + cp = (char *)(rect); + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++, cp += 4) { + val = cp[3] != 0 ? 1.0f / (float)cp[3] : 1.0f; + cp[0] = FTOCHAR(cp[0] * val); + cp[1] = FTOCHAR(cp[1] * val); + cp[2] = FTOCHAR(cp[2] * val); + } + } + } +} + +void IMB_unpremultiply_rect_float(float *rect_float, char planes, int w, int h) +{ + float val, *fp; + int x, y; + + if (planes == 24) { /* put alpha at 1.0 */ + fp = rect_float; + + for (y = 0; y < h; y++) + for (x = 0; x < w; x++, fp += 4) + fp[3] = 1.0; + } + else { + fp = rect_float; + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++, fp += 4) { + val = fp[3] != 0.0f ? 1.0f / fp[3] : 1.0f; + fp[0] = fp[0] * val; + fp[1] = fp[1] * val; + fp[2] = fp[2] * val; + } + } + } + +} + +void IMB_unpremultiply_alpha(ImBuf *ibuf) +{ + if (ibuf == NULL) + return; + + if (ibuf->rect) + IMB_unpremultiply_rect(ibuf->rect, ibuf->planes, ibuf->x, ibuf->y); + + if (ibuf->rect_float) + IMB_unpremultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y); +} diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c index 92b8dd8c724..1eac6236829 100644 --- a/source/blender/imbuf/intern/imageprocess.c +++ b/source/blender/imbuf/intern/imageprocess.c @@ -104,7 +104,7 @@ void bicubic_interpolation_color(struct ImBuf *in, unsigned char outI[4], float BLI_bicubic_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v); } else { - BLI_bicubic_interpolation_char((unsigned char*) in->rect, outI, in->x, in->y, 4, u, v); + BLI_bicubic_interpolation_char((unsigned char *) in->rect, outI, in->x, in->y, 4, u, v); } } @@ -130,7 +130,7 @@ void bilinear_interpolation_color(struct ImBuf *in, unsigned char outI[4], float BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v); } else { - BLI_bilinear_interpolation_char((unsigned char*) in->rect, outI, in->x, in->y, 4, u, v); + BLI_bilinear_interpolation_char((unsigned char *) in->rect, outI, in->x, in->y, 4, u, v); } } diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c index 3a2bf99c75c..8d6218a389e 100644 --- a/source/blender/imbuf/intern/jp2.c +++ b/source/blender/imbuf/intern/jp2.c @@ -228,6 +228,10 @@ struct ImBuf *imb_jp2_decode(unsigned char *mem, size_t size, int flags, char co } ibuf->ftype = JP2; + if (is_jp2) + ibuf->ftype |= JP2_JP2; + else + ibuf->ftype |= JP2_J2K; if (use_float) { float *rect_float = ibuf->rect_float; @@ -852,9 +856,15 @@ int imb_savejp2(struct ImBuf *ibuf, const char *name, int flags) int codestream_length; opj_cio_t *cio = NULL; FILE *f = NULL; + opj_cinfo_t *cinfo = NULL; /* get a JP2 compressor handle */ - opj_cinfo_t *cinfo = opj_create_compress(CODEC_JP2); + if (ibuf->ftype & JP2_JP2) + cinfo = opj_create_compress(CODEC_JP2); + else if (ibuf->ftype & JP2_J2K) + cinfo = opj_create_compress(CODEC_J2K); + else + BLI_assert(!"Unsupported codec was specified in save settings"); /* catch events using our callbacks and give a local context */ opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index 758617bdd48..6a5b534c688 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -234,7 +234,7 @@ static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, size_t * If must suspend, take the specified action (typically "return FALSE"). */ #define INPUT_BYTE(cinfo, V, action) \ - MAKESTMT(MAKE_BYTE_AVAIL(cinfo,action); \ + MAKESTMT(MAKE_BYTE_AVAIL(cinfo, action); \ bytes_in_buffer--; \ V = GETJOCTET(*next_input_byte++); ) @@ -242,7 +242,7 @@ static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, size_t * V should be declared unsigned int or perhaps INT32. */ #define INPUT_2BYTES(cinfo, V, action) \ - MAKESTMT(MAKE_BYTE_AVAIL(cinfo,action); \ + MAKESTMT(MAKE_BYTE_AVAIL(cinfo, action); \ bytes_in_buffer--; \ V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ MAKE_BYTE_AVAIL(cinfo, action); \ diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index da7b31cc2ba..18b08c9b59b 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -1197,6 +1197,9 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char delete file; } } + + if (flags & IB_alphamode_detect) + ibuf->flags |= IB_alphamode_premul; } return(ibuf); } diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index dcfebb95b87..bbe43132051 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -109,10 +109,14 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) unsigned char *pixels = NULL; unsigned char *from, *to; + unsigned short *pixels16 = NULL, *to16; + float *from_float, from_straight[4]; png_bytepp row_pointers = NULL; int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY; FILE *fp = NULL; + int is_16bit = (ibuf->ftype & PNG_16BIT) && ibuf->rect_float; + /* use the jpeg quality setting for compression */ int compression; compression = (int)(((float)(ibuf->ftype & 0xff) / 11.1111f)); @@ -150,8 +154,12 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) /* copy image data */ - pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); - if (pixels == NULL) { + if (is_16bit) + pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned short), "png 16bit pixels"); + else + pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "png 8bit pixels"); + + if (pixels == NULL && pixels16 == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name); return 0; @@ -159,32 +167,66 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) from = (unsigned char *) ibuf->rect; to = pixels; + from_float = ibuf->rect_float; + to16 = pixels16; switch (bytesperpixel) { case 4: color_type = PNG_COLOR_TYPE_RGBA; - for (i = ibuf->x * ibuf->y; i > 0; i--) { - to[0] = from[0]; - to[1] = from[1]; - to[2] = from[2]; - to[3] = from[3]; - to += 4; from += 4; + if (is_16bit) { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + premul_to_straight_v4(from_straight, from_float); + to16[0] = FTOUSHORT(from_straight[0]); + to16[1] = FTOUSHORT(from_straight[1]); + to16[2] = FTOUSHORT(from_straight[2]); + to16[3] = FTOUSHORT(from_straight[3]); + to16 += 4; from_float += 4; + } + } + else { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to[3] = from[3]; + to += 4; from += 4; + } } break; case 3: color_type = PNG_COLOR_TYPE_RGB; - for (i = ibuf->x * ibuf->y; i > 0; i--) { - to[0] = from[0]; - to[1] = from[1]; - to[2] = from[2]; - to += 3; from += 4; + if (is_16bit) { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + premul_to_straight_v4(from_straight, from_float); + to16[0] = FTOUSHORT(from_straight[0]); + to16[1] = FTOUSHORT(from_straight[1]); + to16[2] = FTOUSHORT(from_straight[2]); + to16 += 3; from_float += 4; + } + } + else { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to += 3; from += 4; + } } break; case 1: color_type = PNG_COLOR_TYPE_GRAY; - for (i = ibuf->x * ibuf->y; i > 0; i--) { - to[0] = from[0]; - to++; from += 4; + if (is_16bit) { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + premul_to_straight_v4(from_straight, from_float); + to16[0] = FTOUSHORT(from_straight[0]); + to16++; from_float += 4; + } + } + else { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to++; from += 4; + } } break; } @@ -203,7 +245,10 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) fp = BLI_fopen(name, "wb"); if (!fp) { png_destroy_write_struct(&png_ptr, &info_ptr); - MEM_freeN(pixels); + if (pixels) + MEM_freeN(pixels); + if (pixels16) + MEM_freeN(pixels16); printf("imb_savepng: Cannot open file for writing: '%s'\n", name); return 0; } @@ -227,7 +272,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) info_ptr, ibuf->x, ibuf->y, - 8, + is_16bit ? 16 : 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, @@ -268,12 +313,19 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) /* write the file header information */ png_write_info(png_ptr, info_ptr); +#ifdef __LITTLE_ENDIAN__ + png_set_swap(png_ptr); +#endif + /* allocate memory for an array of row-pointers */ row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); if (row_pointers == NULL) { printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name); png_destroy_write_struct(&png_ptr, &info_ptr); - MEM_freeN(pixels); + if (pixels) + MEM_freeN(pixels); + if (pixels16) + MEM_freeN(pixels16); if (fp) { fclose(fp); } @@ -281,9 +333,17 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) } /* set the individual row-pointers to point at the correct offsets */ - for (i = 0; i < ibuf->y; i++) { - row_pointers[ibuf->y - 1 - i] = (png_bytep) - ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); + if (is_16bit) { + for (i = 0; i < ibuf->y; i++) { + row_pointers[ibuf->y - 1 - i] = (png_bytep) + ((unsigned short *)pixels16 + (i * ibuf->x) * bytesperpixel); + } + } + else { + for (i = 0; i < ibuf->y; i++) { + row_pointers[ibuf->y - 1 - i] = (png_bytep) + ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); + } } /* write out the entire image data in one call */ @@ -293,7 +353,10 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) png_write_end(png_ptr, info_ptr); /* clean up */ - MEM_freeN(pixels); + if (pixels) + MEM_freeN(pixels); + if (pixels16) + MEM_freeN(pixels16); MEM_freeN(row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); @@ -394,6 +457,8 @@ ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[I if (ibuf) { ibuf->ftype = PNG; + if (bit_depth == 16) + ibuf->ftype |= PNG_16BIT; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { int unit_type; diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index 03ed1bb8008..d09adeb09b5 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -212,6 +212,9 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, size_t size, int flags, char color if (ibuf == NULL) return NULL; ibuf->ftype = RADHDR; + if (flags & IB_alphamode_detect) + ibuf->flags |= IB_alphamode_premul; + if (flags & IB_test) return ibuf; /* read in and decode the actual data */ diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index be20c80bdec..00bc78ee488 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -86,15 +86,32 @@ ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char co BLI_strncpy(colorspace, effective_colorspace, IM_MAX_SPACE); } + if (flags & IB_ignore_alpha) { + IMB_rectfill_alpha(ibuf, 1.0f); + } + else { + if (flags & IB_alphamode_premul) { + if (ibuf->rect) { + IMB_unpremultiply_alpha(ibuf); + } + else { + /* pass, floats are expected to be premul */ + } + } + else { + if (ibuf->rect_float) { + IMB_premultiply_alpha(ibuf); + } + else { + /* pass, bytes are expected to be straight */ + } + } + } + /* OCIO_TODO: in some cases it's faster to do threaded conversion, * but how to distinguish such cases */ colormanage_imbuf_make_linear(ibuf, effective_colorspace); - if (flags & IB_premul) { - IMB_premultiply_alpha(ibuf); - ibuf->flags |= IB_premul; - } - return ibuf; } } @@ -230,4 +247,3 @@ void imb_loadtile(ImBuf *ibuf, int tx, int ty, unsigned int *rect) close(file); } - diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index 1e701b8d615..1050d3f8715 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -33,6 +33,7 @@ #include "BLI_utildefines.h" +#include "BLI_math_color.h" #include "MEM_guardedalloc.h" #include "imbuf.h" @@ -291,6 +292,37 @@ struct ImBuf *IMB_double_y(struct ImBuf *ibuf1) return (ibuf2); } +/* pretty much specific functions which converts uchar <-> ushort but assumes + * ushort range of 255*255 which is more convenient here + */ +MINLINE void straight_uchar_to_premul_ushort(unsigned short result[4], const unsigned char color[4]) +{ + unsigned short alpha = color[3]; + + result[0] = color[0] * alpha; + result[1] = color[1] * alpha; + result[2] = color[2] * alpha; + result[3] = alpha * 255; +} + +MINLINE void premul_ushort_to_straight_uchar(unsigned char *result, const unsigned short color[4]) +{ + if (color[3] <= 255) { + result[0] = color[0] / 255; + result[1] = color[1] / 255; + result[2] = color[2] / 255; + result[3] = color[3] / 255; + } + else { + unsigned short alpha = color[3] / 255; + + result[0] = color[0] / alpha; + result[1] = color[1] / alpha; + result[2] = color[2] / alpha; + result[3] = alpha; + } +} + /* result in ibuf2, scaling should be done correctly */ void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1) { @@ -303,23 +335,33 @@ void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1) } if (do_rect) { - char *p1, *p2, *dest; + unsigned char *cp1, *cp2, *dest; - p1 = (char *) ibuf1->rect; - dest = (char *) ibuf2->rect; + cp1 = (unsigned char *) ibuf1->rect; + dest = (unsigned char *) ibuf2->rect; for (y = ibuf2->y; y > 0; y--) { - p2 = p1 + (ibuf1->x << 2); + cp2 = cp1 + (ibuf1->x << 2); for (x = ibuf2->x; x > 0; x--) { - dest[0] = (p1[0] + p2[0] + p1[4] + p2[4]) >> 2; - dest[1] = (p1[1] + p2[1] + p1[5] + p2[5]) >> 2; - dest[2] = (p1[2] + p2[2] + p1[6] + p2[6]) >> 2; - dest[3] = (p1[3] + p2[3] + p1[7] + p2[7]) >> 2; - p1 += 8; - p2 += 8; + unsigned short p1i[8], p2i[8], desti[4]; + + straight_uchar_to_premul_ushort(p1i, cp1); + straight_uchar_to_premul_ushort(p2i, cp2); + straight_uchar_to_premul_ushort(p1i + 4, cp1 + 4); + straight_uchar_to_premul_ushort(p2i + 4, cp2 + 4); + + desti[0] = ((unsigned int) p1i[0] + p2i[0] + p1i[4] + p2i[4]) >> 2; + desti[1] = ((unsigned int) p1i[1] + p2i[1] + p1i[5] + p2i[5]) >> 2; + desti[2] = ((unsigned int) p1i[2] + p2i[2] + p1i[6] + p2i[6]) >> 2; + desti[3] = ((unsigned int) p1i[3] + p2i[3] + p1i[7] + p2i[7]) >> 2; + + premul_ushort_to_straight_uchar(dest, desti); + + cp1 += 8; + cp2 += 8; dest += 4; } - p1 = p2; - if (ibuf1->x & 1) p1 += 4; + cp1 = cp2; + if (ibuf1->x & 1) cp1 += 4; } } diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 83830f260e1..2630aebef3b 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -376,7 +376,7 @@ static void imb_read_tiff_resolution(ImBuf *ibuf, TIFF *image) * This method is most flexible and can handle multiple different bit depths * and RGB channel orderings. */ -static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul) +static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image) { ImBuf *tmpibuf; int success = 0; @@ -390,6 +390,23 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul) TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp); /* number of 'channels' */ TIFFGetField(image, TIFFTAG_PLANARCONFIG, &config); + if (spp == 4) { + /* HACK: this is really tricky hack, which is only needed to force libtiff + * do not touch RGB channels when there's alpha channel present + * The thing is: libtiff will premul RGB if alpha mode is set to + * unassociated, which really conflicts with blender's assumptions + * + * Alternative would be to unpremul after load, but it'll be really + * lossy and unwanted behavior + * + * So let's keep this thing here for until proper solution is found (sergey) + */ + + unsigned short extraSampleTypes[1]; + extraSampleTypes[0] = EXTRASAMPLE_ASSOCALPHA; + TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, extraSampleTypes); + } + imb_read_tiff_resolution(ibuf, image); scanline = TIFFScanlineSize(image); @@ -471,10 +488,6 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul) if (bitspersample < 16) if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(tmpibuf); - if (premul) { - IMB_premultiply_alpha(tmpibuf); - ibuf->flags |= IB_premul; - } /* assign rect last */ if (tmpibuf->rect_float) @@ -557,6 +570,18 @@ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[ return NULL; } + /* get alpha mode from file header */ + if (flags & IB_alphamode_detect) { + if (spp == 4) { + unsigned short extra, *extraSampleTypes; + + TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extra, &extraSampleTypes); + + if (extraSampleTypes[0] == EXTRASAMPLE_ASSOCALPHA) + ibuf->flags |= IB_alphamode_premul; + } + } + /* if testing, we're done */ if (flags & IB_test) { TIFFClose(image); @@ -585,9 +610,6 @@ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[ hbuf->miplevel = level; hbuf->ftype = ibuf->ftype; ibuf->mipmap[level - 1] = hbuf; - - if (flags & IB_premul) - hbuf->flags |= IB_premul; } else hbuf = ibuf; @@ -608,7 +630,7 @@ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[ } /* read pixels */ - if (!(ibuf->flags & IB_tilecache) && !imb_read_tiff_pixels(ibuf, image, 0)) { + if (!(ibuf->flags & IB_tilecache) && !imb_read_tiff_pixels(ibuf, image)) { fprintf(stderr, "imb_loadtiff: Failed to read tiff image.\n"); TIFFClose(image); return NULL; @@ -644,9 +666,6 @@ void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, size_t size, int tx, int if (TIFFReadRGBATile(image, tx * ibuf->tilex, (ibuf->ytiles - 1 - ty) * ibuf->tiley, rect) == 1) { if (ibuf->tiley > ibuf->y) memmove(rect, rect + ibuf->tilex * (ibuf->tiley - ibuf->y), sizeof(int) * ibuf->tilex * ibuf->y); - - if (ibuf->flags & IB_premul) - IMB_premultiply_rect(rect, 32, ibuf->tilex, ibuf->tiley); } else printf("imb_loadtiff: failed to read tiff tile at mipmap level %d\n", ibuf->miplevel); @@ -689,8 +708,6 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags) float *fromf = NULL; float xres, yres; int x, y, from_i, to_i, i; - int extraSampleTypes[1] = { EXTRASAMPLE_ASSOCALPHA }; - /* check for a valid number of bytes per pixel. Like the PNG writer, * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding @@ -763,6 +780,13 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags) TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); if (samplesperpixel == 4) { + unsigned short extraSampleTypes[1]; + + if (bitspersample == 16) + extraSampleTypes[0] = EXTRASAMPLE_ASSOCALPHA; + else + extraSampleTypes[0] = EXTRASAMPLE_UNASSALPHA; + /* RGBA images */ TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, extraSampleTypes); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 7b2773a8205..68896992287 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -42,6 +42,7 @@ extern "C" { struct Library; struct FileData; struct ID; +struct PackedFile; typedef struct IDPropertyData { void *pointer; @@ -136,6 +137,8 @@ typedef struct Library { * setting 'name' directly and it will be kept in * sync - campbell */ struct Library *parent; /* set for indirectly linked libs, used in the outliner and while reading */ + + struct PackedFile *packedfile; } Library; enum eIconSizes { diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index cc26ee479d7..e3571c767bd 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -156,10 +156,7 @@ typedef enum BrushSculptTool { SCULPT_TOOL_THUMB = 12, SCULPT_TOOL_SNAKE_HOOK = 13, SCULPT_TOOL_ROTATE = 14, - - /* slot 15 is free for use */ - /* SCULPT_TOOL_ = 15, */ - + SCULPT_TOOL_SIMPLIFY = 15, SCULPT_TOOL_CREASE = 16, SCULPT_TOOL_BLOB = 17, SCULPT_TOOL_CLAY_STRIPS = 18, diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index fe3550327f7..0f47ee224ae 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -111,6 +111,9 @@ typedef struct Image { /* color management */ ColorManagedColorspaceSettings colorspace_settings; + char alpha_mode; + + char pad[7]; } Image; @@ -119,15 +122,16 @@ typedef struct Image { /* Image.flag */ #define IMA_FIELDS 1 #define IMA_STD_FIELD 2 -#define IMA_DO_PREMUL 4 +#define IMA_DO_PREMUL 4 /* deprecated, should not be used */ #define IMA_REFLECT 16 #define IMA_NOCOLLECT 32 #define IMA_DEPRECATED 64 #define IMA_OLD_PREMUL 128 -#define IMA_CM_PREDIVIDE 256 +/*#define IMA_CM_PREDIVIDE 256*/ /* deprecated, should not be used */ #define IMA_USED_FOR_RENDER 512 #define IMA_USER_FRAME_IN_RANGE 1024 /* for image user, but these flags are mixed */ #define IMA_VIEW_AS_RENDER 2048 +#define IMA_IGNORE_ALPHA 4096 /* Image.tpageflag */ #define IMA_TILES 1 @@ -148,4 +152,10 @@ typedef struct Image { /* gen_flag */ #define IMA_GEN_FLOAT 1 +/* alpha_mode */ +enum { + IMA_ALPHA_STRAIGHT = 0, + IMA_ALPHA_PREMUL = 1, +}; + #endif diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index da7ea94aeff..03b23c5137a 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -170,6 +170,7 @@ typedef struct TFace { #define ME_SUBSURF 128 #define ME_OPT_EDGES 256 #define ME_DS_EXPAND 512 +#define ME_SCULPT_DYNAMIC_TOPOLOGY 1024 /* me->drawflag, short */ #define ME_DRAWEDGES (1 << 0) diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ef9dca58862..4194395ec43 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -281,8 +281,9 @@ typedef struct ImageFormatData { /* Jpeg2000 */ char jp2_flag; + char jp2_codec; - char pad[7]; + char pad[6]; /* color management */ ColorManagedViewSettings view_settings; @@ -351,6 +352,10 @@ typedef struct ImageFormatData { #define R_IMF_JP2_FLAG_CINE_PRESET (1<<1) /* was R_JPEG2K_CINE_PRESET */ #define R_IMF_JP2_FLAG_CINE_48 (1<<2) /* was R_JPEG2K_CINE_48FPS */ +/* ImageFormatData.jp2_codec */ +#define R_IMF_JP2_CODEC_JP2 0 +#define R_IMF_JP2_CODEC_J2K 1 + /* ImageFormatData.cineon_flag */ #define R_IMF_CINEON_FLAG_LOG (1<<0) /* was R_CINEON_LOG */ @@ -704,6 +709,7 @@ typedef struct GameData { #define GAME_SHOW_MOUSE (1 << 14) #define GAME_GLSL_NO_COLOR_MANAGEMENT (1 << 15) #define GAME_SHOW_OBSTACLE_SIMULATION (1 << 16) +#define GAME_NO_MATERIAL_CACHING (1 << 17) /* Note: GameData.flag is now an int (max 32 flags). A short could only take 16 flags */ /* GameData.playerflag */ @@ -840,6 +846,12 @@ typedef struct Sculpt { float special_rotation; + /* Maximum edge length for dynamic topology sculpting (in pixels) */ + int detail_size; + + /* Direction used for SCULPT_OT_symmetrize operator */ + int symmetrize_direction; + int pad; } Sculpt; @@ -1296,11 +1308,11 @@ typedef struct Scene { /* alphamode */ #define R_ADDSKY 0 #define R_ALPHAPREMUL 1 -#define R_ALPHAKEY 2 +/*#define R_ALPHAKEY 2*/ /* deprecated, shouldn't be used */ /* color_mgt_flag */ #define R_COLOR_MANAGEMENT (1 << 0) /* deprecated, should only be used in versioning code only */ -#define R_COLOR_MANAGEMENT_PREDIVIDE (1 << 1) +/*#define R_COLOR_MANAGEMENT_PREDIVIDE (1 << 1)*/ /* deprecated, shouldn't be used */ /* subimtype, flag options for imtype */ #define R_OPENEXR_HALF 1 /*deprecated*/ @@ -1323,6 +1335,7 @@ typedef struct Scene { #define R_BAKE_NORMALIZE 8 #define R_BAKE_MULTIRES 16 #define R_BAKE_LORES_MESH 32 +#define R_BAKE_VCOL 64 /* bake_normal_space */ #define R_BAKE_SPACE_CAMERA 0 @@ -1495,6 +1508,14 @@ typedef enum SculptFlags { SCULPT_USE_OPENMP = (1<<7), SCULPT_ONLY_DEFORM = (1<<8), SCULPT_SHOW_DIFFUSE = (1<<9), + + /* If set, the mesh will be drawn with smooth-shading in + * dynamic-topology mode */ + SCULPT_DYNTOPO_SMOOTH_SHADING = (1<<10), + + /* If set, dynamic-topology brushes will collapse short edges in + * addition to subdividing long ones */ + SCULPT_DYNTOPO_COLLAPSE = (1<<11) } SculptFlags; /* ImagePaintSettings.flag */ diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index de6ddb4b896..d6100dcdbce 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -110,12 +110,26 @@ typedef struct Panel { /* the part from uiBlock that needs saved in file */ int sortorder; /* panels are aligned according to increasing sortorder */ struct Panel *paneltab; /* this panel is tabbed in *paneltab */ void *activedata; /* runtime for panel manipulation */ - - int list_scroll, list_size; - int list_last_len, list_grip_size; - char list_search[64]; } Panel; +typedef struct uiList { /* some list UI data need to be saved in file */ + struct uiList *next, *prev; + + struct uiListType *type; /* runtime */ + void *padp; + + char list_id[64]; /* defined as UI_MAX_NAME_STR */ + + int layout_type; /* How items are layedout in the list */ + int padi; + + int list_scroll; + int list_size; + int list_last_len; + int list_grip_size; +/* char list_search[64]; */ +} uiList; + typedef struct ScrArea { struct ScrArea *next, *prev; @@ -167,6 +181,7 @@ typedef struct ARegion { ListBase uiblocks; /* uiBlock */ ListBase panels; /* Panel */ + ListBase ui_lists; /* uiList */ ListBase handlers; /* wmEventHandler */ struct wmTimer *regiontimer; /* blend in/out */ @@ -216,6 +231,13 @@ typedef struct ARegion { #define PNL_DEFAULT_CLOSED 1 #define PNL_NO_HEADER 2 +/* uilist layout_type */ +enum { + UILST_LAYOUT_DEFAULT = 0, + UILST_LAYOUT_COMPACT = 1, + UILST_LAYOUT_GRID = 2, +}; + /* regiontype, first two are the default set */ /* Do NOT change order, append on end. Types are hardcoded needed */ enum { diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index f106c8f918a..0aa466f7245 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -172,7 +172,10 @@ typedef struct Sequence { float blend_opacity; /* is sfra needed anymore? - it looks like its only used in one place */ - int sfra, pad; /* starting frame according to the timeline of the scene. */ + int sfra; /* starting frame according to the timeline of the scene. */ + + char alpha_mode; + char pad[3]; /* modifiers */ ListBase modifiers; @@ -315,7 +318,7 @@ typedef struct SequencerScopes { #define SEQ_OVERLAP (1 << 3) #define SEQ_FILTERY (1 << 4) #define SEQ_MUTE (1 << 5) -#define SEQ_MAKE_PREMUL (1 << 6) +#define SEQ_MAKE_PREMUL (1 << 6) /* deprecated, used for compatibility code only */ #define SEQ_REVERSE_FRAMES (1 << 7) #define SEQ_IPO_FRAME_LOCKED (1 << 8) #define SEQ_EFFECT_NOT_LOADED (1 << 9) @@ -366,6 +369,12 @@ typedef struct SequencerScopes { #define SEQ_PROXY_TC_RECORD_RUN_NO_GAPS 8 #define SEQ_PROXY_TC_ALL 15 +/* seq->alpha_mode */ +enum { + SEQ_ALPHA_STRAIGHT = 0, + SEQ_ALPHA_PREMUL = 1 +}; + /* seq->type WATCH IT: SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!!! */ enum { SEQ_TYPE_IMAGE = 0, diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h index 6ce883905d4..3194adba3a0 100644 --- a/source/blender/makesdna/DNA_text_types.h +++ b/source/blender/makesdna/DNA_text_types.h @@ -75,12 +75,4 @@ typedef struct Text { #define TXT_FOLLOW 0x0200 /* always follow cursor (console) */ #define TXT_TABSTOSPACES 0x0400 /* use space instead of tabs */ -/* format continuation flags */ -#define TXT_NOCONT 0x00 /* no continuation */ -#define TXT_SNGQUOTSTR 0x01 /* single quotes */ -#define TXT_DBLQUOTSTR 0x02 /* double quotes */ -#define TXT_TRISTR 0x04 /* triplets of quotes: """ or ''' */ -#define TXT_SNGTRISTR 0x05 /*(TXT_TRISTR | TXT_SNGQUOTSTR)*/ -#define TXT_DBLTRISTR 0x06 /*(TXT_TRISTR | TXT_DBLQUOTSTR)*/ - #endif diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index dd63e6aad59..ea4f281efd6 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -340,7 +340,7 @@ typedef struct ColorMapping { /* imaflag */ #define TEX_INTERPOL 1 -#define TEX_USEALPHA 2 +#define TEX_USEALPHA 2 /* deprecated, used for versioning only */ #define TEX_MIPMAP 4 #define TEX_IMAROT 16 #define TEX_CALCALPHA 32 diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index ce4e0c1591d..e7f27834c85 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -249,11 +249,14 @@ typedef struct ThemeSpace { char vertex_size, outline_width, facedot_size; char noodle_curving; - char syntaxl[4], syntaxn[4], syntaxb[4]; /* syntax for textwindow and nodes */ + /* syntax for textwindow and nodes */ + char syntaxl[4], syntaxs[4]; + char syntaxb[4], syntaxn[4]; char syntaxv[4], syntaxc[4]; + char syntaxd[4], syntaxr[4]; char movie[4], movieclip[4], mask[4], image[4], scene[4], audio[4]; /* for sequence editor */ - char effect[4], hpad0[4], transition[4], meta[4]; + char effect[4], transition[4], meta[4]; char editmesh_active[4]; char handle_vertex[4]; @@ -346,6 +349,7 @@ typedef struct bTheme { typedef struct bAddon { struct bAddon *next, *prev; char module[64]; + IDProperty *prop; /* User-Defined Properties on this Addon (for storing preferences) */ } bAddon; typedef struct SolidLight { diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h index 084496871bf..a7921be44d5 100644 --- a/source/blender/makesdna/DNA_view2d_types.h +++ b/source/blender/makesdna/DNA_view2d_types.h @@ -123,9 +123,9 @@ typedef struct View2D { /* horizontal scrollbar */ #define V2D_SCROLL_TOP (1<<2) #define V2D_SCROLL_BOTTOM (1<<3) - /* special hack for outliner hscroll - prevent hanging older versions of Blender */ -#define V2D_SCROLL_BOTTOM_O (1<<4) -#define V2D_SCROLL_HORIZONTAL (V2D_SCROLL_TOP|V2D_SCROLL_BOTTOM|V2D_SCROLL_BOTTOM_O) + +/* UNUSED (1<<4) */ +#define V2D_SCROLL_HORIZONTAL (V2D_SCROLL_TOP|V2D_SCROLL_BOTTOM) /* scale markings - vertical */ #define V2D_SCROLL_SCALE_VERTICAL (1<<5) /* scale markings - horizontal */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index ce7cb32c6e6..8956e9d9005 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -54,6 +54,7 @@ extern StructRNA RNA_ActionPoseMarkers; extern StructRNA RNA_Actuator; extern StructRNA RNA_ActuatorSensor; extern StructRNA RNA_Addon; +extern StructRNA RNA_AddonPreferences; extern StructRNA RNA_AdjustmentSequence; extern StructRNA RNA_AlwaysSensor; extern StructRNA RNA_AndController; @@ -104,7 +105,8 @@ extern StructRNA RNA_CollectionProperty; extern StructRNA RNA_CollisionModifier; extern StructRNA RNA_CollisionSensor; extern StructRNA RNA_CollisionSettings; -extern StructRNA RNA_ColorManagedColorspaceSettings; +extern StructRNA RNA_ColorManagedInputColorspaceSettings; +extern StructRNA RNA_ColorManagedSequencerColorspaceSettings; extern StructRNA RNA_ColorManagedDisplaySettings; extern StructRNA RNA_ColorManagedViewSettings; extern StructRNA RNA_ColorRamp; @@ -625,7 +627,7 @@ extern StructRNA RNA_TrackToConstraint; extern StructRNA RNA_TransformConstraint; extern StructRNA RNA_TransformSequence; extern StructRNA RNA_UILayout; -extern StructRNA RNA_UIListItem; +extern StructRNA RNA_UIList; extern StructRNA RNA_UVWarpModifier; extern StructRNA RNA_UVProjectModifier; extern StructRNA RNA_UVProjector; diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 75bb3475fed..a8df3b9dfdd 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -70,6 +70,7 @@ extern EnumPropertyItem keyframe_handle_type_items[]; extern EnumPropertyItem keyblock_type_items[]; extern EnumPropertyItem keyingset_path_grouping_items[]; +extern EnumPropertyItem keying_flag_items[]; extern EnumPropertyItem keyframe_paste_offset_items[]; extern EnumPropertyItem keyframe_paste_merge_items[]; @@ -89,6 +90,8 @@ extern EnumPropertyItem brush_sculpt_tool_items[]; extern EnumPropertyItem brush_vertex_tool_items[]; extern EnumPropertyItem brush_image_tool_items[]; +extern EnumPropertyItem symmetrize_direction_items[]; + extern EnumPropertyItem texture_type_items[]; extern EnumPropertyItem lamp_type_items[]; @@ -132,6 +135,9 @@ extern EnumPropertyItem prop_dynamicpaint_type_items[]; extern EnumPropertyItem clip_editor_mode_items[]; +extern EnumPropertyItem icon_items[]; +extern EnumPropertyItem uilist_layout_type_items[]; + #ifdef WITH_FREESTYLE extern EnumPropertyItem linestyle_color_modifier_type_items[]; extern EnumPropertyItem linestyle_alpha_modifier_type_items[]; diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 1b1e4f19cbb..a9cb6cdf77e 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -415,10 +415,10 @@ static const char *rna_type_type_name(PropertyRNA *prop) return "float"; case PROP_STRING: if (prop->flag & PROP_THICK_WRAP) { - return "char*"; + return "char *"; } else { - return "const char*"; + return "const char *"; } default: return NULL; @@ -870,16 +870,16 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr if (prop->flag & PROP_ID_REFCOUNT) { fprintf(f, "\n if (data->%s)\n", dp->dnaname); - fprintf(f, " id_us_min((ID*)data->%s);\n", dp->dnaname); + fprintf(f, " id_us_min((ID *)data->%s);\n", dp->dnaname); fprintf(f, " if (value.data)\n"); - fprintf(f, " id_us_plus((ID*)value.data);\n\n"); + fprintf(f, " id_us_plus((ID *)value.data);\n\n"); } else { PointerPropertyRNA *pprop = (PointerPropertyRNA *)dp->prop; StructRNA *type = rna_find_struct((const char *)pprop->type); if (type && (type->flag & STRUCT_ID)) { fprintf(f, " if (value.data)\n"); - fprintf(f, " id_lib_extern((ID*)value.data);\n\n"); + fprintf(f, " id_lib_extern((ID *)value.data);\n\n"); } } @@ -1084,7 +1084,7 @@ static char *rna_def_property_begin_func(FILE *f, StructRNA *srna, PropertyRNA * fprintf(f, "\n memset(iter, 0, sizeof(*iter));\n"); fprintf(f, " iter->parent= *ptr;\n"); - fprintf(f, " iter->prop= (PropertyRNA*)&rna_%s_%s;\n", srna->identifier, prop->identifier); + fprintf(f, " iter->prop= (PropertyRNA *)&rna_%s_%s;\n", srna->identifier, prop->identifier); if (dp->dnalengthname || dp->dnalengthfixed) { if (manualfunc) { @@ -1768,7 +1768,7 @@ static void rna_def_property_funcs_header_cpp(FILE *f, StructRNA *srna, Property const char *collection_funcs = "DefaultCollectionFunctions"; if (!(dp->prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)) && cprop->property.srna) - collection_funcs = (char*)cprop->property.srna; + collection_funcs = (char *)cprop->property.srna; if (cprop->item_type) fprintf(f, "\tCOLLECTION_PROPERTY(%s, %s, %s, %s, %s, %s, %s)", collection_funcs, (const char *)cprop->item_type, srna->identifier, @@ -2906,9 +2906,9 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr rna_property_structname(prop->type), srna->identifier, strnest, prop->identifier); - if (prop->next) fprintf(f, "\t{(PropertyRNA*)&rna_%s%s_%s, ", srna->identifier, strnest, prop->next->identifier); + if (prop->next) fprintf(f, "\t{(PropertyRNA *)&rna_%s%s_%s, ", srna->identifier, strnest, prop->next->identifier); else fprintf(f, "\t{NULL, "); - if (prop->prev) fprintf(f, "(PropertyRNA*)&rna_%s%s_%s,\n", srna->identifier, strnest, prop->prev->identifier); + if (prop->prev) fprintf(f, "(PropertyRNA *)&rna_%s%s_%s,\n", srna->identifier, strnest, prop->prev->identifier); else fprintf(f, "NULL,\n"); fprintf(f, "\t%d, ", prop->magic); rna_print_c_string(f, prop->identifier); @@ -3080,12 +3080,12 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE fprintf(f, "%s%s rna_%s_%s_func = {\n", "", "FunctionRNA", srna->identifier, func->identifier); if (func->cont.next) - fprintf(f, "\t{(FunctionRNA*)&rna_%s_%s_func, ", srna->identifier, + fprintf(f, "\t{(FunctionRNA *)&rna_%s_%s_func, ", srna->identifier, ((FunctionRNA *)func->cont.next)->identifier); else fprintf(f, "\t{NULL, "); if (func->cont.prev) - fprintf(f, "(FunctionRNA*)&rna_%s_%s_func,\n", srna->identifier, + fprintf(f, "(FunctionRNA *)&rna_%s_%s_func,\n", srna->identifier, ((FunctionRNA *)func->cont.prev)->identifier); else fprintf(f, "NULL,\n"); @@ -3093,11 +3093,11 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE fprintf(f, "\tNULL,\n"); parm = func->cont.properties.first; - if (parm) fprintf(f, "\t{(PropertyRNA*)&rna_%s_%s_%s, ", srna->identifier, func->identifier, parm->identifier); + if (parm) fprintf(f, "\t{(PropertyRNA *)&rna_%s_%s_%s, ", srna->identifier, func->identifier, parm->identifier); else fprintf(f, "\t{NULL, "); parm = func->cont.properties.last; - if (parm) fprintf(f, "(PropertyRNA*)&rna_%s_%s_%s}},\n", srna->identifier, func->identifier, parm->identifier); + if (parm) fprintf(f, "(PropertyRNA *)&rna_%s_%s_%s}},\n", srna->identifier, func->identifier, parm->identifier); else fprintf(f, "NULL}},\n"); fprintf(f, "\t"); @@ -3110,7 +3110,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE else fprintf(f, "\tNULL,\n"); if (func->c_ret) - fprintf(f, "\t(PropertyRNA*)&rna_%s_%s_%s\n", srna->identifier, func->identifier, func->c_ret->identifier); + fprintf(f, "\t(PropertyRNA *)&rna_%s_%s_%s\n", srna->identifier, func->identifier, func->c_ret->identifier); else fprintf(f, "\tNULL\n"); @@ -3128,11 +3128,11 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE fprintf(f, "\tNULL,\n"); prop = srna->cont.properties.first; - if (prop) fprintf(f, "\t{(PropertyRNA*)&rna_%s_%s, ", srna->identifier, prop->identifier); + if (prop) fprintf(f, "\t{(PropertyRNA *)&rna_%s_%s, ", srna->identifier, prop->identifier); else fprintf(f, "\t{NULL, "); prop = srna->cont.properties.last; - if (prop) fprintf(f, "(PropertyRNA*)&rna_%s_%s}},\n", srna->identifier, prop->identifier); + if (prop) fprintf(f, "(PropertyRNA *)&rna_%s_%s}},\n", srna->identifier, prop->identifier); else fprintf(f, "NULL}},\n"); fprintf(f, "\t"); rna_print_c_string(f, srna->identifier); @@ -3151,7 +3151,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE while (base->base && base->base->nameproperty == prop) base = base->base; - fprintf(f, "\t(PropertyRNA*)&rna_%s_%s, ", base->identifier, prop->identifier); + fprintf(f, "\t(PropertyRNA *)&rna_%s_%s, ", base->identifier, prop->identifier); } else fprintf(f, "\tNULL, "); @@ -3159,7 +3159,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE base = srna; while (base->base && base->base->iteratorproperty == prop) base = base->base; - fprintf(f, "(PropertyRNA*)&rna_%s_rna_properties,\n", base->identifier); + fprintf(f, "(PropertyRNA *)&rna_%s_rna_properties,\n", base->identifier); if (srna->base) fprintf(f, "\t&RNA_%s,\n", srna->base->identifier); else fprintf(f, "\tNULL,\n"); @@ -3181,11 +3181,11 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE } func = srna->functions.first; - if (func) fprintf(f, "\t{(FunctionRNA*)&rna_%s_%s_func, ", srna->identifier, func->identifier); + if (func) fprintf(f, "\t{(FunctionRNA *)&rna_%s_%s_func, ", srna->identifier, func->identifier); else fprintf(f, "\t{NULL, "); func = srna->functions.last; - if (func) fprintf(f, "(FunctionRNA*)&rna_%s_%s_func}\n", srna->identifier, func->identifier); + if (func) fprintf(f, "(FunctionRNA *)&rna_%s_%s_func}\n", srna->identifier, func->identifier); else fprintf(f, "NULL}\n"); fprintf(f, "};\n"); @@ -3578,7 +3578,7 @@ static const char *cpp_classes = "" " int length;\n" "\n" " DynamicArray() : data(NULL), length(0) {}\n" -" DynamicArray(int new_length) : data(NULL), length(new_length) { data = (float*)malloc(sizeof(T) * new_length); }\n" +" DynamicArray(int new_length) : data(NULL), length(new_length) { data = (float *)malloc(sizeof(T) * new_length); }\n" " DynamicArray(const DynamicArray<T>& other) { copy_from(other); }\n" " const DynamicArray<T>& operator=(const DynamicArray<T>& other) { copy_from(other); return *this; }\n" "\n" @@ -3589,7 +3589,7 @@ static const char *cpp_classes = "" "protected:\n" " void copy_from(const DynamicArray<T>& other) {\n" " if (data) free(data);\n" -" data = (float*)malloc(sizeof(T) * other.length);\n" +" data = (float *)malloc(sizeof(T) * other.length);\n" " memcpy(data, other.data, sizeof(T) * other.length);\n" " length = other.length;\n" " }\n" @@ -3620,7 +3620,7 @@ static const char *cpp_classes = "" "{ return iter.valid != other.iter.valid; }\n" "\n" " void begin(const Pointer &ptr)\n" -" { if (init) Tend(&iter); Tbegin(&iter, (PointerRNA*)&ptr.ptr); t = T(iter.ptr); init = true; }\n" +" { if (init) Tend(&iter); Tbegin(&iter, (PointerRNA *)&ptr.ptr); t = T(iter.ptr); init = true; }\n" "\n" "private:\n" " const CollectionIterator<T, Tbegin, Tnext, Tend>& operator=" @@ -3754,13 +3754,13 @@ static void rna_generate_header_cpp(BlenderRNA *UNUSED(brna), FILE *f) if (first_collection_func_struct == NULL) first_collection_func_struct = ds->srna->identifier; - if (!rna_is_collection_functions_struct(collection_func_structs, (char*)prop->srna)) { + if (!rna_is_collection_functions_struct(collection_func_structs, (char *)prop->srna)) { if (all_collection_func_structs >= max_collection_func_structs) { printf("Array size to store all collection structures names is too small\n"); exit(1); } - collection_func_structs[all_collection_func_structs++] = (char*)prop->srna; + collection_func_structs[all_collection_func_structs++] = (char *)prop->srna; } } } diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index caa53a23d77..0048e1c60c2 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -4204,6 +4204,8 @@ char *RNA_path_full_struct_py(struct PointerRNA *ptr) ret = BLI_sprintfN("%s.%s", id_path, data_path); + MEM_freeN(data_path); + return ret; } @@ -4235,6 +4237,10 @@ char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) ret = BLI_sprintfN("%s.%s[%d]", id_path, data_path, index); } + MEM_freeN(id_path); + if (data_path) { + MEM_freeN(data_path); + } return ret; } @@ -4264,6 +4270,10 @@ char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) data_path, index); } + if (data_path) { + MEM_freeN(data_path); + } + return ret; } diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 7229dddf6d6..402d05a20b6 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -52,6 +52,20 @@ EnumPropertyItem keyingset_path_grouping_items[] = { {0, NULL, 0, NULL, NULL} }; +/* It would be cool to get rid of this 'INSERTKEY_' prefix in 'py strings' values, but it would break existing + * exported keyingset... :/ + */ +EnumPropertyItem keying_flag_items[] = { + {INSERTKEY_NEEDED, "INSERTKEY_NEEDED", 0, "Only Needed", + "Only insert keyframes where they're needed in the relevant F-Curves"}, + {INSERTKEY_MATRIX, "INSERTKEY_VISUAL", 0, "Visual Keying", + "Insert keyframes based on 'visual transforms'"}, + {INSERTKEY_XYZ2RGB, "INSERTKEY_XYZ_TO_RGB", 0, "XYZ=RGB Colors", + "Color for newly added transformation F-Curves (Location, Rotation, Scale) " + "and also Color is based on the transform axis"}, + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME #include "BLI_math_base.h" @@ -518,17 +532,6 @@ static void rna_def_common_keying_flags(StructRNA *srna, short UNUSED(reg)) { PropertyRNA *prop; - static EnumPropertyItem keying_flag_items[] = { - {INSERTKEY_NEEDED, "INSERTKEY_NEEDED", 0, "Only Needed", - "Only insert keyframes where they're needed in the relevant F-Curves"}, - {INSERTKEY_MATRIX, "INSERTKEY_VISUAL", 0, "Visual Keying", - "Insert keyframes based on 'visual transforms'"}, - {INSERTKEY_XYZ2RGB, "INSERTKEY_XYZ_TO_RGB", 0, "XYZ=RGB Colors", - "Color for newly added transformation F-Curves (Location, Rotation, Scale) " - "and also Color is based on the transform axis"}, - {0, NULL, 0, NULL, NULL} - }; - prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "keyingflag"); RNA_def_property_enum_items(prop, keying_flag_items); diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 7bdebd620ee..3d5106b0cef 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -65,6 +65,7 @@ EnumPropertyItem brush_sculpt_tool_items[] = { {SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""}, {SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""}, {SCULPT_TOOL_SCRAPE, "SCRAPE", ICON_BRUSH_SCRAPE, "Scrape", ""}, + {SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_SUBTRACT /* icon TODO */, "Simplify", ""}, {SCULPT_TOOL_SMOOTH, "SMOOTH", ICON_BRUSH_SMOOTH, "Smooth", ""}, {SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""}, {SCULPT_TOOL_THUMB, "THUMB", ICON_BRUSH_THUMB, "Thumb", ""}, diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index b72bba0422a..0b1e1c215c4 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -112,8 +112,8 @@ void RNA_def_camera(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem prop_lens_unit_items[] = { - {0, "MILLIMETERS", 0, "Millimeters", ""}, - {CAM_ANGLETOGGLE, "DEGREES", 0, "Degrees", ""}, + {0, "MILLIMETERS", 0, "Millimeters", "Specify the lens in millimeters"}, + {CAM_ANGLETOGGLE, "FOV", 0, "Field of View", "Specify the lens as the field of view's angle"}, {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem sensor_fit_items[] = { @@ -154,23 +154,23 @@ void RNA_def_camera(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); prop = RNA_def_property(srna, "angle_x", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_range(prop, M_PI * (0.367 / 180.0), M_PI * (172.847 / 180.0)); + RNA_def_property_range(prop, DEG2RAD(0.367), DEG2RAD(172.847)); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Horizontal FOV", "Camera lens horizontal field of view in degrees"); + RNA_def_property_ui_text(prop, "Horizontal FOV", "Camera lens horizontal field of view"); RNA_def_property_float_funcs(prop, "rna_Camera_angle_x_get", "rna_Camera_angle_x_set", NULL); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update"); prop = RNA_def_property(srna, "angle_y", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_range(prop, M_PI * (0.367 / 180.0), M_PI * (172.847 / 180.0)); + RNA_def_property_range(prop, DEG2RAD(0.367), DEG2RAD(172.847)); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Vertical FOV", "Camera lens vertical field of view in degrees"); + RNA_def_property_ui_text(prop, "Vertical FOV", "Camera lens vertical field of view"); RNA_def_property_float_funcs(prop, "rna_Camera_angle_y_get", "rna_Camera_angle_y_set", NULL); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update"); prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_range(prop, M_PI * (0.367 / 180.0), M_PI * (172.847 / 180.0)); + RNA_def_property_range(prop, DEG2RAD(0.367), DEG2RAD(172.847)); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Field of View", "Camera lens field of view in degrees"); + RNA_def_property_ui_text(prop, "Field of View", "Camera lens field of view"); RNA_def_property_float_funcs(prop, "rna_Camera_angle_get", "rna_Camera_angle_set", NULL); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update"); diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 851ae69ed3f..36d5a575ab4 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -1011,15 +1011,26 @@ static void rna_def_colormanage(BlenderRNA *brna) RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagement_update"); /* ** Colorspace ** */ - srna = RNA_def_struct(brna, "ColorManagedColorspaceSettings", NULL); - RNA_def_struct_ui_text(srna, "ColorManagedColorspaceSettings", "Input color space settings"); + srna = RNA_def_struct(brna, "ColorManagedInputColorspaceSettings", NULL); + RNA_def_struct_ui_text(srna, "ColorManagedInputColorspaceSettings", "Input color space settings"); prop = RNA_def_property(srna, "name", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, color_space_items); RNA_def_property_enum_funcs(prop, "rna_ColorManagedColorspaceSettings_colorspace_get", "rna_ColorManagedColorspaceSettings_colorspace_set", "rna_ColorManagedColorspaceSettings_colorspace_itemf"); - RNA_def_property_ui_text(prop, "Color Space", "Input color space name"); + RNA_def_property_ui_text(prop, "Input Color Space", "Color space of the image or movie on disk"); + RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagedColorspaceSettings_reload_update"); + + srna = RNA_def_struct(brna, "ColorManagedSequencerColorspaceSettings", NULL); + RNA_def_struct_ui_text(srna, "ColorManagedSequencerColorspaceSettings", "Input color space settings"); + + prop = RNA_def_property(srna, "name", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, color_space_items); + RNA_def_property_enum_funcs(prop, "rna_ColorManagedColorspaceSettings_colorspace_get", + "rna_ColorManagedColorspaceSettings_colorspace_set", + "rna_ColorManagedColorspaceSettings_colorspace_itemf"); + RNA_def_property_ui_text(prop, "Color Space", "Color space that the sequencer operates in"); RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagedColorspaceSettings_reload_update"); } diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 30a9bfd81f6..0c8fb3d6a36 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -214,7 +214,7 @@ static void rna_Constraint_name_set(PointerRNA *ptr, const char *value) /* if we have the list, check for unique name, otherwise give up */ if (list) - unique_constraint_name(con, list); + BKE_unique_constraint_name(con, list); } /* fix all the animation data which may link to this */ @@ -293,7 +293,7 @@ static EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSED(C), PropertyRNA *UNUSED(prop), int *UNUSED(free)) { bConstraint *con = (bConstraint *)ptr->data; - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1392,19 +1392,19 @@ static void rna_def_constraint_rigid_body_joint(BlenderRNA *brna) prop = RNA_def_property(srna, "axis_x", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "axX"); RNA_def_property_range(prop, -M_PI * 2, M_PI * 2); - RNA_def_property_ui_text(prop, "Axis X", "Rotate pivot on X axis in degrees"); + RNA_def_property_ui_text(prop, "Axis X", "Rotate pivot on X axis"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); prop = RNA_def_property(srna, "axis_y", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "axY"); RNA_def_property_range(prop, -M_PI * 2, M_PI * 2); - RNA_def_property_ui_text(prop, "Axis Y", "Rotate pivot on Y axis in degrees"); + RNA_def_property_ui_text(prop, "Axis Y", "Rotate pivot on Y axis"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); prop = RNA_def_property(srna, "axis_z", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "axZ"); RNA_def_property_range(prop, -M_PI * 2, M_PI * 2); - RNA_def_property_ui_text(prop, "Axis Z", "Rotate pivot on Z axis in degrees"); + RNA_def_property_ui_text(prop, "Axis Z", "Rotate pivot on Z axis"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); prop = RNA_def_property(srna, "use_linked_collision", PROP_BOOLEAN, PROP_NONE); @@ -1528,7 +1528,7 @@ static void rna_def_constraint_clamp_to(BlenderRNA *brna) prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "tar"); RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Curve_object_poll"); - RNA_def_property_ui_text(prop, "Target", "Target Object"); + RNA_def_property_ui_text(prop, "Target", "Target Object (Curves only)"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index bb1ecea6a24..727b1e44931 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -391,7 +391,9 @@ static int rna_validate_identifier(const char *identifier, char *error, int prop { int a = 0; - /* list from http://docs.python.org/py3k/reference/lexical_analysis.html#keywords */ + /* list is from... + * ", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist if kw not in {"False", "None", "True"}]) + */ static const char *kwlist[] = { /* "False", "None", "True", */ "and", "as", "assert", "break", @@ -631,7 +633,7 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char * if (DefRNA.preprocess) { char error[512]; - if (rna_validate_identifier(identifier, error, 0) == 0) { + if (rna_validate_identifier(identifier, error, FALSE) == 0) { fprintf(stderr, "%s: struct identifier \"%s\" error - %s\n", __func__, identifier, error); DefRNA.error = 1; } @@ -909,7 +911,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier if (DefRNA.preprocess) { char error[512]; - if (rna_validate_identifier(identifier, error, 1) == 0) { + if (rna_validate_identifier(identifier, error, TRUE) == 0) { fprintf(stderr, "%s: property identifier \"%s.%s\" - %s\n", __func__, CONTAINER_RNA_ID(cont), identifier, error); DefRNA.error = 1; @@ -926,6 +928,16 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier dprop = MEM_callocN(sizeof(PropertyDefRNA), "PropertyDefRNA"); rna_addtail(&dcont->properties, dprop); } + else { +#ifdef DEBUG + char error[512]; + if (rna_validate_identifier(identifier, error, TRUE) == 0) { + fprintf(stderr, "%s: runtime property identifier \"%s.%s\" - %s\n", __func__, + CONTAINER_RNA_ID(cont), identifier, error); + DefRNA.error = 1; + } +#endif + } prop = MEM_callocN(rna_property_type_sizeof(type), "PropertyRNA"); @@ -2674,7 +2686,7 @@ static FunctionRNA *rna_def_function(StructRNA *srna, const char *identifier) if (DefRNA.preprocess) { char error[512]; - if (rna_validate_identifier(identifier, error, 0) == 0) { + if (rna_validate_identifier(identifier, error, FALSE) == 0) { fprintf(stderr, "%s: function identifier \"%s\" - %s\n", __func__, identifier, error); DefRNA.error = 1; } diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c index 4f9f2009a14..99d2f6dbbda 100644 --- a/source/blender/makesrna/intern/rna_dynamicpaint.c +++ b/source/blender/makesrna/intern/rna_dynamicpaint.c @@ -32,6 +32,8 @@ #include "rna_internal.h" +#include "BLI_math_base.h" + #include "BKE_modifier.h" #include "BKE_dynamicpaint.h" @@ -219,6 +221,14 @@ static int rna_DynamicPaint_is_cache_user_get(PointerRNA *ptr) return (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ) ? 1 : 0; } +/* is some 3D view preview available */ +static int rna_DynamicPaint_use_color_preview_get(PointerRNA *ptr) +{ + DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data; + + return dynamicPaint_surfaceHasColorPreview(surface); +} + /* does output layer exist*/ static int rna_DynamicPaint_is_output_exists(DynamicPaintSurface *surface, Object *ob, int index) { @@ -239,6 +249,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe tmp.value = MOD_DPAINT_SURFACE_T_PAINT; tmp.identifier = "PAINT"; tmp.name = "Paint"; + tmp.icon = ICON_TPAINT_HLT; RNA_enum_item_add(&item, &totitem, &tmp); /* Displace */ @@ -248,6 +259,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe tmp.value = MOD_DPAINT_SURFACE_T_DISPLACE; tmp.identifier = "DISPLACE"; tmp.name = "Displace"; + tmp.icon = ICON_MOD_DISPLACE; RNA_enum_item_add(&item, &totitem, &tmp); } @@ -256,6 +268,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe tmp.value = MOD_DPAINT_SURFACE_T_WEIGHT; tmp.identifier = "WEIGHT"; tmp.name = "Weight"; + tmp.icon = ICON_MOD_VERTEX_WEIGHT; RNA_enum_item_add(&item, &totitem, &tmp); } @@ -264,6 +277,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe tmp.value = MOD_DPAINT_SURFACE_T_WAVE; tmp.identifier = "WAVE"; tmp.name = "Waves"; + tmp.icon = ICON_MOD_WAVE; RNA_enum_item_add(&item, &totitem, &tmp); } @@ -705,6 +719,14 @@ static void rna_def_canvas_surface(BlenderRNA *brna) RNA_def_property_boolean_funcs(prop, "rna_DynamicPaint_is_cache_user_get", NULL); RNA_def_property_ui_text(prop, "Use Cache", ""); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); + + /* whether this surface has preview data for 3D view */ + RNA_define_verify_sdna(FALSE); + prop = RNA_def_property(srna, "use_color_preview", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_DynamicPaint_use_color_preview_get", NULL); + RNA_def_property_ui_text(prop, "Use Color Preview", "Whether this surface has some color preview for 3D view"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); + RNA_define_verify_sdna(TRUE); } static void rna_def_dynamic_paint_canvas_settings(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 9fedbee41ff..5d37f67fa93 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -116,15 +116,6 @@ static void rna_Image_fields_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P BKE_image_release_ibuf(ima, ibuf, lock); } -static void rna_Image_free_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) -{ - Image *ima = ptr->id.data; - BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); - WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id); - DAG_id_tag_update(&ima->id, 0); -} - - static void rna_Image_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Image *ima = ptr->id.data; @@ -139,6 +130,15 @@ static void rna_Image_generated_update(Main *UNUSED(bmain), Scene *UNUSED(scene) BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); } +static void rna_Image_colormanage_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + Image *ima = ptr->id.data; + BKE_image_signal(ima, NULL, IMA_SIGNAL_COLORMANAGE); + DAG_id_tag_update(&ima->id, 0); + WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id); + WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id); +} + static void rna_ImageUser_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) { ImageUser *iuser = ptr->data; @@ -463,6 +463,11 @@ static void rna_def_image(BlenderRNA *brna) {IMA_STD_FIELD, "ODD", 0, "Lower First", "Lower field first"}, {0, NULL, 0, NULL, NULL} }; + static const EnumPropertyItem alpha_mode_items[] = { + {IMA_ALPHA_STRAIGHT, "STRAIGHT", 0, "Straight", "Transparent RGB and alpha pixels are unmodified"}, + {IMA_ALPHA_PREMUL, "PREMUL", 0, "Premultiplied", "Transparent RGB pixels are multiplied by the alpha channel"}, + {0, NULL, 0, NULL, NULL} + }; srna = RNA_def_struct(brna, "Image", "ID"); RNA_def_struct_ui_text(srna, "Image", "Image datablock referencing an external or packed image"); @@ -512,23 +517,17 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_fields_update"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DO_PREMUL); - RNA_def_property_ui_text(prop, "Premultiply", "Convert RGB from key alpha to premultiplied alpha"); - RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_free_update"); - - prop = RNA_def_property(srna, "use_color_unpremultiply", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_CM_PREDIVIDE); - RNA_def_property_ui_text(prop, "Color Unpremultiply", - "For premultiplied alpha images, do color space conversion on colors without alpha, " - "to avoid fringing for images with light backgrounds"); - RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_free_update"); prop = RNA_def_property(srna, "view_as_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_VIEW_AS_RENDER); RNA_def_property_ui_text(prop, "View as Render", "Apply render part of display transformation when displaying this image on the screen"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); + prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IMA_IGNORE_ALPHA); + RNA_def_property_ui_text(prop, "Use Alpha", "Use the alpha channel information from the image or make image fully opaque"); + RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update"); + prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -674,9 +673,14 @@ static void rna_def_image(BlenderRNA *brna) prop = RNA_def_property(srna, "colorspace_settings", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings"); - RNA_def_property_struct_type(prop, "ColorManagedColorspaceSettings"); + RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings"); RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings"); + prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, alpha_mode_items); + RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels"); + RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update"); + RNA_api_image(srna); } diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c index af39500442d..660f6fc6ab7 100644 --- a/source/blender/makesrna/intern/rna_lamp.c +++ b/source/blender/makesrna/intern/rna_lamp.c @@ -54,7 +54,7 @@ static void rna_Lamp_buffer_size_set(PointerRNA *ptr, int value) { Lamp *la = (Lamp *)ptr->data; - CLAMP(value, 512, 10240); + CLAMP(value, 128, 10240); la->bufsize = value; la->bufsize &= (~15); /* round to multiple of 16 */ } @@ -540,7 +540,7 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) prop = RNA_def_property(srna, "shadow_buffer_size", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "bufsize"); - RNA_def_property_range(prop, 512, 10240); + RNA_def_property_range(prop, 128, 10240); RNA_def_property_ui_text(prop, "Shadow Buffer Size", "Resolution of the shadow buffer, higher values give crisper shadows " "but use more memory"); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index eb1fd61d9a7..31e27ebc982 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -154,7 +154,6 @@ static void rna_Mesh_update_vertmask(Main *bmain, Scene *scene, PointerRNA *ptr) Mesh *me = ptr->data; if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && (me->editflag & ME_EDIT_PAINT_FACE_SEL)) { me->editflag &= ~ME_EDIT_PAINT_FACE_SEL; - BKE_mesh_flush_select_from_polys(me); } rna_Mesh_update_draw(bmain, scene, ptr); } @@ -164,7 +163,6 @@ static void rna_Mesh_update_facemask(Main *bmain, Scene *scene, PointerRNA *ptr) Mesh *me = ptr->data; if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && (me->editflag & ME_EDIT_PAINT_FACE_SEL)) { me->editflag &= ~ME_EDIT_PAINT_VERT_SEL; - BKE_mesh_flush_select_from_verts(me); } rna_Mesh_update_draw(bmain, scene, ptr); } @@ -2963,7 +2961,7 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "show_extra_face_angle", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_FACEANG); RNA_def_property_ui_text(prop, "Face Angles", - "Display the angles in the selected edges in degrees, " + "Display the angles in the selected edges, " "using global values when set in the transform panel"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index e1489d821a0..7a576c88677 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -748,13 +748,13 @@ static void rna_BevelModifier_angle_limit_set(PointerRNA *ptr, float value) static void rna_UVWarpModifier_vgroup_set(PointerRNA *ptr, const char *value) { - UVWarpModifierData *umd = (UVWarpModifierData*)ptr->data; + UVWarpModifierData *umd = (UVWarpModifierData *)ptr->data; rna_object_vgroup_name_set(ptr, value, umd->vgroup_name, sizeof(umd->vgroup_name)); } static void rna_UVWarpModifier_uvlayer_set(PointerRNA *ptr, const char *value) { - UVWarpModifierData *umd = (UVWarpModifierData*)ptr->data; + UVWarpModifierData *umd = (UVWarpModifierData *)ptr->data; rna_object_uvlayer_name_set(ptr, value, umd->uvlayer_name, sizeof(umd->uvlayer_name)); } @@ -3269,7 +3269,7 @@ static void rna_def_modifier_ocean(BlenderRNA *brna) prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "size"); - RNA_def_property_ui_text(prop, "Size", ""); + RNA_def_property_ui_text(prop, "Size", "Surface scale factor (does not affect the height of the waves)"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 0); RNA_def_property_update(prop, 0, "rna_OceanModifier_topology_update"); @@ -3310,16 +3310,17 @@ static void rna_def_modifier_ocean(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Resolution", "Resolution of the generated surface"); RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); - prop = RNA_def_property(srna, "spatial_size", PROP_INT, PROP_DISTANCE); + prop = RNA_def_property(srna, "spatial_size", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "spatial_size"); RNA_def_property_ui_range(prop, 1, 512, 2, 0); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Spatial Size", "Physical size of the simulation domain (m)"); + RNA_def_property_ui_text(prop, "Spatial Size", + "Size of the simulation domain (in meters), and of the generated geometry (in BU)"); RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); prop = RNA_def_property(srna, "wind_velocity", PROP_FLOAT, PROP_VELOCITY); RNA_def_property_float_sdna(prop, NULL, "wind_velocity"); - RNA_def_property_ui_text(prop, "Wind Velocity", "Wind speed (m/s)"); + RNA_def_property_ui_text(prop, "Wind Velocity", "Wind speed"); RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); prop = RNA_def_property(srna, "damping", PROP_FLOAT, PROP_FACTOR); @@ -3332,42 +3333,43 @@ static void rna_def_modifier_ocean(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "smallest_wave"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0, FLT_MAX); - RNA_def_property_ui_text(prop, "Smallest Wave", "Shortest allowed wavelength (m)"); + RNA_def_property_ui_text(prop, "Smallest Wave", "Shortest allowed wavelength"); RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); prop = RNA_def_property(srna, "wave_alignment", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "wave_alignment"); RNA_def_property_range(prop, 0.0, 10.0); - RNA_def_property_ui_text(prop, "Wave Alignment", ""); + RNA_def_property_ui_text(prop, "Wave Alignment", "How much the waves are aligned to each other"); RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); prop = RNA_def_property(srna, "wave_direction", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "wave_direction"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Wave Direction", ""); + RNA_def_property_ui_text(prop, "Wave Direction", "Main direction of the waves when they are (partially) aligned"); RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); prop = RNA_def_property(srna, "wave_scale", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "wave_scale"); - RNA_def_property_ui_text(prop, "Wave Scale", ""); + RNA_def_property_ui_text(prop, "Wave Scale", "Scale of the displacement effect"); RNA_def_property_update(prop, 0, "rna_OceanModifier_sim_update"); - prop = RNA_def_property(srna, "depth", PROP_FLOAT, PROP_UNSIGNED); + prop = RNA_def_property(srna, "depth", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "depth"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Depth", ""); + RNA_def_property_ui_text(prop, "Depth", "Depth of the solid ground below the water surface"); RNA_def_property_ui_range(prop, 0, 250, 1, 0); RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); prop = RNA_def_property(srna, "foam_coverage", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "foam_coverage"); - RNA_def_property_ui_text(prop, "Foam Coverage", ""); + RNA_def_property_ui_text(prop, "Foam Coverage", "Amount of generated foam"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "bake_foam_fade", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "foam_fade"); - RNA_def_property_ui_text(prop, "Foam Fade", ""); - RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 0); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Foam Fade", "How much foam accumulates over time (baked ocean only)"); + RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 0); RNA_def_property_update(prop, 0, NULL); prop = RNA_def_property(srna, "foam_layer_name", PROP_STRING, PROP_NONE); @@ -3377,33 +3379,34 @@ static void rna_def_modifier_ocean(BlenderRNA *brna) prop = RNA_def_property(srna, "choppiness", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "chop_amount"); - RNA_def_property_ui_text(prop, "Choppiness", ""); + RNA_def_property_ui_text(prop, "Choppiness", + "Choppiness of the wave's crest (adds some horizontal component to the displacement)"); RNA_def_property_ui_range(prop, 0.0, 4.0, 3, 0); RNA_def_property_float_funcs(prop, NULL, "rna_OceanModifier_ocean_chop_set", NULL); RNA_def_property_update(prop, 0, "rna_OceanModifier_sim_update"); prop = RNA_def_property(srna, "time", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "time"); - RNA_def_property_ui_text(prop, "Time", ""); + RNA_def_property_ui_text(prop, "Time", "Current time of the simulation"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 0); RNA_def_property_update(prop, 0, "rna_OceanModifier_sim_update"); prop = RNA_def_property(srna, "random_seed", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "seed"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Random Seed", ""); + RNA_def_property_ui_text(prop, "Random Seed", "Seed of the random generator"); RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "bakestart"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Bake Start", ""); + RNA_def_property_ui_text(prop, "Bake Start", "Start frame of the ocean baking"); RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "bakeend"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Bake End", ""); + RNA_def_property_ui_text(prop, "Bake End", "End frame of the ocean baking"); RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); prop = RNA_def_property(srna, "is_cached", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index 99effc990a8..3b018591455 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -308,7 +308,7 @@ static void rna_def_movieclip(BlenderRNA *brna) /* color management */ prop = RNA_def_property(srna, "colorspace_settings", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings"); - RNA_def_property_struct_type(prop, "ColorManagedColorspaceSettings"); + RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings"); RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings"); } diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 3e9f5f1b88f..18dfd8aa6f9 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1101,7 +1101,7 @@ static void rna_ShaderNodeScript_mode_set(PointerRNA *ptr, int value) /* replace text datablock by filepath */ if (node->id) { - Text *text = (Text*)node->id; + Text *text = (Text *)node->id; if (value == NODE_SCRIPT_EXTERNAL && text->name) { BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath)); @@ -3217,8 +3217,8 @@ static void def_cmp_premul_key(StructRNA *srna) PropertyRNA *prop; static EnumPropertyItem type_items[] = { - {0, "KEY_TO_PREMUL", 0, "Key to Premul", ""}, - {1, "PREMUL_TO_KEY", 0, "Premul to Key", ""}, + {0, "STRAIGHT_TO_PREMUL", 0, "Straight to Premul", ""}, + {1, "PREMUL_TO_STRAIGHT", 0, "Premul to Straight", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h index de535156199..46f2306f284 100644 --- a/source/blender/makesrna/intern/rna_nodetree_types.h +++ b/source/blender/makesrna/intern/rna_nodetree_types.h @@ -84,6 +84,7 @@ DefNode( ShaderNode, SH_NODE_LIGHT_PATH, 0, "LI DefNode( ShaderNode, SH_NODE_LIGHT_FALLOFF, 0, "LIGHT_FALLOFF", LightFalloff, "Light Falloff", "" ) DefNode( ShaderNode, SH_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "" ) DefNode( ShaderNode, SH_NODE_PARTICLE_INFO, 0, "PARTICLE_INFO", ParticleInfo, "Particle Info", "" ) +DefNode( ShaderNode, SH_NODE_HAIR_INFO, 0, "HAIR_INFO", HairInfo, "Hair Info", "" ) DefNode( ShaderNode, SH_NODE_BUMP, 0, "BUMP", Bump, "Bump", "" ) DefNode( ShaderNode, SH_NODE_NORMAL_MAP, def_sh_normal_map, "NORMAL_MAP", NormalMap, "Normal Map", "" ) DefNode( ShaderNode, SH_NODE_TANGENT, def_sh_tangent, "TANGENT", Tangent, "Tangent", "" ) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index b218cc6a944..80d74c3a9fe 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -48,6 +48,7 @@ #include "BLI_utildefines.h" +#include "BKE_paint.h" #include "BKE_tessmesh.h" #include "BKE_group.h" /* needed for object_in_group() */ @@ -1123,7 +1124,7 @@ static void rna_GameObjectSettings_used_state_get(PointerRNA *ptr, int *values) static void rna_GameObjectSettings_col_group_get(PointerRNA *ptr, int *values) { - Object *ob = (Object*)ptr->data; + Object *ob = (Object *)ptr->data; int i; for (i = 0; i < OB_MAX_COL_MASKS; i++) { @@ -1133,7 +1134,7 @@ static void rna_GameObjectSettings_col_group_get(PointerRNA *ptr, int *values) static void rna_GameObjectSettings_col_group_set(PointerRNA *ptr, const int *values) { - Object *ob = (Object*)ptr->data; + Object *ob = (Object *)ptr->data; int i, tot = 0; /* ensure we always have some group selected */ @@ -1152,7 +1153,7 @@ static void rna_GameObjectSettings_col_group_set(PointerRNA *ptr, const int *val static void rna_GameObjectSettings_col_mask_get(PointerRNA *ptr, int *values) { - Object *ob = (Object*)ptr->data; + Object *ob = (Object *)ptr->data; int i; for (i = 0; i < OB_MAX_COL_MASKS; i++) { @@ -1162,7 +1163,7 @@ static void rna_GameObjectSettings_col_mask_get(PointerRNA *ptr, int *values) static void rna_GameObjectSettings_col_mask_set(PointerRNA *ptr, const int *values) { - Object *ob = (Object*)ptr->data; + Object *ob = (Object *)ptr->data; int i, tot = 0; /* ensure we always have some mask selected */ @@ -1252,20 +1253,20 @@ static PointerRNA rna_Object_collision_get(PointerRNA *ptr) static PointerRNA rna_Object_active_constraint_get(PointerRNA *ptr) { Object *ob = (Object *)ptr->id.data; - bConstraint *con = constraints_get_active(&ob->constraints); + bConstraint *con = BKE_constraints_get_active(&ob->constraints); return rna_pointer_inherit_refine(ptr, &RNA_Constraint, con); } static void rna_Object_active_constraint_set(PointerRNA *ptr, PointerRNA value) { Object *ob = (Object *)ptr->id.data; - constraints_set_active(&ob->constraints, (bConstraint *)value.data); + BKE_constraints_set_active(&ob->constraints, (bConstraint *)value.data); } static bConstraint *rna_Object_constraints_new(Object *object, int type) { WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, object); - return add_ob_constraint(object, NULL, type); + return BKE_add_ob_constraint(object, NULL, type); } static void rna_Object_constraints_remove(Object *object, ReportList *reports, PointerRNA *con_ptr) @@ -1276,7 +1277,7 @@ static void rna_Object_constraints_remove(Object *object, ReportList *reports, P return; } - remove_constraint(&object->constraints, con); + BKE_remove_constraint(&object->constraints, con); RNA_POINTER_INVALIDATE(con_ptr); ED_object_constraint_update(object); @@ -1286,7 +1287,7 @@ static void rna_Object_constraints_remove(Object *object, ReportList *reports, P static void rna_Object_constraints_clear(Object *object) { - free_constraints(&object->constraints); + BKE_free_constraints(&object->constraints); ED_object_constraint_update(object); ED_object_constraint_set_active(object, NULL); @@ -1436,6 +1437,12 @@ int rna_DupliObject_index_get(PointerRNA *ptr) return dob->persistent_id[0]; } +int rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr) +{ + SculptSession *ss = ((Object *)ptr->id.data)->sculpt; + return (ss && ss->bm); +} + #else static int rna_matrix_dimsize_4x4[] = {4, 4}; @@ -2629,6 +2636,12 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Active Shape Key Index", "Current shape key index"); RNA_def_property_update(prop, 0, "rna_Object_active_shape_update"); + /* sculpt */ + prop = RNA_def_property(srna, "use_dynamic_topology_sculpting", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_Object_use_dynamic_topology_sculpting_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Dynamic Topology Sculpting", NULL); + RNA_api_object(srna); } diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 87fc3be28a2..d7115256fe5 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -36,42 +36,79 @@ #include "RNA_define.h" -#include "DNA_object_types.h" +#include "DNA_constraint_types.h" #include "DNA_modifier_types.h" +#include "DNA_object_types.h" #include "rna_internal.h" /* own include */ +static EnumPropertyItem space_items[] = { + {CONSTRAINT_SPACE_WORLD, "WORLD", 0, "World Space", + "The most gobal space in Blender"}, + {CONSTRAINT_SPACE_POSE, "POSE", 0, "Pose Space", + "The pose space of a bone (its armature's object space)"}, + {CONSTRAINT_SPACE_PARLOCAL, "LOCAL_WITH_PARENT", 0, "Local With Parent", + "The local space of a bone's parent bone"}, + {CONSTRAINT_SPACE_LOCAL, "LOCAL", 0, "Local Space", + "The local space of an object/bone"}, + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME + #include "BLI_math.h" -#include "BKE_main.h" -#include "BKE_global.h" -#include "BKE_context.h" -#include "BKE_report.h" -#include "BKE_object.h" -#include "BKE_mesh.h" -#include "BKE_DerivedMesh.h" +#include "BKE_anim.h" #include "BKE_bvhutils.h" - +#include "BKE_cdderivedmesh.h" +#include "BKE_constraint.h" +#include "BKE_context.h" #include "BKE_customdata.h" -#include "BKE_anim.h" #include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" #include "BKE_displist.h" #include "BKE_font.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_mesh.h" #include "BKE_mball.h" #include "BKE_modifier.h" -#include "BKE_cdderivedmesh.h" +#include "BKE_object.h" +#include "BKE_report.h" +#include "DNA_curve_types.h" #include "DNA_mesh_types.h" -#include "DNA_scene_types.h" #include "DNA_meshdata_types.h" -#include "DNA_curve_types.h" -#include "DNA_modifier_types.h" -#include "DNA_constraint_types.h" +#include "DNA_scene_types.h" #include "DNA_view3d_types.h" #include "MEM_guardedalloc.h" +/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */ +static void rna_Scene_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan, + float *mat, float *mat_ret, int from, int to) +{ + copy_m4_m4((float (*)[4])mat_ret, (float (*)[4])mat); + + /* Error in case of invalid from/to values when pchan is NULL */ + if (pchan == NULL) { + if (ELEM(from, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL)) { + const char *identifier = NULL; + RNA_enum_identifier(space_items, from, &identifier); + BKE_reportf(reports, RPT_ERROR, "'from_space' '%s' is invalid when no pose bone is given!", identifier); + return; + } + if (ELEM(to, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL)) { + const char *identifier = NULL; + RNA_enum_identifier(space_items, to, &identifier); + BKE_reportf(reports, RPT_ERROR, "'to_space' '%s' is invalid when no pose bone is given!", identifier); + return; + } + } + + BKE_constraint_mat_convertspace(ob, pchan, (float (*)[4])mat_ret, from, to); +} + /* copied from Mesh_getFromObject and adapted to RNA interface */ /* settings: 0 - preview, 1 - render */ static Mesh *rna_Object_to_mesh(Object *ob, ReportList *reports, Scene *sce, int apply_modifiers, int settings) @@ -570,7 +607,7 @@ void rna_Object_dm_info(struct Object *ob, int type, char *result) } #endif /* NDEBUG */ -#else +#else /* RNA_RUNTIME */ void RNA_api_object(StructRNA *srna) { @@ -583,6 +620,8 @@ void RNA_api_object(StructRNA *srna) {0, NULL, 0, NULL, NULL} }; + static int rna_matrix_dimsize_4x4[] = {4, 4}; + #ifndef NDEBUG static EnumPropertyItem mesh_dm_info_items[] = { {0, "SOURCE", 0, "Source", "Source mesh"}, @@ -592,6 +631,25 @@ void RNA_api_object(StructRNA *srna) }; #endif + /* Matrix space conversion */ + func = RNA_def_function(srna, "convert_space", "rna_Scene_mat_convert_space"); + RNA_def_function_ui_description(func, "Convert (transform) the given matrix from one space to another"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "pose_bone", "PoseBone", "", + "Bone to use to define spaces (may be None, in which case only the two 'WORLD' and " + "'LOCAL' spaces are usable)"); + parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The matrix to transform"); + parm = RNA_def_property(func, "matrix_return", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The transformed matrix"); + RNA_def_function_output(func, parm); + parm = RNA_def_enum(func, "from_space", space_items, CONSTRAINT_SPACE_WORLD, "", + "The space in which 'matrix' is currently"); + parm = RNA_def_enum(func, "to_space", space_items, CONSTRAINT_SPACE_WORLD, "", + "The space to which you want to transform 'matrix'"); + /* mesh */ func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh"); RNA_def_function_ui_description(func, "Create a Mesh datablock with modifiers applied"); @@ -737,5 +795,4 @@ void RNA_api_object_base(StructRNA *srna) RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); } -#endif - +#endif /* RNA_RUNTIME */ diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 6d7187da7d9..0c2944b3966 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -763,7 +763,8 @@ static void rna_def_pointcache(BlenderRNA *brna) prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "startframe"); - RNA_def_property_range(prop, 1, MAXFRAME); + RNA_def_property_range(prop, -MAXFRAME, MAXFRAME); + RNA_def_property_ui_range(prop, -1000, MAXFRAME, 1, 1); RNA_def_property_ui_text(prop, "Start", "Frame on which the simulation starts"); prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_TIME); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 93f940b1aa3..be3cbfaece3 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -238,7 +238,329 @@ static void rna_ParticleHairKey_location_object_set(PointerRNA *ptr, const float } } -/* property update functions */ +static void rna_ParticleHairKey_co_object(HairKey *hairkey, Object *object, ParticleSystemModifierData *modifier, ParticleData *particle, + float n_co[3]) +{ + + DerivedMesh *hairdm = (modifier->psys->flag & PSYS_HAIR_DYNAMICS) ? modifier->psys->hair_out_dm : NULL; + if (particle) { + if (hairdm) { + MVert *mvert = CDDM_get_vert(hairdm, particle->hair_index + (hairkey - particle->hair)); + copy_v3_v3(n_co, mvert->co); + } + else { + float hairmat[4][4]; + psys_mat_hair_to_object(object, modifier->dm, modifier->psys->part->from, particle, hairmat); + copy_v3_v3(n_co, hairkey->co); + mul_m4_v3(hairmat, n_co); + } + } + else { + zero_v3(n_co); + } +} + +static void rna_Particle_uv_on_emitter(ParticleData *particle, ParticleSystemModifierData *modifier, float n_uv[2]) +{ + /*psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, nor, 0, 0, sd.orco, 0);*/ + + /* get uvco & mcol */ + int num = particle->num_dmcache; + int from = modifier->psys->part->from; + + if (num == DMCACHE_NOTFOUND) + if (particle->num < modifier->dm->getNumTessFaces(modifier->dm)) + num = particle->num; + + /* get uvco */ + if (n_uv && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { + + if (num != DMCACHE_NOTFOUND) { + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); + MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0); + mtface += num; + + psys_interpolate_uvs(mtface, mface->v4, particle->fuv, n_uv); + } + else { + n_uv[0] = 0.0f; + n_uv[1] = 0.0f; + } + } +} + +static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *object, ParticleSystemModifierData *modifier, int particle_no, int step, + float n_co[3]) +{ + ParticleSettings *part = 0; + ParticleData *pars = 0; + ParticleCacheKey *cache = 0; + int totchild = 0; + int path_nbr = 0; + int totpart; + int max_k = 0; + + if (particlesystem == NULL) + return; + + part = particlesystem->part; + pars = particlesystem->particles; + + if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem)) + return; + + if (part->ren_as == PART_DRAW_OB || part->ren_as == PART_DRAW_GR || part->ren_as == PART_DRAW_NOT) + return; + + totchild = particlesystem->totchild * part->disp / 100; + + /* can happen for disconnected/global hair */ + if (part->type == PART_HAIR && !particlesystem->childcache) + totchild = 0; + + totpart = particlesystem->totpart; + + if (particle_no >= totpart + totchild) + return; + + if (part->ren_as == PART_DRAW_PATH && particlesystem->pathcache) + path_nbr = (int)pow(2.0, part->draw_step); + + if (particle_no < totpart) { + + if (path_nbr) { + cache = particlesystem->pathcache[particle_no]; + max_k = (int)cache->steps; + } + + } + else { + + if (path_nbr) { + cache = particlesystem->childcache[particle_no - totpart]; + + if (cache->steps < 0) + max_k = 0; + else + max_k = (int)cache->steps; + } + } + + /*strands key loop data stored in cache + step->co*/ + if (path_nbr) { + if (step >= 0 && step <= path_nbr) { + if (step <= max_k) + copy_v3_v3(n_co, (cache + step)->co); + } + } + +} + +static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, ParticleSystemModifierData *modifier, ParticleData *particle, int particle_no, + float n_uv[2]) +{ + ParticleSettings *part = 0; + int totpart; + int totchild = 0; + int num; + + /* 1. check that everything is ok & updated */ + if (particlesystem == NULL) + return; + + part = particlesystem->part; + + totchild = particlesystem->totchild; + + /* can happen for disconnected/global hair */ + if (part->type == PART_HAIR && !particlesystem->childcache) + totchild = 0; + + totpart = particlesystem->totpart; + + if (particle_no >= totpart + totchild) + return; + +/* 3. start creating renderable things */ + /* setup per particle individual stuff */ + if (particle_no < totpart) { + + /* get uvco & mcol */ + num = particle->num_dmcache; + + if (num == DMCACHE_NOTFOUND) + if (particle->num < modifier->dm->getNumTessFaces(modifier->dm)) + num = particle->num; + + if (n_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (num != DMCACHE_NOTFOUND) { + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); + MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0); + mtface += num; + + psys_interpolate_uvs(mtface, mface->v4, particle->fuv, n_uv); + } + else { + n_uv[0] = 0.0f; + n_uv[1] = 0.0f; + } + } + } + else { + ChildParticle *cpa = particlesystem->child + particle_no - totpart; + + num = cpa->num; + + /* get uvco & mcol */ + if (part->childtype == PART_CHILD_FACES) { + if (n_uv && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (cpa->num != DMCACHE_NOTFOUND) { + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, cpa->num, CD_MFACE); + MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0); + mtface += cpa->num; + + psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, n_uv); + } + else { + n_uv[0] = 0.0f; + n_uv[1] = 0.0f; + } + } + } + else { + ParticleData *parent = particlesystem->particles + cpa->parent; + num = parent->num_dmcache; + + if (num == DMCACHE_NOTFOUND) + if (parent->num < modifier->dm->getNumTessFaces(modifier->dm)) + num = parent->num; + + if (n_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (num != DMCACHE_NOTFOUND) { + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); + MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0); + mtface += num; + + psys_interpolate_uvs(mtface, mface->v4, parent->fuv, n_uv); + } + else { + n_uv[0] = 0.0f; + n_uv[1] = 0.0f; + } + } + } + } +} + +static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, ParticleSystemModifierData *modifier, ParticleData *particle, int particle_no, int vcol_no, + float n_mcol[3]) +{ + ParticleSettings *part = 0; + int totpart; + int totchild = 0; + int num; + MCol mcol = {255, 255, 255, 255}; + + /* 1. check that everything is ok & updated */ + if (particlesystem == NULL) + return; + + part = particlesystem->part; + + totchild = particlesystem->totchild; + + /* can happen for disconnected/global hair */ + if (part->type == PART_HAIR && !particlesystem->childcache) + totchild = 0; + + totpart = particlesystem->totpart; + + if (particle_no >= totpart + totchild) + return; + +/* 3. start creating renderable things */ + /* setup per particle individual stuff */ + if (particle_no < totpart) { + + /* get uvco & mcol */ + num = particle->num_dmcache; + + if (num == DMCACHE_NOTFOUND) + if (particle->num < modifier->dm->getNumTessFaces(modifier->dm)) + num = particle->num; + + if (n_mcol && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (num != DMCACHE_NOTFOUND) { + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); + MCol *mc = (MCol*)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no); + mc += num * 4; + + psys_interpolate_mcol(mc, mface->v4, particle->fuv, &mcol); + n_mcol[0] = (float)mcol.b / 255.0f; + n_mcol[1] = (float)mcol.g / 255.0f; + n_mcol[2] = (float)mcol.r / 255.0f; + } + else { + n_mcol[0] = 0.0f; + n_mcol[1] = 0.0f; + n_mcol[2] = 0.0f; + } + } + } + else { + ChildParticle *cpa = particlesystem->child + particle_no - totpart; + + num = cpa->num; + + /* get uvco & mcol */ + if (part->childtype == PART_CHILD_FACES) { + if (n_mcol && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (cpa->num != DMCACHE_NOTFOUND) { + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, cpa->num, CD_MFACE); + MCol *mc = (MCol*)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, 0); + mc += cpa->num * 4; + + psys_interpolate_mcol(mc, mface->v4, cpa->fuv, &mcol); + n_mcol[0] = (float)mcol.b / 255.0f; + n_mcol[1] = (float)mcol.g / 255.0f; + n_mcol[2] = (float)mcol.r / 255.0f; + } + else { + n_mcol[0] = 0.0f; + n_mcol[1] = 0.0f; + n_mcol[2] = 0.0f; + } + } + } + else { + ParticleData *parent = particlesystem->particles + cpa->parent; + num = parent->num_dmcache; + + if (num == DMCACHE_NOTFOUND) + if (parent->num < modifier->dm->getNumTessFaces(modifier->dm)) + num = parent->num; + + if (n_mcol && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (num != DMCACHE_NOTFOUND) { + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); + MCol *mc = (MCol*)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, 0); + mc += num * 4; + + psys_interpolate_mcol(mc, mface->v4, parent->fuv, &mcol); + n_mcol[0] = (float)mcol.b / 255.0f; + n_mcol[1] = (float)mcol.g / 255.0f; + n_mcol[2] = (float)mcol.r / 255.0f; + } + else { + n_mcol[0] = 0.0f; + n_mcol[1] = 0.0f; + n_mcol[2] = 0.0f; + } + } + } + } +} + static void particle_recalc(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr, short flag) { if (ptr->type == &RNA_ParticleSystem) { @@ -905,6 +1227,7 @@ static void rna_def_particle_hair_key(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; srna = RNA_def_struct(brna, "ParticleHairKey", NULL); RNA_def_struct_sdna(srna, "HairKey"); @@ -928,6 +1251,19 @@ static void rna_def_particle_hair_key(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Location", "Location of the hair key in its internal coordinate system, " "relative to the emitting face"); + + /* Aided co func */ + func = RNA_def_function(srna, "co_object", "rna_ParticleHairKey_co_object"); + RNA_def_function_ui_description(func, "Obtain hairkey location with particle and modifier data"); + + prop = RNA_def_pointer(func, "object", "Object", "", "Object"); + prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + prop = RNA_def_pointer(func, "particle", "Particle", "", "hair particle"); + + prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co", + "Exported hairkey location", -1e4, 1e4); + RNA_def_property_flag(prop, PROP_THICK_WRAP); + RNA_def_function_output(func, prop); } static void rna_def_particle_key(BlenderRNA *brna) @@ -979,6 +1315,7 @@ static void rna_def_particle(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; static EnumPropertyItem alive_items[] = { /*{PARS_KILLED, "KILLED", 0, "Killed", ""}, */ @@ -1083,6 +1420,15 @@ static void rna_def_particle(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Alive State", ""); /* short rt2; */ + +/* UVs */ + func = RNA_def_function(srna, "uv_on_emitter", "rna_Particle_uv_on_emitter"); + RNA_def_function_ui_description(func, "Obtain uv for particle on derived mesh"); + prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS); + RNA_def_property_array(prop, 2); + RNA_def_property_flag(prop, PROP_THICK_WRAP); + RNA_def_function_output(func, prop); } static void rna_def_particle_dupliweight(BlenderRNA *brna) @@ -2696,6 +3042,7 @@ static void rna_def_particle_system(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; srna = RNA_def_struct(brna, "ParticleSystem", NULL); RNA_def_struct_ui_text(srna, "Particle System", "Particle system in an object"); @@ -2793,7 +3140,6 @@ static void rna_def_particle_system(BlenderRNA *brna) "rna_ParticleSystem_active_particle_target_index_range"); RNA_def_property_ui_text(prop, "Active Particle Target Index", ""); - /* billboard */ prop = RNA_def_property(srna, "billboard_normal_uv", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "bb_uvname[0]"); @@ -2995,6 +3341,44 @@ static void rna_def_particle_system(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_struct_path_func(srna, "rna_ParticleSystem_path"); + + /* extract cached hair location data */ + func = RNA_def_function(srna, "co_hair", "rna_ParticleSystem_co_hair"); + RNA_def_function_ui_description(func, "Obtain cache hair data"); + + prop = RNA_def_pointer(func, "object", "Object", "", "Object"); + prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); + prop = RNA_def_int(func, "step", 0, INT_MIN, INT_MAX, "step no", "", INT_MIN, INT_MAX); + + prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co", + "Exported hairkey location", -1e4, 1e4); + RNA_def_property_flag(prop, PROP_THICK_WRAP); + RNA_def_function_output(func, prop); + + /* extract hair UVs */ + func = RNA_def_function(srna, "uv_on_emitter", "rna_ParticleSystem_uv_on_emitter"); + RNA_def_function_ui_description(func, "Obtain uv for all particles"); + prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle"); + prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); + prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS); + RNA_def_property_array(prop, 2); + RNA_def_property_flag(prop, PROP_THICK_WRAP); + RNA_def_function_output(func, prop); + + /* extract hair mcols */ + func = RNA_def_function(srna, "mcol_on_emitter", "rna_ParticleSystem_mcol_on_emitter"); + RNA_def_function_ui_description(func, "Obtain mcol for all particles"); + prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle"); + prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); + prop = RNA_def_int(func, "vcol_no", 0, INT_MIN, INT_MAX, "vcol no", "", INT_MIN, INT_MAX); + prop = RNA_def_property(func, "mcol", PROP_FLOAT, PROP_COLOR); + RNA_def_property_array(prop, 3); + RNA_def_property_flag(prop, PROP_THICK_WRAP); + RNA_def_function_output(func, prop); + } void RNA_def_particle(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 28d1de2c601..23f61282b78 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -472,14 +472,14 @@ static void rna_pose_pgroup_name_set(PointerRNA *ptr, const char *value, char *r static PointerRNA rna_PoseChannel_active_constraint_get(PointerRNA *ptr) { bPoseChannel *pchan = (bPoseChannel *)ptr->data; - bConstraint *con = constraints_get_active(&pchan->constraints); + bConstraint *con = BKE_constraints_get_active(&pchan->constraints); return rna_pointer_inherit_refine(ptr, &RNA_Constraint, con); } static void rna_PoseChannel_active_constraint_set(PointerRNA *ptr, PointerRNA value) { bPoseChannel *pchan = (bPoseChannel *)ptr->data; - constraints_set_active(&pchan->constraints, (bConstraint *)value.data); + BKE_constraints_set_active(&pchan->constraints, (bConstraint *)value.data); } static bConstraint *rna_PoseChannel_constraints_new(bPoseChannel *pchan, int type) @@ -487,7 +487,7 @@ static bConstraint *rna_PoseChannel_constraints_new(bPoseChannel *pchan, int typ /*WM_main_add_notifier(NC_OBJECT|ND_CONSTRAINT|NA_ADDED, object); */ /* TODO, pass object also */ /* TODO, new pose bones don't have updated draw flags */ - return add_pose_constraint(NULL, pchan, NULL, type); + return BKE_add_pose_constraint(NULL, pchan, NULL, type); } static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, ReportList *reports, PointerRNA *con_ptr) @@ -501,12 +501,12 @@ static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, Repo return; } - remove_constraint(&pchan->constraints, con); + BKE_remove_constraint(&pchan->constraints, con); RNA_POINTER_INVALIDATE(con_ptr); ED_object_constraint_update(ob); - constraints_set_active(&pchan->constraints, NULL); /* XXX, is this really needed? - Campbell */ + BKE_constraints_set_active(&pchan->constraints, NULL); /* XXX, is this really needed? - Campbell */ WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, id); @@ -786,14 +786,14 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_editable_array_func(prop, "rna_PoseChannel_location_editable"); RNA_def_property_ui_text(prop, "Location", ""); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); - RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_IK_update"); prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "size"); RNA_def_property_editable_array_func(prop, "rna_PoseChannel_scale_editable"); RNA_def_property_float_array_default(prop, default_scale); RNA_def_property_ui_text(prop, "Scale", ""); - RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_IK_update"); prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION); RNA_def_property_float_sdna(prop, NULL, "quat"); diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 46b22cd0963..93c5b45e642 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -137,7 +137,7 @@ static void engine_update_script_node(RenderEngine *engine, struct bNodeTree *nt FunctionRNA *func; RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr); - RNA_pointer_create((ID*)ntree, &RNA_Node, node, &nodeptr); + RNA_pointer_create((ID *)ntree, &RNA_Node, node, &nodeptr); func = &rna_RenderEngine_update_script_node_func; RNA_parameter_list_create(&list, &ptr, func); @@ -406,6 +406,9 @@ static void rna_def_render_engine(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "resolution_y"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop = RNA_def_property(srna, "use_highlight_tiles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RE_ENGINE_HIGHLIGHT_TILES); + /* registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 29d7391ccb4..8d99cecd9fa 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -119,7 +119,8 @@ EnumPropertyItem proportional_falloff_curve_only_items[] = { EnumPropertyItem proportional_editing_items[] = { {PROP_EDIT_OFF, "DISABLED", ICON_PROP_OFF, "Disable", "Proportional Editing disabled"}, {PROP_EDIT_ON, "ENABLED", ICON_PROP_ON, "Enable", "Proportional Editing enabled"}, - {PROP_EDIT_CONNECTED, "CONNECTED", ICON_PROP_CON, "Connected", "Proportional Editing using connected geometry only"}, + {PROP_EDIT_CONNECTED, "CONNECTED", ICON_PROP_CON, "Connected", + "Proportional Editing using connected geometry only"}, {0, NULL, 0, NULL, NULL} }; @@ -880,7 +881,7 @@ static int rna_SceneRender_file_ext_length(PointerRNA *ptr) RenderData *rd = (RenderData *)ptr->data; char ext[8]; ext[0] = '\0'; - BKE_add_image_extension(ext, rd->im_format.imtype); + BKE_add_image_extension(ext, &rd->im_format); return strlen(ext); } @@ -888,7 +889,7 @@ static void rna_SceneRender_file_ext_get(PointerRNA *ptr, char *str) { RenderData *rd = (RenderData *)ptr->data; str[0] = '\0'; - BKE_add_image_extension(str, rd->im_format.imtype); + BKE_add_image_extension(str, &rd->im_format); } #ifdef WITH_QUICKTIME @@ -1137,7 +1138,7 @@ static void rna_SceneRenderLayer_name_set(PointerRNA *ptr, const char *value) static char *rna_SceneRenderLayer_path(PointerRNA *ptr) { - SceneRenderLayer *srl = (SceneRenderLayer*)ptr->data; + SceneRenderLayer *srl = (SceneRenderLayer *)ptr->data; return BLI_sprintfN("render.layers[\"%s\"]", srl->name); } @@ -1368,7 +1369,8 @@ static void rna_TimeLine_remove(Scene *scene, ReportList *reports, PointerRNA *m { TimeMarker *marker = marker_ptr->data; if (BLI_remlink_safe(&scene->markers, marker) == FALSE) { - BKE_reportf(reports, RPT_ERROR, "Timeline marker '%s' not found in scene '%s'", marker->name, scene->id.name + 2); + BKE_reportf(reports, RPT_ERROR, "Timeline marker '%s' not found in scene '%s'", + marker->name, scene->id.name + 2); return; } @@ -2050,7 +2052,8 @@ void rna_def_render_layer_common(StructRNA *srna, int scene) if (scene) { prop = RNA_def_property(srna, "samples", PROP_INT, PROP_UNSIGNED); - RNA_def_property_ui_text(prop, "Samples", "Override number of render samples for this render layer, 0 will use the scene setting"); + RNA_def_property_ui_text(prop, "Samples", "Override number of render samples for this render layer, " + "0 will use the scene setting"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); } @@ -2799,7 +2802,7 @@ static void rna_def_scene_game_recast_data(BlenderRNA *brna) prop = RNA_def_property(srna, "slope_max", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "agentmaxslope"); RNA_def_property_range(prop, 0, M_PI / 2); - RNA_def_property_ui_text(prop, "Max Slope", "Maximum walkable slope angle in degrees"); + RNA_def_property_ui_text(prop, "Max Slope", "Maximum walkable slope angle"); RNA_def_property_update(prop, NC_SCENE, NULL); @@ -2924,8 +2927,10 @@ static void rna_def_scene_game_data(BlenderRNA *brna) {RAS_STORE_AUTO, "AUTO", 0, "Auto Select", "Chooses the best supported mode"}, {RAS_STORE_IMMEDIATE, "IMMEDIATE", 0, "Immediate Mode", "Slowest performance, requires OpenGL (any version)"}, {RAS_STORE_VA, "VERTEX_ARRAY", 0, "Vertex Arrays", "Better performance, requires at least OpenGL 1.1"}, - /* VBOS are currently disabled since they cannot beat vertex array with display lists in performance. */ - /* {RAS_STORE_VBO, "VERTEX_BUFFER_OBJECT", 0, "Vertex Buffer Objects", "Best performance, requires at least OpenGL 1.4"}, */ +#if 0 /* XXX VBOS are currently disabled since they cannot beat vertex array with display lists in performance. */ + {RAS_STORE_VBO, "VERTEX_BUFFER_OBJECT", 0, "Vertex Buffer Objects", + "Best performance, requires at least OpenGL 1.4"}, +#endif {0, NULL, 0, NULL, NULL}}; srna = RNA_def_struct(brna, "SceneGameData", NULL); @@ -2960,13 +2965,13 @@ static void rna_def_scene_game_data(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "exitkey"); RNA_def_property_enum_items(prop, event_type_items); RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_exit_key_set", NULL); - RNA_def_property_ui_text(prop, "Exit Key", "The key that exits the Game Engine"); + RNA_def_property_ui_text(prop, "Exit Key", "The key that exits the Game Engine"); RNA_def_property_update(prop, NC_SCENE, NULL); prop = RNA_def_property(srna, "raster_storage", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "raster_storage"); RNA_def_property_enum_items(prop, storage_items); - RNA_def_property_ui_text(prop, "Storage", "Sets the storage mode used by the rasterizer"); + RNA_def_property_ui_text(prop, "Storage", "Set the storage mode used by the rasterizer"); RNA_def_property_update(prop, NC_SCENE, NULL); /* Do we need it here ? (since we already have it in World */ @@ -3252,6 +3257,12 @@ static void rna_def_scene_game_data(BlenderRNA *brna) "Use extra textures like normal or specular maps for GLSL rendering"); RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update"); + prop = RNA_def_property(srna, "use_material_caching", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_NO_MATERIAL_CACHING); + RNA_def_property_ui_text(prop, "Use Material Caching", + "Cache materials in the converter (this is faster, but can cause problems with older " + "Singletexture and Multitexture games"); + /* obstacle simulation */ prop = RNA_def_property(srna, "obstacle_simulation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "obstacleSimulation"); @@ -3370,6 +3381,14 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna) }; #endif +#ifdef WITH_OPENJPEG + static EnumPropertyItem jp2_codec_items[] = { + {R_IMF_JP2_CODEC_JP2, "JP2", 0, "JP2", ""}, + {R_IMF_JP2_CODEC_J2K, "J2K", 0, "J2K", ""}, + {0, NULL, 0, NULL, NULL} + }; +#endif + StructRNA *srna; PropertyRNA *prop; @@ -3457,6 +3476,12 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "jp2_flag", R_IMF_JP2_FLAG_CINE_48); RNA_def_property_ui_text(prop, "Cinema (48)", "Use Openjpeg Cinema Preset (48fps)"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + + prop = RNA_def_property(srna, "jpeg2k_codec", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "jp2_codec"); + RNA_def_property_enum_items(prop, jp2_codec_items); + RNA_def_property_ui_text(prop, "Codec", "Codec settings for Jpek2000"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); #endif /* Cineon and DPX */ @@ -3796,8 +3821,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) static EnumPropertyItem alpha_mode_items[] = { {R_ADDSKY, "SKY", 0, "Sky", "Transparent pixels are filled with sky color"}, - {R_ALPHAPREMUL, "PREMUL", 0, "Premultiplied", "Transparent RGB pixels are multiplied by the alpha channel"}, - {R_ALPHAKEY, "STRAIGHT", 0, "Straight Alpha", "Transparent RGB and alpha pixels are unmodified"}, + {R_ALPHAPREMUL, "TRANSPARENT", 0, "Transparent", "World background is transparent with premultiplied alpha"}, {0, NULL, 0, NULL, NULL} }; @@ -4174,10 +4198,9 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); - prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "blurfac"); - RNA_def_property_range(prop, 0.01f, 10.0f); - RNA_def_property_ui_range(prop, 0.01, 2.0f, 1, 0); + RNA_def_property_ui_range(prop, 0.01f, 2.0f, 1, 0); RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); @@ -4248,13 +4271,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) "editor pipeline, if sequencer strips exist"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - prop = RNA_def_property(srna, "use_color_unpremultiply", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "color_mgt_flag", R_COLOR_MANAGEMENT_PREDIVIDE); - RNA_def_property_ui_text(prop, "Color Unpremultiply", - "For premultiplied alpha render output, do color space conversion on " - "colors without alpha, to avoid fringing on light backgrounds"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - prop = RNA_def_property(srna, "use_file_extension", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_EXTENSION); RNA_def_property_ui_text(prop, "File Extensions", @@ -4407,6 +4423,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Samples", "Number of samples used for ambient occlusion baking from multires"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "use_bake_to_vertex_color", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_VCOL); + RNA_def_property_ui_text(prop, "Bake to Vertex Color", + "Bake to vertex colors instead of to a UV-mapped image"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + /* stamp */ prop = RNA_def_property(srna, "use_stamp_time", PROP_BOOLEAN, PROP_NONE); @@ -5169,7 +5191,7 @@ void RNA_def_scene(BlenderRNA *brna) prop = RNA_def_property(srna, "sequencer_colorspace_settings", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "sequencer_colorspace_settings"); - RNA_def_property_struct_type(prop, "ColorManagedColorspaceSettings"); + RNA_def_property_struct_type(prop, "ColorManagedSequencerColorspaceSettings"); RNA_def_property_ui_text(prop, "Sequencer Color Space Settings", "Settings of color space sequencer is working in"); /* Nestled Data */ diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 012767b5845..9b5a858a581 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -84,7 +84,7 @@ static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, char *name if (BKE_imtype_is_movie(rd->im_format.imtype)) BKE_movie_filepath_get(name, rd); else - BKE_makepicstring(name, rd->pic, G.main->name, (frame == INT_MIN) ? rd->cfra : frame, rd->im_format.imtype, + BKE_makepicstring(name, rd->pic, G.main->name, (frame == INT_MIN) ? rd->cfra : frame, &rd->im_format, rd->scemode & R_EXTENSION, TRUE); } diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index f717c83075a..17edf2944aa 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -40,6 +40,9 @@ #include "WM_api.h" #include "WM_types.h" +#include "BLI_utildefines.h" +#include "bmesh.h" + static EnumPropertyItem particle_edit_hair_brush_items[] = { {PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush"}, {PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs"}, @@ -52,6 +55,18 @@ static EnumPropertyItem particle_edit_hair_brush_items[] = { {0, NULL, 0, NULL, NULL} }; +EnumPropertyItem symmetrize_direction_items[] = { + {BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""}, + {BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""}, + + {BMO_SYMMETRIZE_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y to +Y", ""}, + {BMO_SYMMETRIZE_POSITIVE_Y, "POSITIVE_Y", 0, "+Y to -Y", ""}, + + {BMO_SYMMETRIZE_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z to +Z", ""}, + {BMO_SYMMETRIZE_POSITIVE_Z, "POSITIVE_Z", 0, "+Z to -Z", ""}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME #include "MEM_guardedalloc.h" @@ -204,6 +219,11 @@ static void rna_Sculpt_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNU if (ob) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob); + + if (ob->sculpt) { + ob->sculpt->bm_smooth_shading = (scene->toolsettings->sculpt->flags & + SCULPT_DYNTOPO_SMOOTH_SHADING); + } } } @@ -319,6 +339,27 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Show Diffuse Color", "Show diffuse color of object and overlay sculpt mask on top of it"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_ShowDiffuseColor_update"); + + prop = RNA_def_property(srna, "detail_size", PROP_INT, PROP_DISTANCE); + RNA_def_property_ui_range(prop, 2, 100, 0, 0); + RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (in pixels)"); + + prop = RNA_def_property(srna, "use_smooth_shading", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_DYNTOPO_SMOOTH_SHADING); + RNA_def_property_ui_text(prop, "Smooth Shading", + "Show faces in dynamic-topology mode with smooth " + "shading rather than flat shaded"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update"); + + prop = RNA_def_property(srna, "use_edge_collapse", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_DYNTOPO_COLLAPSE); + RNA_def_property_ui_text(prop, "Collapse Short Edges", + "In dynamic-topology mode, collapse short edges " + "in addition to subdividing long ones"); + + prop = RNA_def_property(srna, "symmetrize_direction", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, symmetrize_direction_items); + RNA_def_property_ui_text(prop, "Direction", "Source and destination for symmetrize operator"); } diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 18a9b9683f8..a41551fc8da 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1401,26 +1401,26 @@ static void rna_def_sequence(BlenderRNA *brna) prop = RNA_def_property(srna, "frame_offset_start", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "startofs"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ +// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ RNA_def_property_ui_text(prop, "Start Offset", ""); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); prop = RNA_def_property(srna, "frame_offset_end", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "endofs"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ +// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ RNA_def_property_ui_text(prop, "End Offset", ""); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); prop = RNA_def_property(srna, "frame_still_start", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "startstill"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ +// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ RNA_def_property_range(prop, 0, MAXFRAME); RNA_def_property_ui_text(prop, "Start Still", ""); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); prop = RNA_def_property(srna, "frame_still_end", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "endstill"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ +// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ RNA_def_property_range(prop, 0, MAXFRAME); RNA_def_property_ui_text(prop, "End Still", ""); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); @@ -1541,14 +1541,20 @@ static void rna_def_filter_video(StructRNA *srna) { PropertyRNA *prop; + static const EnumPropertyItem alpha_mode_items[] = { + {SEQ_ALPHA_STRAIGHT, "STRAIGHT", 0, "Straight", "RGB channels in transparent pixels are unaffected by the alpha channel"}, + {SEQ_ALPHA_PREMUL, "PREMUL", 0, "Premultiplied", "RGB channels in transparent pixels are multiplied by the alpha channel"}, + {0, NULL, 0, NULL, NULL} + }; + prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_FILTERY); RNA_def_property_ui_text(prop, "De-Interlace", "For video movies to remove fields"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update_reopen_files"); - prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_MAKE_PREMUL); - RNA_def_property_ui_text(prop, "Premultiply", "Convert RGB from key alpha to premultiplied alpha"); + prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, alpha_mode_items); + RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); prop = RNA_def_property(srna, "use_flip_x", PROP_BOOLEAN, PROP_NONE); @@ -1694,7 +1700,7 @@ static void rna_def_color_management(StructRNA *srna) prop = RNA_def_property(srna, "colorspace_settings", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "strip->colorspace_settings"); - RNA_def_property_struct_type(prop, "ColorManagedColorspaceSettings"); + RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings"); RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings"); } diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 7602ec99c2b..69d35a3c2f0 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -37,6 +37,8 @@ #include "DNA_scene_types.h" #include "DNA_sequence_types.h" +#include "BLI_utildefines.h" + #ifdef RNA_RUNTIME //#include "DNA_anim_types.h" @@ -62,6 +64,16 @@ #include "WM_api.h" +static void rna_Sequence_update_rnafunc(ID *id, Sequence *self, int do_data) +{ + if (do_data) { + BKE_sequencer_update_changed_seq_and_deps((Scene *)id, self, true, true); + // new_tstripdata(self); // need 2.6x version of this. + } + BKE_sequence_calc((Scene *)id, self); + BKE_sequence_calc_disp((Scene *)id, self); +} + static void rna_Sequence_swap_internal(Sequence *seq_self, ReportList *reports, Sequence *seq_other) { const char *error_msg; @@ -389,7 +401,13 @@ void RNA_api_sequence_strip(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; - func = RNA_def_function(srna, "getStripElem", "BKE_sequencer_give_stripelem"); + func = RNA_def_function(srna, "update", "rna_Sequence_update_rnafunc"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + RNA_def_function_ui_description(func, "Update the strip dimensions"); + parm = RNA_def_boolean(func, "data", false, "Frame", + "Update strip data"); + + func = RNA_def_function(srna, "strip_elem_from_frame", "BKE_sequencer_give_stripelem"); RNA_def_function_ui_description(func, "Return the strip element from a given frame or None"); parm = RNA_def_int(func, "frame", 0, -MAXFRAME, MAXFRAME, "Frame", "The frame to get the strip element from", -MAXFRAME, MAXFRAME); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 09209ddea4d..7fa3aae8ede 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2375,11 +2375,11 @@ static void rna_def_space_dopesheet(BlenderRNA *brna) /* XXX: action-editor is currently for object-level only actions, so show that using object-icon hint */ static EnumPropertyItem mode_items[] = { - {SACTCONT_DOPESHEET, "DOPESHEET", ICON_OOPS, "DopeSheet", "DopeSheet Editor"}, - {SACTCONT_ACTION, "ACTION", ICON_OBJECT_DATA, "Action Editor", "Action Editor"}, - {SACTCONT_SHAPEKEY, "SHAPEKEY", ICON_SHAPEKEY_DATA, "ShapeKey Editor", "ShapeKey Editor"}, - {SACTCONT_GPENCIL, "GPENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Grease Pencil"}, - {SACTCONT_MASK, "MASK", ICON_MOD_MASK, "Mask", "Mask Editor"}, + {SACTCONT_DOPESHEET, "DOPESHEET", ICON_OOPS, "DopeSheet", "Edit all keyframes in scene"}, + {SACTCONT_ACTION, "ACTION", ICON_OBJECT_DATA, "Action Editor", "Edit keyframes in active object's Object-level action"}, + {SACTCONT_SHAPEKEY, "SHAPEKEY", ICON_SHAPEKEY_DATA, "ShapeKey Editor", "Edit keyframes in active object's Shape Keys action"}, + {SACTCONT_GPENCIL, "GPENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Edit timings for all Grease Pencil sketches in file"}, + {SACTCONT_MASK, "MASK", ICON_MOD_MASK, "Mask", "Edit timings for Mask Editor splines"}, {0, NULL, 0, NULL, NULL} }; @@ -2723,6 +2723,7 @@ static void rna_def_console_line(BlenderRNA *brna) "rna_ConsoleLine_body_set"); RNA_def_property_ui_text(prop, "Line", "Text in the line"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CONSOLE, NULL); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_TEXT); prop = RNA_def_property(srna, "current_character", PROP_INT, PROP_NONE); /* copied from text editor */ RNA_def_property_int_sdna(prop, NULL, "cursor"); diff --git a/source/blender/makesrna/intern/rna_speaker.c b/source/blender/makesrna/intern/rna_speaker.c index 139582104ee..8a75aa2d227 100644 --- a/source/blender/makesrna/intern/rna_speaker.c +++ b/source/blender/makesrna/intern/rna_speaker.c @@ -62,6 +62,7 @@ static void rna_def_speaker(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", SPK_MUTED); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Mute", "Mute the speaker"); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_SOUND); /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ #if 0 /* This shouldn't be changed actually, hiding it! */ diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c index b1637ef4c8a..df6181af4b2 100644 --- a/source/blender/makesrna/intern/rna_text.c +++ b/source/blender/makesrna/intern/rna_text.c @@ -30,6 +30,8 @@ #include "MEM_guardedalloc.h" +#include "BLF_translation.h" + #include "BKE_text.h" #include "RNA_define.h" @@ -127,6 +129,7 @@ static void rna_def_text_line(BlenderRNA *brna) RNA_def_property_string_funcs(prop, "rna_TextLine_body_get", "rna_TextLine_body_length", "rna_TextLine_body_set"); RNA_def_property_ui_text(prop, "Line", "Text in the line"); RNA_def_property_update(prop, NC_TEXT | NA_EDITED, NULL); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_TEXT); } static void rna_def_text(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index e116e5df0de..2ab448c9188 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -1194,11 +1194,6 @@ static void rna_def_texture_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Flip Axis", "Flip the texture's X and Y axis"); RNA_def_property_update(prop, 0, "rna_Texture_update"); - prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "imaflag", TEX_USEALPHA); - RNA_def_property_ui_text(prop, "Use Alpha", "Use the alpha channel information in the image"); - RNA_def_property_update(prop, 0, "rna_Texture_update"); - prop = RNA_def_property(srna, "use_calculate_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "imaflag", TEX_CALCALPHA); RNA_def_property_ui_text(prop, "Calculate Alpha", "Calculate an alpha channel based on RGB values in the image"); diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index f5bcab3e530..7cc57947671 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -280,7 +280,7 @@ static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerR static void rna_trackingObject_tracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { - MovieTrackingObject *object = (MovieTrackingObject * )ptr->data; + MovieTrackingObject *object = (MovieTrackingObject *)ptr->data; if (object->flag & TRACKING_OBJECT_CAMERA) { MovieClip *clip = (MovieClip *)ptr->id.data; @@ -294,7 +294,7 @@ static void rna_trackingObject_tracks_begin(CollectionPropertyIterator *iter, Po static PointerRNA rna_trackingObject_reconstruction_get(PointerRNA *ptr) { - MovieTrackingObject *object = (MovieTrackingObject * )ptr->data; + MovieTrackingObject *object = (MovieTrackingObject *)ptr->data; if (object->flag & TRACKING_OBJECT_CAMERA) { MovieClip *clip = (MovieClip *)ptr->id.data; diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index de359fd6413..14789a437b7 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -55,6 +55,16 @@ EnumPropertyItem operator_context_items[] = { {0, NULL, 0, NULL, NULL} }; +EnumPropertyItem uilist_layout_type_items[] = { + {UILST_LAYOUT_DEFAULT, "DEFAULT", 0, "Default Layout", + "Use the default, multi-rows layout"}, + {UILST_LAYOUT_COMPACT, "COMPACT", 0, "Compact Layout", + "Use the compact, single-row layout"}, + {UILST_LAYOUT_GRID, "GRID", 0, "Grid Layout", + "Use the grid-based layout"}, + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME #include <assert.h> @@ -252,6 +262,105 @@ static StructRNA *rna_Panel_refine(PointerRNA *ptr) return (hdr->type && hdr->type->ext.srna) ? hdr->type->ext.srna : &RNA_Panel; } +/* UIList */ +static void uilist_draw_item(uiList *ui_list, bContext *C, uiLayout *layout, PointerRNA *dataptr, PointerRNA *itemptr, + int icon, PointerRNA *active_dataptr, const char *active_propname, int index) +{ + extern FunctionRNA rna_UIList_draw_item_func; + + PointerRNA ul_ptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create(&CTX_wm_screen(C)->id, ui_list->type->ext.srna, ui_list, &ul_ptr); + func = &rna_UIList_draw_item_func; /* RNA_struct_find_function(&ul_ptr, "draw_item"); */ + + RNA_parameter_list_create(&list, &ul_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + RNA_parameter_set_lookup(&list, "layout", &layout); + RNA_parameter_set_lookup(&list, "data", dataptr); + RNA_parameter_set_lookup(&list, "item", itemptr); + RNA_parameter_set_lookup(&list, "icon", &icon); + RNA_parameter_set_lookup(&list, "active_data", active_dataptr); + RNA_parameter_set_lookup(&list, "active_property", &active_propname); + RNA_parameter_set_lookup(&list, "index", &index); + ui_list->type->ext.call((bContext *)C, &ul_ptr, func, &list); + + RNA_parameter_list_free(&list); +} + +static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type) +{ + uiListType *ult = RNA_struct_blender_type_get(type); + + if (!ult) + return; + + RNA_struct_free_extension(type, &ult->ext); + + WM_uilisttype_freelink(ult); + + RNA_struct_free(&BLENDER_RNA, type); + + /* update while blender is running */ + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); +} + +static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +{ + uiListType *ult, dummyult = {NULL}; + uiList dummyuilist = {NULL}; + PointerRNA dummyul_ptr; + int have_function[1]; + size_t over_alloc = 0; /* warning, if this becomes a bess, we better do another alloc */ + + /* setup dummy menu & menu type to store static properties in */ + dummyuilist.type = &dummyult; + RNA_pointer_create(NULL, &RNA_UIList, &dummyuilist, &dummyul_ptr); + + /* validate the python class */ + if (validate(&dummyul_ptr, data, have_function) != 0) + return NULL; + + if (strlen(identifier) >= sizeof(dummyult.idname)) { + BKE_reportf(reports, RPT_ERROR, "Registering uilist class: '%s' is too long, maximum length is %d", + identifier, (int)sizeof(dummyult.idname)); + return NULL; + } + + /* check if we have registered this uilist type before, and remove it */ + ult = WM_uilisttype_find(dummyult.idname, TRUE); + if (ult && ult->ext.srna) + rna_UIList_unregister(bmain, ult->ext.srna); + + /* create a new menu type */ + ult = MEM_callocN(sizeof(uiListType) + over_alloc, "python uilist"); + memcpy(ult, &dummyult, sizeof(dummyult)); + + ult->ext.srna = RNA_def_struct(&BLENDER_RNA, ult->idname, "UIList"); + ult->ext.data = data; + ult->ext.call = call; + ult->ext.free = free; + RNA_struct_blender_type_set(ult->ext.srna, ult); + RNA_def_struct_flag(ult->ext.srna, STRUCT_NO_IDPROPERTIES); + + ult->draw_item = (have_function[0]) ? uilist_draw_item : NULL; + + WM_uilisttype_add(ult); + + /* update while blender is running */ + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); + + return ult->ext.srna; +} + +static StructRNA *rna_UIList_refine(PointerRNA *ptr) +{ + uiList *ui_list = (uiList *)ptr->data; + return (ui_list->type && ui_list->type->ext.srna) ? ui_list->type->ext.srna : &RNA_UIList; +} + /* Header */ static void header_draw(const bContext *C, Header *hdr) @@ -495,6 +604,8 @@ static void rna_Menu_bl_description_set(PointerRNA *ptr, const char *value) else assert(!"setting the bl_description on a non-builtin menu"); } +/* UILayout */ + static int rna_UILayout_active_get(PointerRNA *ptr) { return uiLayoutGetActive(ptr->data); @@ -738,6 +849,58 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Options", "Options for this panel type"); } +static void rna_def_uilist(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + PropertyRNA *parm; + FunctionRNA *func; + + srna = RNA_def_struct(brna, "UIList", NULL); + RNA_def_struct_ui_text(srna, "UIList", "UI list containing the elements of a collection"); + RNA_def_struct_sdna(srna, "uiList"); + RNA_def_struct_refine_func(srna, "rna_UIList_refine"); + RNA_def_struct_register_funcs(srna, "rna_UIList_register", "rna_UIList_unregister", NULL); + + /* draw */ + func = RNA_def_function(srna, "draw_item", NULL); + RNA_def_function_ui_description(func, "Draw an item in the list (NOTE: when you define your own draw_item " + "function, you may want to check given 'item' is of the right type...)"); + RNA_def_function_flag(func, FUNC_REGISTER); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take Collection property"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + parm = RNA_def_pointer(func, "item", "AnyType", "", "Item of the collection property"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + parm = RNA_def_int(func, "icon", 0, 0, INT_MAX, "", "Icon of the item in the collection", 0, INT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_pointer(func, "active_data", "AnyType", "", + "Data from which to take property for the active element"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + parm = RNA_def_string(func, "active_property", "", 0, "", + "Identifier of property in active_data, for the active element"); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_int(func, "index", 0, 0, INT_MAX, "", "Index of the item in the collection", 0, INT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED); + + prop = RNA_def_property(srna, "layout_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, uilist_layout_type_items); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + /* registration */ + prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->idname"); + RNA_def_property_flag(prop, PROP_REGISTER | PROP_NEVER_CLAMP); + RNA_def_property_ui_text(prop, "ID Name", + "If this is set, the uilist gets a custom ID, otherwise it takes the " + "name of the class used to define the uilist (for example, if the " + "class name is \"OBJECT_UL_vgroups\", and bl_idname is not set by the " + "script, then bl_idname = \"OBJECT_UL_vgroups\")"); +} + static void rna_def_header(BlenderRNA *brna) { StructRNA *srna; @@ -852,6 +1015,7 @@ void RNA_def_ui(BlenderRNA *brna) { rna_def_ui_layout(brna); rna_def_panel(brna); + rna_def_uilist(brna); rna_def_header(brna); rna_def_menu(brna); } diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 548539e3395..366d0dc1fd9 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -33,8 +33,12 @@ #include <stdio.h> #include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "DNA_screen_types.h" #include "UI_resources.h" +#include "UI_interface_icons.h" #include "rna_internal.h" @@ -70,12 +74,117 @@ static PointerRNA rna_uiItemO(uiLayout *layout, const char *opname, const char * return uiItemFullO(layout, opname, name, icon, NULL, uiLayoutGetOperatorContext(layout), flag); } +static void rna_uiItemL(uiLayout *layout, const char *name, int icon, int icon_value) +{ + if (icon_value && !icon) { + icon = icon_value; + } + + uiItemL(layout, name, icon); +} + +static int rna_ui_get_rnaptr_icon(bContext *C, PointerRNA *ptr_icon) +{ + return UI_rnaptr_icon_get(C, ptr_icon, RNA_struct_ui_icon(ptr_icon->type), FALSE); +} + +static const char *rna_ui_get_enum_name(bContext *C, PointerRNA *ptr, const char *propname, const char *identifier) +{ + PropertyRNA *prop = NULL; + EnumPropertyItem *items = NULL, *item; + int free; + const char *name = ""; + + prop = RNA_struct_find_property(ptr, propname); + if (!prop || (RNA_property_type(prop) != PROP_ENUM)) { + RNA_warning("Property not found or not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname); + return name; + } + + RNA_property_enum_items_gettexted(C, ptr, prop, &items, NULL, &free); + + if (items) { + for (item = items; item->identifier; item++) { + if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) { + name = item->name; + break; + } + } + if (free) { + MEM_freeN(items); + } + } + + return name; +} + +static const char *rna_ui_get_enum_description(bContext *C, PointerRNA *ptr, const char *propname, + const char *identifier) +{ + PropertyRNA *prop = NULL; + EnumPropertyItem *items = NULL, *item; + int free; + const char *desc = ""; + + prop = RNA_struct_find_property(ptr, propname); + if (!prop || (RNA_property_type(prop) != PROP_ENUM)) { + RNA_warning("Property not found or not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname); + return desc; + } + + RNA_property_enum_items_gettexted(C, ptr, prop, &items, NULL, &free); + + if (items) { + for (item = items; item->identifier; item++) { + if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) { + desc = item->description; + break; + } + } + if (free) { + MEM_freeN(items); + } + } + + return desc; +} + +static int rna_ui_get_enum_icon(bContext *C, PointerRNA *ptr, const char *propname, const char *identifier) +{ + PropertyRNA *prop = NULL; + EnumPropertyItem *items = NULL, *item; + int free; + int icon = ICON_NONE; + + prop = RNA_struct_find_property(ptr, propname); + if (!prop || (RNA_property_type(prop) != PROP_ENUM)) { + RNA_warning("Property not found or not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname); + return icon; + } + + RNA_property_enum_items(C, ptr, prop, &items, NULL, &free); + + if (items) { + for (item = items; item->identifier; item++) { + if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) { + icon = item->icon; + break; + } + } + if (free) { + MEM_freeN(items); + } + } + + return icon; +} + #else #define DEF_ICON_BLANK_SKIP #define DEF_ICON(name) {ICON_##name, (#name), 0, (#name), ""}, #define DEF_VICO(name) {VICO_##name, (#name), 0, (#name), ""}, -static EnumPropertyItem icon_items[] = { +EnumPropertyItem icon_items[] = { #include "UI_icons.h" {0, NULL, 0, NULL, NULL} }; @@ -92,7 +201,6 @@ static void api_ui_item_common(FunctionRNA *func) prop = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, icon_items); RNA_def_property_ui_text(prop, "Icon", "Override automatic icon of the item"); - } static void api_ui_item_op(FunctionRNA *func) @@ -130,13 +238,6 @@ void RNA_api_ui_layout(StructRNA *srna) {'h', "HUE", 0, "Hue", ""}, {0, NULL, 0, NULL, NULL} }; - - static EnumPropertyItem list_type_items[] = { - {0, "DEFAULT", 0, "None", ""}, - {'c', "COMPACT", 0, "Compact", ""}, - {'i', "ICONS", 0, "Icons", ""}, - {0, NULL, 0, NULL, NULL} - }; /* simple layout specifiers */ func = RNA_def_function(srna, "row", "uiLayoutRow"); @@ -175,6 +276,44 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_float(func, "percentage", 0.0f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at", 0.0f, 1.0f); RNA_def_boolean(func, "align", 0, "", "Align buttons to each other"); + /* Icon of a rna pointer */ + func = RNA_def_function(srna, "icon", "rna_ui_get_rnaptr_icon"); + parm = RNA_def_int(func, "icon_value", ICON_NONE, 0, INT_MAX, "", "Icon identifier", 0, INT_MAX); + RNA_def_function_return(func, parm); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); + parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take the icon"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_function_ui_description(func, "Return the custom icon for this data, " + "use it e.g. to get materials or texture icons"); + + /* UI name, description and icon of an enum item */ + func = RNA_def_function(srna, "enum_item_name", "rna_ui_get_enum_name"); + parm = RNA_def_string(func, "name", "", 0, "", "UI name of the enum item"); + RNA_def_function_return(func, parm); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); + api_ui_item_rna_common(func); + parm = RNA_def_string(func, "identifier", "", 0, "", "Identifier of the enum item"); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_function_ui_description(func, "Return the UI name for this enum item"); + + func = RNA_def_function(srna, "enum_item_description", "rna_ui_get_enum_description"); + parm = RNA_def_string(func, "description", "", 0, "", "UI description of the enum item"); + RNA_def_function_return(func, parm); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); + api_ui_item_rna_common(func); + parm = RNA_def_string(func, "identifier", "", 0, "", "Identifier of the enum item"); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_function_ui_description(func, "Return the UI description for this enum item"); + + func = RNA_def_function(srna, "enum_item_icon", "rna_ui_get_enum_icon"); + parm = RNA_def_int(func, "icon_value", ICON_NONE, 0, INT_MAX, "", "Icon identifier", 0, INT_MAX); + RNA_def_function_return(func, parm); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); + api_ui_item_rna_common(func); + parm = RNA_def_string(func, "identifier", "", 0, "", "Identifier of the enum item"); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_function_ui_description(func, "Return the icon for this enum item"); + /* items */ func = RNA_def_function(srna, "prop", "rna_uiItemR"); RNA_def_function_ui_description(func, "Item. Exposes an RNA item and places it into the layout"); @@ -274,9 +413,13 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_property_flag(parm, PROP_REQUIRED); #endif - func = RNA_def_function(srna, "label", "uiItemL"); - RNA_def_function_ui_description(func, "Item. Display text in the layout"); + func = RNA_def_function(srna, "label", "rna_uiItemL"); + RNA_def_function_ui_description(func, "Item. Display text and/or icon in the layout"); api_ui_item_common(func); + parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED); + RNA_def_property_ui_text(parm, "Icon Value", + "Override automatic icon of the item " + "(use it e.g. with custom material icons returned by icon()...)"); func = RNA_def_function(srna, "menu", "uiItemM"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); @@ -439,26 +582,29 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_boolean(func, "compact", 0, "", "Use more compact layout"); func = RNA_def_function(srna, "template_list", "uiTemplateList"); - RNA_def_function_ui_description(func, "Item. A list widget to display data, e.g. vertexgroups " - "(WARNING: only one per panel allowed!)."); + RNA_def_function_ui_description(func, "Item. A list widget to display data, e.g. vertexgroups."); RNA_def_function_flag(func, FUNC_USE_CONTEXT); - parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property"); + parm = RNA_def_string(func, "listtype_name", "", 0, "", "Identifier of the list type to use"); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_string(func, "list_id", "", 0, "", + "Identifier of this list widget. " + "If this is set, the uilist gets a custom ID, otherwise it takes the " + "name of the class used to define the uilist (for example, if the " + "class name is \"OBJECT_UL_vgroups\", and list_id is not set by the " + "script, then bl_idname = \"OBJECT_UL_vgroups\")"); + parm = RNA_def_pointer(func, "dataptr", "AnyType", "", "Data from which to take the Collection property"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); - parm = RNA_def_string(func, "property", "", 0, "", "Identifier of property in data"); + parm = RNA_def_string(func, "propname", "", 0, "", "Identifier of the Collection property in data"); RNA_def_property_flag(parm, PROP_REQUIRED); - parm = RNA_def_pointer(func, "active_data", "AnyType", "", - "Data from which to take property for the active element"); + parm = RNA_def_pointer(func, "active_dataptr", "AnyType", "", + "Data from which to take the integer property, index of the active item"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); - parm = RNA_def_string(func, "active_property", "", 0, "", - "Identifier of property in data, for the active element"); + parm = RNA_def_string(func, "active_propname", "", 0, "", + "Identifier of the integer property in active_data, index of the active item"); RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_string(func, "prop_list", "", 0, "", - "Identifier of a string property in each data member, specifying which " - "of its properties should have a widget displayed in its row " - "(format: \"propname1:propname2:propname3:...\")"); RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Number of rows to display", 0, INT_MAX); RNA_def_int(func, "maxrows", 5, 0, INT_MAX, "", "Maximum number of rows to display", 0, INT_MAX); - RNA_def_enum(func, "type", list_type_items, 0, "Type", "Type of list to use"); + RNA_def_enum(func, "type", uilist_layout_type_items, UILST_LAYOUT_DEFAULT, "Type", "Type of layout to use"); func = RNA_def_function(srna, "template_running_jobs", "uiTemplateRunningJobs"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 06154a235aa..7474ff40e32 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -47,6 +47,7 @@ #include "BLF_translation.h" #include "BKE_sound.h" +#include "BKE_addon.h" #ifdef WITH_CYCLES static EnumPropertyItem compute_device_type_items[] = { @@ -67,6 +68,7 @@ static EnumPropertyItem compute_device_type_items[] = { #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_idprop.h" #include "GPU_draw.h" @@ -79,6 +81,8 @@ static EnumPropertyItem compute_device_type_items[] = { #include "CCL_api.h" +#include "BKE_addon.h" + static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { WM_main_add_notifier(NC_WINDOW, NULL); @@ -428,6 +432,103 @@ static EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C), Poi } #endif +static IDProperty *rna_AddonPref_idprops(PointerRNA *ptr, int create) +{ + if (create && !ptr->data) { + IDPropertyTemplate val = {0}; + ptr->data = IDP_New(IDP_GROUP, &val, "RNA_AddonPreferences group"); + } + + return ptr->data; +} + +static PointerRNA rna_Addon_preferences_get(PointerRNA *ptr) +{ + bAddon *addon = (bAddon *)ptr->data; + bAddonPrefType *apt = BKE_addon_pref_type_find(addon->module, TRUE); + if (apt) { + if (addon->prop == NULL) { + IDPropertyTemplate val = {0}; + addon->prop = IDP_New(IDP_GROUP, &val, addon->module); /* name is unimportant */ + } + return rna_pointer_inherit_refine(ptr, apt->ext.srna, addon->prop); + } + else { + return PointerRNA_NULL; + } +} + +static void rna_AddonPref_unregister(Main *UNUSED(bmain), StructRNA *type) +{ + bAddonPrefType *apt = RNA_struct_blender_type_get(type); + + if (!apt) + return; + + RNA_struct_free_extension(type, &apt->ext); + + BKE_addon_pref_type_remove(apt); + RNA_struct_free(&BLENDER_RNA, type); + + /* update while blender is running */ + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); +} + +static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +{ + bAddonPrefType *apt, dummyapt = {{'\0'}}; + bAddon dummyaddon = {NULL}; + PointerRNA dummyhtr; + // int have_function[1]; + + /* setup dummy header & header type to store static properties in */ + RNA_pointer_create(NULL, &RNA_AddonPreferences, &dummyaddon, &dummyhtr); + + /* validate the python class */ + if (validate(&dummyhtr, data, NULL /* have_function */ ) != 0) + return NULL; + + BLI_strncpy(dummyapt.idname, dummyaddon.module, sizeof(dummyapt.idname)); + if (strlen(identifier) >= sizeof(dummyapt.idname)) { + BKE_reportf(reports, RPT_ERROR, "Registering addon-prefs class: '%s' is too long, maximum length is %d", + identifier, (int)sizeof(dummyapt.idname)); + return NULL; + } + + /* check if we have registered this header type before, and remove it */ + apt = BKE_addon_pref_type_find(dummyaddon.module, TRUE); + if (apt) { + if (apt->ext.srna) { + rna_AddonPref_unregister(bmain, apt->ext.srna); + } + } + + /* create a new header type */ + apt = MEM_mallocN(sizeof(bAddonPrefType), "addonpreftype"); + memcpy(apt, &dummyapt, sizeof(dummyapt)); + BKE_addon_pref_type_add(apt); + + apt->ext.srna = RNA_def_struct(&BLENDER_RNA, identifier, "AddonPreferences"); + apt->ext.data = data; + apt->ext.call = call; + apt->ext.free = free; + RNA_struct_blender_type_set(apt->ext.srna, apt); + +// apt->draw = (have_function[0]) ? header_draw : NULL; + + /* update while blender is running */ + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); + + return apt->ext.srna; +} + +/* placeholder, doesn't do anything useful yet */ +static StructRNA *rna_AddonPref_refine(PointerRNA *ptr) +{ + return (ptr->type) ? ptr->type : &RNA_AddonPreferences; +} + #else static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna) @@ -437,7 +538,7 @@ static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna) static EnumPropertyItem font_kerning_style[] = { {0, "UNFITTED", 0, "Unfitted", "Use scaled but un-grid-fitted kerning distances"}, - {1, "DEFAULT", 0, "Default", "Use scaled and grid-fitted kerning distances"}, + {1, "FITTED", 0, "Fitted", "Use scaled and grid-fitted kerning distances"}, {0, NULL, 0, NULL, NULL} }; @@ -1549,10 +1650,28 @@ static void rna_def_userdef_theme_space_text(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Syntax Built-in", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "syntax_symbols", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "syntaxs"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Syntax Symbols", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "syntax_special", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "syntaxv"); RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Decorator", ""); + RNA_def_property_ui_text(prop, "Syntax Special", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "syntax_preprocessor", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "syntaxd"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Syntax PreProcessor", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "syntax_reserved", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "syntaxr"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Syntax Reserved", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); prop = RNA_def_property(srna, "syntax_comment", PROP_FLOAT, PROP_COLOR_GAMMA); @@ -2228,6 +2347,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna) static EnumPropertyItem active_theme_area[] = { {0, "USER_INTERFACE", ICON_UI, "User Interface", ""}, + {19, "STYLE", ICON_FONTPREVIEW, "Text Style", ""}, {18, "BONE_COLOR_SETS", ICON_COLOR, "Bone Color Sets", ""}, {1, "VIEW_3D", ICON_VIEW3D, "3D View", ""}, {2, "TIMELINE", ICON_TIME, "Timeline", ""}, @@ -2394,6 +2514,32 @@ static void rna_def_userdef_addon(BlenderRNA *brna) prop = RNA_def_property(srna, "module", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Module", "Module name"); RNA_def_struct_name_property(srna, prop); + + /* Collection active property */ + prop = RNA_def_property(srna, "preferences", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "AddonPreferences"); + RNA_def_property_pointer_funcs(prop, "rna_Addon_preferences_get", NULL, NULL, NULL); +} + +static void rna_def_userdef_addon_pref(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "AddonPreferences", NULL); + RNA_def_struct_ui_text(srna, "Addon Preferences", ""); + RNA_def_struct_sdna(srna, "bAddon"); /* WARNING: only a bAddon during registration */ + + RNA_def_struct_refine_func(srna, "rna_AddonPref_refine"); + RNA_def_struct_register_funcs(srna, "rna_AddonPref_register", "rna_AddonPref_unregister", NULL); + RNA_def_struct_idprops_func(srna, "rna_AddonPref_idprops"); + + /* registration */ + RNA_define_verify_sdna(0); + prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "module"); + RNA_def_property_flag(prop, PROP_REGISTER | PROP_NEVER_CLAMP); + RNA_define_verify_sdna(1); } @@ -3031,62 +3177,10 @@ static void rna_def_userdef_system(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; -#if 0 - /* hardcoded here, could become dynamic somehow */ - /* locale according to http://www.roseindia.net/tutorials/I18N/locales-list.shtml */ - /* if you edit here, please also edit the source/blender/blenfont/intern/blf_lang.c 's locales */ - /* Note: As this list is in alphabetical order, and not defined order, - * here is the highest define currently in use: 35 (Esperanto). */ - static EnumPropertyItem language_items[] = { - { 0, "", 0, N_("Nearly Done"), ""}, - { 0, "DEFAULT", 0, "Default (Default)", ""}, - /* using the utf8 flipped form of Arabic (العربية) */ - {21, "ARABIC", 0, "Arabic (ﺔﻴﺑﺮﻌﻟﺍ)", "ar_EG"}, - {32, "BRAZILIANPORTUGUESE", 0, "Brazilian Portuguese (Português do Brasil)", "pt_BR"}, - { 1, "ENGLISH", 0, "English (English)", "en_US"}, - { 8, "FRENCH", 0, "French (Français)", "fr_FR"}, - { 4, "ITALIAN", 0, "Italian (Italiano)", "it_IT"}, - { 2, "JAPANESE", 0, "Japanese (日本語)", "ja_JP"}, - {12, "PORTUGUESE", 0, "Portuguese (Português)", "pt"}, - {15, "RUSSIAN", 0, "Russian (Русский)", "ru_RU"}, - {13, "SIMPLIFIED_CHINESE", 0, "Simplified Chinese (简体中文)", "zh_CN"}, - { 9, "SPANISH", 0, "Spanish (Español)", "es"}, - {14, "TRADITIONAL_CHINESE", 0, "Traditional Chinese (繁體中文)", "zh_TW"}, - {18, "UKRAINIAN", 0, "Ukrainian (Український)", "uk_UA"}, - { 0, "", 0, N_("In Progress"), ""}, -/* {22, "BULGARIAN", 0, "Bulgarian (Български)", "bg_BG"},*/ /* XXX Not active nor enough translated. */ -/* {10, "CATALAN", 0, "Catalan (Català)", "ca_AD"},*/ /* XXX Not active nor enough translated. */ - {16, "CROATIAN", 0, "Croatian (Hrvatski)", "hr_HR"}, - {11, "CZECH", 0, "Czech (Český)", "cs_CZ"}, - { 3, "DUTCH", 0, "Dutch (Nederlandse taal)", "nl_NL"}, - {35, "ESPERANTO", 0, "Esperanto (Esperanto)", "eo"}, - {34, "ESTONIAN", 0, "Estonian (Eestlane)", "et_EE"}, -/* { 6, "FINNISH", 0, "Finnish (Suomi)", "fi_FI"},*/ /* XXX Not active nor enough translated. */ - { 5, "GERMAN", 0, "German (Deutsch)", "de_DE"}, -/* {23, "GREEK", 0, "Greek (Ελληνικά)", "el_GR"},*/ /* XXX Not active nor enough translated. */ - /* using the utf8 flipped form of Hebrew (עִבְרִית)) */ - {33, "HEBREW", 0, "Hebrew (תירִבְעִ)", "he_IL"}, - {31, "HUNGARIAN", 0, "Hungarian (Magyar)", "hu_HU"}, - {27, "INDONESIAN", 0, "Indonesian (Bahasa indonesia)", "id_ID"}, - {29, "KYRGYZ", 0, "Kyrgyz (Кыргыз тили)", "ky_KG"}, -/* {24, "KOREAN", 0, "Korean (한국 언어)", "ko_KR"}, */ /* XXX Not active nor enough translated. */ -/* {25, "NEPALI", 0, "Nepali (नेपाली)", "ne_NP"},*/ /* XXX Not active nor enough translated. */ - /* using the utf8 flipped form of Persian (فارسی) */ - {26, "PERSIAN", 0, "Persian (ﯽﺳﺭﺎﻓ)", "fa_IR"}, -/* {19, "POLISH", 0, "Polish (Polski)", "pl_PL"},*/ /* XXX Not active nor enough translated. */ -/* {20, "ROMANIAN", 0, "Romanian (Român)", "ro_RO"}, */ /* XXX Not active nor enough translated. */ - {17, "SERBIAN", 0, "Serbian (Српски)", "sr_RS"}, - {28, "SERBIAN_LATIN", 0, "Serbian Latin (Srpski latinica)", "sr_RS@latin"}, - { 7, "SWEDISH", 0, "Swedish (Svenska)", "sv_SE"}, - {30, "TURKISH", 0, "Turkish (Türkçe)", "tr_TR"}, - { 0, NULL, 0, NULL, NULL} - }; -#else static EnumPropertyItem language_items[] = { - { 0, "DEFAULT", 0, "Default (Default)", ""}, - { 0, NULL, 0, NULL, NULL} + {0, "DEFAULT", 0, "Default (Default)", ""}, + {0, NULL, 0, NULL, NULL} }; -#endif #ifdef WITH_CYCLES static EnumPropertyItem compute_device_items[] = { @@ -3801,6 +3895,7 @@ void RNA_def_userdef(BlenderRNA *brna) rna_def_userdef_filepaths(brna); rna_def_userdef_system(brna); rna_def_userdef_addon(brna); + rna_def_userdef_addon_pref(brna); } diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 59befe4db05..776adb57c13 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -140,7 +140,7 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *UNUSED(ob), } } - BM_mesh_bevel(bm, bmd->value, segments); + BM_mesh_bevel(bm, bmd->value, segments, bmd->flags & BME_BEVEL_VERT); result = CDDM_from_bmesh(bm, TRUE); diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index a23b677f8e6..2d3d5c97af7 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -63,7 +63,7 @@ static void initData(ModifierData *md) DecimateModifierData *dmd = (DecimateModifierData *) md; dmd->percent = 1.0; - dmd->angle = DEG2RADF(15.0f); + dmd->angle = DEG2RADF(5.0f); } static void copyData(ModifierData *md, ModifierData *target) diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 5c786626c94..33601c197b9 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -48,7 +48,6 @@ #include "DNA_object_types.h" -#define EDGE_MARK 1 static DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd, Object *UNUSED(ob)) { diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 564fa696c2a..c0e529f1eae 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -139,10 +139,10 @@ static void initData(ModifierData *md) omd->ocean = BKE_add_ocean(); init_ocean_modifier(omd); simulate_ocean_modifier(omd); -#else // WITH_OCEANSIM +#else /* WITH_OCEANSIM */ /* unused */ (void)md; -#endif // WITH_OCEANSIM +#endif /* WITH_OCEANSIM */ } static void freeData(ModifierData *md) @@ -153,10 +153,10 @@ static void freeData(ModifierData *md) BKE_free_ocean(omd->ocean); if (omd->oceancache) BKE_free_ocean_cache(omd->oceancache); -#else // WITH_OCEANSIM +#else /* WITH_OCEANSIM */ /* unused */ (void)md; -#endif // WITH_OCEANSIM +#endif /* WITH_OCEANSIM */ } static void copyData(ModifierData *md, ModifierData *target) @@ -201,11 +201,11 @@ static void copyData(ModifierData *md, ModifierData *target) tomd->ocean = BKE_add_ocean(); init_ocean_modifier(tomd); simulate_ocean_modifier(tomd); -#else // WITH_OCEANSIM +#else /* WITH_OCEANSIM */ /* unused */ (void)md; (void)target; -#endif // WITH_OCEANSIM +#endif /* WITH_OCEANSIM */ } #ifdef WITH_OCEANSIM @@ -219,14 +219,14 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) return dataMask; } -#else // WITH_OCEANSIM +#else /* WITH_OCEANSIM */ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) { /* unused */ (void)md; return 0; } -#endif // WITH_OCEANSIM +#endif /* WITH_OCEANSIM */ #if 0 static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, float *oy) @@ -302,11 +302,7 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd) mpolys = CDDM_get_polys(result); mloops = CDDM_get_loops(result); -#if 0 // trunk - origindex = result->getFaceDataArray(result, CD_ORIGINDEX); -#else // bmesh origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX); -#endif /* create vertices */ #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES) @@ -443,7 +439,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob, cfra = md->scene->r.cfra; CLAMP(cfra, omd->bakestart, omd->bakeend); - cfra -= omd->bakestart; // shift to 0 based + cfra -= omd->bakestart; /* shift to 0 based */ num_verts = dm->getNumVerts(dm); num_faces = dm->getNumPolys(dm); @@ -500,7 +496,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob, /* displace the geometry */ - //#pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES) + /* #pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES) */ for (i = 0, mv = mverts; i < num_verts; i++, mv++) { const float u = OCEAN_CO(size_co_inv, mv->co[0]); const float v = OCEAN_CO(size_co_inv, mv->co[1]); @@ -522,7 +518,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob, return dm; } -#else // WITH_OCEANSIM +#else /* WITH_OCEANSIM */ static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob), DerivedMesh *derivedData, int UNUSED(useRenderParams)) @@ -531,7 +527,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob), (void)md; return derivedData; } -#endif // WITH_OCEANSIM +#endif /* WITH_OCEANSIM */ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 93b5e36e5a4..ff88cd97197 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -225,7 +225,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, /* angle */ -#if 0 // cant incluide this, not predictable enough, though quite fun,. +#if 0 /* cant incluide this, not predictable enough, though quite fun. */ if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) { float mtx3_tx[3][3]; copy_m3_m4(mtx3_tx, mtx_tx); diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c index 7fe8dc69790..697ccdc49a4 100644 --- a/source/blender/modifiers/intern/MOD_shapekey.c +++ b/source/blender/modifiers/intern/MOD_shapekey.c @@ -54,13 +54,16 @@ static void deformVerts(ModifierData *md, Object *ob, int numVerts, ModifierApplyFlag UNUSED(flag)) { - KeyBlock *kb = BKE_keyblock_from_object(ob); + Key *key = BKE_key_from_object(ob); float (*deformedVerts)[3]; - if (kb && kb->totelem == numVerts) { - deformedVerts = (float(*)[3])do_ob_key(md->scene, ob); + if (key && key->block.first) { + int deformedVerts_tot; + deformedVerts = (float(*)[3])BKE_key_evaluate_object(md->scene, ob, &deformedVerts_tot); if (deformedVerts) { - memcpy(vertexCos, deformedVerts, sizeof(float) * 3 * numVerts); + if (numVerts == deformedVerts_tot) { + memcpy(vertexCos, deformedVerts, sizeof(float) * 3 * numVerts); + } MEM_freeN(deformedVerts); } } diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 75e54d77b15..038fb4913ec 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -185,6 +185,8 @@ static void copyData(ModifierData *md, ModifierData *target) tsmd->crease_outer = smd->crease_outer; tsmd->crease_rim = smd->crease_rim; tsmd->flag = smd->flag; + tsmd->mat_ofs = smd->mat_ofs; + tsmd->mat_ofs_rim = smd->mat_ofs_rim; BLI_strncpy(tsmd->defgrp_name, smd->defgrp_name, sizeof(tsmd->defgrp_name)); } diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 5883b176317..f025352795b 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -361,7 +361,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der /* Mix weights. */ for (i = 0; i < numIdx; i++) { - float weight2 = 0.0; + float weight2; org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a; weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b; diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index e936e571a5b..71d6d4880ad 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -107,9 +107,9 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], /*nearest_v.dist = nearest_e.dist = nearest_f.dist = FLT_MAX;*/ /* Find the nearest vert/edge/face. */ #ifndef __APPLE__ -#pragma omp parallel for default(none) private(i) firstprivate(nearest_v,nearest_e,nearest_f) \ - shared(treeData_v,treeData_e,treeData_f,numVerts,v_cos,dist_v,dist_e, \ - dist_f,loc2trgt) \ +#pragma omp parallel for default(none) private(i) firstprivate(nearest_v, nearest_e, nearest_f) \ + shared(treeData_v, treeData_e, treeData_f, numVerts, v_cos, dist_v, dist_e, \ + dist_f, loc2trgt) \ schedule(static) #endif for (i = 0; i < numVerts; i++) { diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 141a3680df2..a7b491cf42b 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -168,6 +168,7 @@ set(SRC shader/nodes/node_shader_mix_shader.c shader/nodes/node_shader_normal_map.c shader/nodes/node_shader_object_info.c + shader/nodes/node_shader_hair_info.c shader/nodes/node_shader_output_lamp.c shader/nodes/node_shader_output_material.c shader/nodes/node_shader_output_world.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 74135776c9c..0a7a11e4506 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -78,6 +78,7 @@ void register_node_type_sh_fresnel(struct bNodeTreeType *ttype); void register_node_type_sh_layer_weight(struct bNodeTreeType *ttype); void register_node_type_sh_tex_coord(struct bNodeTreeType *ttype); void register_node_type_sh_particle_info(struct bNodeTreeType *ttype); +void register_node_type_sh_hair_info(struct bNodeTreeType *ttype); void register_node_type_sh_script(struct bNodeTreeType *ttype); void register_node_type_sh_normal_map(struct bNodeTreeType *ttype); void register_node_type_sh_tangent(struct bNodeTreeType *ttype); diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c index 57eb99021f6..c4b48b83b16 100644 --- a/source/blender/nodes/composite/node_composite_util.c +++ b/source/blender/nodes/composite/node_composite_util.c @@ -615,7 +615,7 @@ void generate_preview(void *data, bNode *node, CompBuf *stackbuf) bNodePreview *preview= node->preview; int xsize, ysize; int profile_from= (rd->color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; - int predivide= (rd->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); + int predivide= TRUE; int dither= 0; unsigned char *rect; diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index 88d78df190f..7e44210928c 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -291,7 +291,6 @@ static void cmp_node_image_update(bNodeTree *ntree, bNode *node) float *node_composit_get_float_buffer(RenderData *rd, ImBuf *ibuf, int *alloc) { float *rect; - int predivide= (ibuf->flags & IB_cm_predivide); *alloc= FALSE; @@ -305,7 +304,7 @@ float *node_composit_get_float_buffer(RenderData *rd, ImBuf *ibuf, int *alloc) rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image"); IMB_buffer_float_from_float(rect, ibuf->rect_float, - 4, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, predivide, + 4, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); *alloc= TRUE; diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c index 214617c91e5..fe23f7373fb 100644 --- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c +++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c @@ -269,7 +269,7 @@ static void exec_output_file_singlelayer(RenderData *rd, bNode *node, bNodeStack /* get full path */ BLI_join_dirfile(path, FILE_MAX, nimf->base_path, sockdata->path); - BKE_makepicstring(filename, path, bmain->name, rd->cfra, format->imtype, (rd->scemode & R_EXTENSION), TRUE); + BKE_makepicstring(filename, path, bmain->name, rd->cfra, format, (rd->scemode & R_EXTENSION), TRUE); if (0 == BKE_imbuf_write(ibuf, filename, format)) printf("Cannot save Node File Output to %s\n", filename); @@ -304,7 +304,7 @@ static void exec_output_file_multilayer(RenderData *rd, bNode *node, bNodeStack int recty = -1; int has_preview = 0; - BKE_makepicstring(filename, nimf->base_path, bmain->name, rd->cfra, R_IMF_IMTYPE_MULTILAYER, (rd->scemode & R_EXTENSION), TRUE); + BKE_makepicstring_from_type(filename, nimf->base_path, bmain->name, rd->cfra, R_IMF_IMTYPE_MULTILAYER, (rd->scemode & R_EXTENSION), TRUE); BLI_make_existing_file(filename); for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) { diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index 86ef8a14c12..dc8d427c0ae 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -305,7 +305,7 @@ void node_group_verify(struct bNodeTree *ntree, struct bNode *node, struct ID *i { /* check inputs and outputs, and remove or insert them */ if (node->id==id) { - bNodeTree *ngroup= (bNodeTree*)node->id; + bNodeTree *ngroup= (bNodeTree *)node->id; group_verify_socket_list(ntree, node, &node->inputs, SOCK_IN, &ngroup->inputs); group_verify_socket_list(ntree, node, &node->outputs, SOCK_OUT, &ngroup->outputs); } @@ -314,7 +314,7 @@ void node_group_verify(struct bNodeTree *ntree, struct bNode *node, struct ID *i struct bNodeTree *node_group_edit_get(bNode *node) { if (node->flag & NODE_GROUP_EDIT) - return (bNodeTree*)node->id; + return (bNodeTree *)node->id; else return NULL; } @@ -322,7 +322,7 @@ struct bNodeTree *node_group_edit_get(bNode *node) struct bNodeTree *node_group_edit_set(bNode *node, int edit) { if (edit) { - bNodeTree *ngroup= (bNodeTree*)node->id; + bNodeTree *ngroup= (bNodeTree *)node->id; if (ngroup) { if (ngroup->id.lib) ntreeMakeLocal(ngroup); @@ -339,7 +339,7 @@ struct bNodeTree *node_group_edit_set(bNode *node, int edit) void node_group_edit_clear(bNode *node) { - bNodeTree *ngroup= (bNodeTree*)node->id; + bNodeTree *ngroup= (bNodeTree *)node->id; bNode *inode; node->flag &= ~NODE_GROUP_EDIT; diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c index 3cc7ebf9337..86f8f4dfbbf 100644 --- a/source/blender/nodes/intern/node_exec.c +++ b/source/blender/nodes/intern/node_exec.c @@ -114,13 +114,13 @@ static struct bNodeStack *setup_stack(bNodeStack *stack, bNodeSocket *sock) if (sock->default_value) { switch (sock->type) { case SOCK_FLOAT: - ns->vec[0] = ((bNodeSocketValueFloat*)sock->default_value)->value; + ns->vec[0] = ((bNodeSocketValueFloat *)sock->default_value)->value; break; case SOCK_VECTOR: - copy_v3_v3(ns->vec, ((bNodeSocketValueVector*)sock->default_value)->value); + copy_v3_v3(ns->vec, ((bNodeSocketValueVector *)sock->default_value)->value); break; case SOCK_RGBA: - copy_v4_v4(ns->vec, ((bNodeSocketValueRGBA*)sock->default_value)->value); + copy_v4_v4(ns->vec, ((bNodeSocketValueRGBA *)sock->default_value)->value); break; } } diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index 6130fe72af3..544ccb8fda6 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -139,49 +139,49 @@ void nodeShaderSynchronizeID(bNode *node, int copyto) if (copyto) { switch (a) { case MAT_IN_COLOR: - copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA*)sock->default_value)->value); break; + copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA *)sock->default_value)->value); break; case MAT_IN_SPEC: - copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA*)sock->default_value)->value); break; + copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break; case MAT_IN_REFL: - ma->ref= ((bNodeSocketValueFloat*)sock->default_value)->value; break; + ma->ref= ((bNodeSocketValueFloat *)sock->default_value)->value; break; case MAT_IN_MIR: - copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA*)sock->default_value)->value); break; + copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break; case MAT_IN_AMB: - ma->amb= ((bNodeSocketValueFloat*)sock->default_value)->value; break; + ma->amb = ((bNodeSocketValueFloat *)sock->default_value)->value; break; case MAT_IN_EMIT: - ma->emit= ((bNodeSocketValueFloat*)sock->default_value)->value; break; + ma->emit = ((bNodeSocketValueFloat *)sock->default_value)->value; break; case MAT_IN_SPECTRA: - ma->spectra= ((bNodeSocketValueFloat*)sock->default_value)->value; break; + ma->spectra = ((bNodeSocketValueFloat *)sock->default_value)->value; break; case MAT_IN_RAY_MIRROR: - ma->ray_mirror= ((bNodeSocketValueFloat*)sock->default_value)->value; break; + ma->ray_mirror = ((bNodeSocketValueFloat *)sock->default_value)->value; break; case MAT_IN_ALPHA: - ma->alpha= ((bNodeSocketValueFloat*)sock->default_value)->value; break; + ma->alpha = ((bNodeSocketValueFloat *)sock->default_value)->value; break; case MAT_IN_TRANSLUCENCY: - ma->translucency= ((bNodeSocketValueFloat*)sock->default_value)->value; break; + ma->translucency = ((bNodeSocketValueFloat *)sock->default_value)->value; break; } } else { switch (a) { case MAT_IN_COLOR: - copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->r); break; + copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->r); break; case MAT_IN_SPEC: - copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->specr); break; + copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->specr); break; case MAT_IN_REFL: - ((bNodeSocketValueFloat*)sock->default_value)->value= ma->ref; break; + ((bNodeSocketValueFloat *)sock->default_value)->value= ma->ref; break; case MAT_IN_MIR: - copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->mirr); break; + copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->mirr); break; case MAT_IN_AMB: - ((bNodeSocketValueFloat*)sock->default_value)->value= ma->amb; break; + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->amb; break; case MAT_IN_EMIT: - ((bNodeSocketValueFloat*)sock->default_value)->value= ma->emit; break; + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->emit; break; case MAT_IN_SPECTRA: - ((bNodeSocketValueFloat*)sock->default_value)->value= ma->spectra; break; + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->spectra; break; case MAT_IN_RAY_MIRROR: - ((bNodeSocketValueFloat*)sock->default_value)->value= ma->ray_mirror; break; + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ray_mirror; break; case MAT_IN_ALPHA: - ((bNodeSocketValueFloat*)sock->default_value)->value= ma->alpha; break; + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->alpha; break; case MAT_IN_TRANSLUCENCY: - ((bNodeSocketValueFloat*)sock->default_value)->value= ma->translucency; break; + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->translucency; break; } } } @@ -259,7 +259,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree) break; if (node) - ntree= (bNodeTree*)node->id; + ntree = (bNodeTree *)node->id; for (node= ntree->nodes.first; node; node= node->next) if (node->flag & NODE_ACTIVE_TEXTURE) @@ -320,7 +320,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in float domax= (texmap->flag & TEXMAP_CLIP_MAX) != 0; if (domin || domax || !(texmap->flag & TEXMAP_UNIT_MATRIX)) { - GPUNodeLink *tmat = GPU_uniform((float*)texmap->mat); + GPUNodeLink *tmat = GPU_uniform((float *)texmap->mat); GPUNodeLink *tmin = GPU_uniform(texmap->min); GPUNodeLink *tmax = GPU_uniform(texmap->max); GPUNodeLink *tdomin = GPU_uniform(&domin); diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c index 688d77d8350..cf6f778bbf5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_common.c +++ b/source/blender/nodes/shader/nodes/node_shader_common.c @@ -70,7 +70,7 @@ static void move_stack(bNodeStack *to, bNodeStack *from) static void *group_initexec(bNode *node) { - bNodeTree *ngroup= (bNodeTree*)node->id; + bNodeTree *ngroup = (bNodeTree *)node->id; bNodeTreeExec *exec; if (!ngroup) @@ -84,7 +84,7 @@ static void *group_initexec(bNode *node) static void group_freeexec(bNode *UNUSED(node), void *nodedata) { - bNodeTreeExec*gexec= (bNodeTreeExec*)nodedata; + bNodeTreeExec*gexec = (bNodeTreeExec *)nodedata; ntreeShaderEndExecTree(gexec, 0); } @@ -121,7 +121,7 @@ static void group_move_outputs(bNode *node, bNodeStack **out, bNodeStack *gstack static void group_execute(void *data, int thread, struct bNode *node, void *nodedata, struct bNodeStack **in, struct bNodeStack **out) { - bNodeTreeExec *exec= (bNodeTreeExec*)nodedata; + bNodeTreeExec *exec = (bNodeTreeExec *)nodedata; bNodeThreadStack *nts; if (!exec) @@ -177,7 +177,7 @@ static void group_gpu_move_outputs(bNode *node, GPUNodeStack *out, bNodeStack *g static int gpu_group_execute(GPUMaterial *mat, bNode *node, void *nodedata, GPUNodeStack *in, GPUNodeStack *out) { - bNodeTreeExec *exec= (bNodeTreeExec*)nodedata; + bNodeTreeExec *exec = (bNodeTreeExec *)nodedata; group_gpu_copy_inputs(node, in, exec->stack); ntreeExecGPUNodes(exec, mat, (node->flag & NODE_GROUP_EDIT)); diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.c b/source/blender/nodes/shader/nodes/node_shader_hair_info.c new file mode 100644 index 00000000000..5cd4c8bd1d3 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.c @@ -0,0 +1,53 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../node_shader_util.h" + +static bNodeSocketTemplate outputs[] = { + { SOCK_FLOAT, 0, N_("Is Strand"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 0, N_("Intercept"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 0, N_("Thickness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 0, N_("Tangent Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* node type definition */ +void register_node_type_sh_hair_info(bNodeTreeType *ttype) +{ + static bNodeType ntype; + + node_type_base(ttype, &ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, NULL, outputs); + node_type_size(&ntype, 150, 60, 200); + node_type_init(&ntype, NULL); + node_type_storage(&ntype, "", NULL, NULL); + node_type_exec(&ntype, NULL); + node_type_gpu(&ntype, NULL); + + nodeRegisterType(ttype, &ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c index cedd3a4910c..396c1ac60bf 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mapping.c +++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c @@ -77,7 +77,7 @@ static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in, G TexMapping *texmap= node->storage; float domin= (texmap->flag & TEXMAP_CLIP_MIN) != 0; float domax= (texmap->flag & TEXMAP_CLIP_MAX) != 0; - GPUNodeLink *tmat = GPU_uniform((float*)texmap->mat); + GPUNodeLink *tmat = GPU_uniform((float *)texmap->mat); GPUNodeLink *tmin = GPU_uniform(texmap->min); GPUNodeLink *tmax = GPU_uniform(texmap->max); GPUNodeLink *tdomin = GPU_uniform(&domin); diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript index 15403d7acf4..4fb6d771c5b 100644 --- a/source/blender/python/SConscript +++ b/source/blender/python/SConscript @@ -134,6 +134,12 @@ if env['WITH_BF_TIFF']: if env['WITH_BF_INTERNATIONAL']: defs.append('WITH_INTERNATIONAL') +if env['WITH_BF_OPENAL']: + defs.append('WITH_OPENAL') + +if env['WITH_BF_SDL']: + defs.append('WITH_SDL') + if env['WITH_BF_JACK']: defs.append('WITH_JACK') @@ -155,12 +161,12 @@ if env['WITH_BF_REMESH']: if env['WITH_BF_SMOKE']: defs.append('WITH_SMOKE') -if env['WITH_BF_OPENAL']: - defs.append('WITH_OPENAL') - if env['WITH_BF_COLLADA']: defs.append('WITH_COLLADA') +if env['WITH_BF_OIIO']: + defs.append('WITH_OCIO') + if env['WITH_BF_PLAYER']: defs.append('WITH_PLAYER') diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c index 9abb13731af..ce8153fb994 100644 --- a/source/blender/python/bmesh/bmesh_py_api.c +++ b/source/blender/python/bmesh/bmesh_py_api.c @@ -110,14 +110,17 @@ PyDoc_STRVAR(bpy_bm_update_edit_mesh_doc, " :arg destructive: Use when grometry has been added or removed.\n" " :type destructive: boolean\n" ); -static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args) +static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"mesh", "tessface", "destructive", NULL}; PyObject *py_me; Mesh *me; int do_tessface = TRUE; int is_destructive = TRUE; - if (!PyArg_ParseTuple(args, "O|ii:update_edit_mesh", &py_me, &do_tessface, &is_destructive)) { + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|ii:update_edit_mesh", (char **)kwlist, + &py_me, &do_tessface, &is_destructive)) + { return NULL; } @@ -144,7 +147,7 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args) static struct PyMethodDef BPy_BM_methods[] = { {"new", (PyCFunction)bpy_bm_new, METH_NOARGS, bpy_bm_new_doc}, {"from_edit_mesh", (PyCFunction)bpy_bm_from_edit_mesh, METH_O, bpy_bm_from_edit_mesh_doc}, - {"update_edit_mesh", (PyCFunction)bpy_bm_update_edit_mesh, METH_VARARGS, bpy_bm_update_edit_mesh_doc}, + {"update_edit_mesh", (PyCFunction)bpy_bm_update_edit_mesh, METH_VARARGS | METH_KEYWORDS, bpy_bm_update_edit_mesh_doc}, {NULL, NULL, 0, NULL} }; diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 53112d46098..10ca7a943cb 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -836,6 +836,11 @@ static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self) return BPy_IDGroup_MapDataToPy(self->prop); } +static PyObject *BPy_IDGroup_clear(BPy_IDProperty *self) +{ + IDP_ClearProperty(self->prop); + Py_RETURN_NONE; +} /* Matches python dict.get(key, [default]) */ static PyObject *BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args) @@ -875,6 +880,8 @@ static struct PyMethodDef BPy_IDGroup_methods[] = { "idprop.get(k[,d]) -> idprop[k] if k in idprop, else d. d defaults to None"}, {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS, "return a purely python version of the group"}, + {"clear", (PyCFunction)BPy_IDGroup_clear, METH_NOARGS, + "clear all members from this group"}, {NULL, NULL, 0, NULL} }; diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index f62fdaf09db..9a064923736 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -241,6 +241,23 @@ PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...) return item; } +PyObject *PyC_FrozenSetFromStrings(const char **strings) +{ + const char **str; + PyObject *ret; + + ret = PyFrozenSet_New(NULL); + + for (str = strings; *str; str++) { + PyObject *py_str = PyUnicode_FromString(*str); + PySet_Add(ret, py_str); + Py_DECREF(py_str); + } + + return ret; +} + + /* similar to PyErr_Format(), * * implementation - we cant actually preprend the existing exception, diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 935a5f9030b..db582bd7086 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -33,6 +33,7 @@ void PyC_LineSpit(void); void PyC_StackSpit(void); PyObject * PyC_ExceptionBuffer(void); PyObject * PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...); +PyObject * PyC_FrozenSetFromStrings(const char **strings); PyObject * PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...); void PyC_FileAndNum(const char **filename, int *lineno); void PyC_FileAndNum_Safe(const char **filename, int *lineno); /* checks python is running */ @@ -53,7 +54,7 @@ void PyC_MainModule_Restore(PyObject *main_mod); void PyC_SetHomePath(const char *py_path_bundle); -#define PYC_INTERPRETER_ACTIVE (((PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)) != NULL) +#define PYC_INTERPRETER_ACTIVE (((PyThreadState *)_Py_atomic_load_relaxed(&_PyThreadState_Current)) != NULL) void *PyC_RNA_AsPointer(PyObject *value, const char *type_name); diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 8f90a823668..823c7c709d7 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -56,6 +56,7 @@ set(SRC bpy_library.c bpy_operator.c bpy_operator_wrap.c + bpy_path.c bpy_props.c bpy_rna.c bpy_rna_anim.c @@ -76,6 +77,7 @@ set(SRC bpy_library.h bpy_operator.h bpy_operator_wrap.h + bpy_path.h bpy_props.h bpy_rna.h bpy_rna_anim.h @@ -190,12 +192,16 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() -if(WITH_JACK) - add_definitions(-DWITH_JACK) +if(WITH_OPENAL) + add_definitions(-DWITH_OPENAL) endif() -if(WITH_LIBMV) - add_definitions(-DWITH_LIBMV) +if(WITH_SDL) + add_definitions(-DWITH_SDL) +endif() + +if(WITH_JACK) + add_definitions(-DWITH_JACK) endif() if(WITH_LIBMV) @@ -222,14 +228,14 @@ if(WITH_MOD_SMOKE) add_definitions(-DWITH_SMOKE) endif() -if(WITH_OPENAL) - add_definitions(-DWITH_OPENAL) -endif() - if(WITH_OPENCOLLADA) add_definitions(-DWITH_COLLADA) endif() +if(WITH_OPENCOLORIO) + add_definitions(-DWITH_OCIO) +endif() + if(WITH_PLAYER) add_definitions(-DWITH_PLAYER) endif() diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index 74df3ef7307..8815348c22d 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor(s): Bastien Montagne + * Contributor(s): Sergey Sharybin * * ***** END GPL LICENSE BLOCK ***** */ @@ -29,152 +29,282 @@ #include "bpy_app_build_options.h" -static PyObject *make_build_options(void) +static PyTypeObject BlenderAppBuildOptionsType; + +static PyStructSequence_Field app_builtopts_info_fields[] = { + /* names mostly follow CMake options, lowecases, after WITH_ */ + {(char *)"bullet", NULL}, + {(char *)"codec_avi", NULL}, + {(char *)"codec_ffmpeg", NULL}, + {(char *)"codec_quicktime", NULL}, + {(char *)"codec_sndfile", NULL}, + {(char *)"compositor", NULL}, + {(char *)"cycles", NULL}, + {(char *)"cycles_osl", NULL}, + {(char *)"freestyle", NULL}, + {(char *)"gameengine", NULL}, + {(char *)"image_cineon", NULL}, + {(char *)"image_dds", NULL}, + {(char *)"image_frameserver", NULL}, + {(char *)"image_hdr", NULL}, + {(char *)"image_openexr", NULL}, + {(char *)"image_openjpeg", NULL}, + {(char *)"image_redcode", NULL}, + {(char *)"image_tiff", NULL}, + {(char *)"input_ndof", NULL}, + {(char *)"audaspace", NULL}, + {(char *)"international", NULL}, + {(char *)"openal", NULL}, + {(char *)"sdl", NULL}, + {(char *)"jack", NULL}, + {(char *)"libmv", NULL}, + {(char *)"mod_boolean", NULL}, + {(char *)"mod_fluid", NULL}, + {(char *)"mod_oceansim", NULL}, + {(char *)"mod_remesh", NULL}, + {(char *)"mod_smoke", NULL}, + {(char *)"collada", NULL}, + {(char *)"opencolorio", NULL}, + {(char *)"player", NULL}, + {NULL} +}; + + +static PyStructSequence_Desc app_builtopts_info_desc = { + (char *)"bpy.app.build_options", /* name */ + (char *)"This module contains information about FFmpeg blender is linked against", /* doc */ + app_builtopts_info_fields, /* fields */ + (sizeof(app_builtopts_info_fields) / sizeof(PyStructSequence_Field)) - 1 +}; + +static PyObject *make_builtopts_info(void) { - PyObject *build_options = PyFrozenSet_New(NULL); + PyObject *builtopts_info; + int pos = 0; -#define SetStrItem(str) \ - PySet_Add(build_options, PyUnicode_FromString(str)); + builtopts_info = PyStructSequence_New(&BlenderAppBuildOptionsType); + if (builtopts_info == NULL) { + return NULL; + } -#ifdef WITH_AUDASPACE - SetStrItem("AUDASPACE"); -#endif +#define SetObjIncref(item) \ + PyStructSequence_SET_ITEM(builtopts_info, pos++, (Py_IncRef(item), item)) #ifdef WITH_BULLET - SetStrItem("BULLET"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_AVI - SetStrItem("CODEC_AVI"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_FFMPEG - SetStrItem("CODEC_FFMPEG"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_QUICKTIME - SetStrItem("CODEC_QUICKTIME"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_SNDFILE - SetStrItem("CODEC_SNDFILE"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_COMPOSITOR - SetStrItem("COMPOSITOR"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_CYCLES - SetStrItem("CYCLES"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_CYCLES_OSL - SetStrItem("CYCLES_OSL"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_FREESTYLE - SetStrItem("FREESTYLE"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_GAMEENGINE - SetStrItem("GAMEENGINE"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_CINEON - SetStrItem("IMAGE_CINEON"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_DDS - SetStrItem("IMAGE_DDS"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_FRAMESERVER - SetStrItem("IMAGE_FRAMESERVER"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_HDR - SetStrItem("IMAGE_HDR"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_OPENEXR - SetStrItem("IMAGE_OPENEXR"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_OPENJPEG - SetStrItem("IMAGE_OPENJPEG"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_REDCODE - SetStrItem("IMAGE_REDCODE"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_TIFF - SetStrItem("IMAGE_TIFF"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_INPUT_NDOF - SetStrItem("INPUT_NDOF"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + +#ifdef WITH_AUDASPACE + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_INTERNATIONAL - SetStrItem("INTERNATIONAL"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + +#ifdef WITH_OPENAL + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + +#ifdef WITH_SDL + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_JACK - SetStrItem("JACK"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_LIBMV - SetStrItem("LIBMV"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_MOD_BOOLEAN - SetStrItem("MOD_BOOLEAN"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_MOD_FLUID - SetStrItem("MOD_FLUID"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_OCEANSIM - SetStrItem("MOD_OCEANSIM"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_MOD_REMESH - SetStrItem("MOD_REMESH"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_SMOKE - SetStrItem("MOD_SMOKE"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif -#ifdef WITH_OPENAL - SetStrItem("OPENAL"); +#ifdef WITH_COLLADA + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif -#ifdef WITH_COLLADA - SetStrItem("COLLADA"); +#ifdef WITH_OCIO + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif #ifdef WITH_PLAYER - SetStrItem("PLAYER"); + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); #endif -#undef SetStrItem +#undef SetObjIncref - if (PyErr_Occurred()) { - Py_CLEAR(build_options); - return NULL; - } - - return build_options; + return builtopts_info; } PyObject *BPY_app_build_options_struct(void) { PyObject *ret; - ret = make_build_options(); + PyStructSequence_InitType(&BlenderAppBuildOptionsType, &app_builtopts_info_desc); + + ret = make_builtopts_info(); + + /* prevent user from creating new instances */ + BlenderAppBuildOptionsType.tp_init = NULL; + BlenderAppBuildOptionsType.tp_new = NULL; + BlenderAppBuildOptionsType.tp_hash = (hashfunc)_Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */ return ret; } diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index cdecf64c93c..7bce8673943 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -44,6 +44,7 @@ #include "bpy.h" #include "gpu.h" #include "bpy_rna.h" +#include "bpy_path.h" #include "bpy_util.h" #include "bpy_traceback.h" #include "bpy_intern_string.h" @@ -212,6 +213,7 @@ static struct _inittab bpy_internal_modules[] = { {(char *)"mathutils", PyInit_mathutils}, // {(char *)"mathutils.geometry", PyInit_mathutils_geometry}, // {(char *)"mathutils.noise", PyInit_mathutils_noise}, + {(char *)"_bpy_path", BPyInit__bpy_path}, {(char *)"bgl", BPyInit_bgl}, {(char *)"blf", BPyInit_blf}, {(char *)"bmesh", BPyInit_bmesh}, @@ -269,7 +271,8 @@ void BPY_python_start(int argc, const char **argv) Py_Initialize(); /* THIS IS BAD: see http://bugs.python.org/issue16129 */ -#if 1 + /* this clobbers the stdout on exit (no 'MEM_printmemlist_stats') */ +#if 0 /* until python provides a reliable way to set the env var */ PyRun_SimpleString("import sys, io\n" "sys.__backup_stdio__ = sys.__stdout__, sys.__stderr__\n" /* else we loose the FD's [#32720] */ @@ -817,7 +820,7 @@ typedef struct { } dealloc_obj; /* call once __file__ is set */ -void bpy_module_delay_init(PyObject *bpy_proxy) +static void bpy_module_delay_init(PyObject *bpy_proxy) { const int argc = 1; const char *argv[2]; @@ -856,6 +859,9 @@ static void dealloc_obj_dealloc(PyObject *self) } PyMODINIT_FUNC +PyInit_bpy(void); + +PyMODINIT_FUNC PyInit_bpy(void) { PyObject *bpy_proxy = PyModule_Create(&bpy_proxy_def); diff --git a/source/blender/python/intern/bpy_path.c b/source/blender/python/intern/bpy_path.c new file mode 100644 index 00000000000..8df7ed2364f --- /dev/null +++ b/source/blender/python/intern/bpy_path.c @@ -0,0 +1,65 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_path.c + * \ingroup pythonintern + * + * This file defines '_bpy_path' module, Some 'C' funtionality used by 'bpy.path' + */ + +#include <Python.h> + +#include "bpy_path.h" + +#include "../generic/py_capi_utils.h" + +/* #include "IMB_imbuf_types.h" */ +extern const char *imb_ext_image[]; +extern const char *imb_ext_movie[]; +extern const char *imb_ext_audio[]; + +/*----------------------------MODULE INIT-------------------------*/ +static struct PyModuleDef _bpy_path_module_def = { + PyModuleDef_HEAD_INIT, + "_bpy_path", /* m_name */ + NULL, /* m_doc */ + 0, /* m_size */ + NULL, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +PyObject *BPyInit__bpy_path(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&_bpy_path_module_def); + + PyModule_AddObject(submodule, "extensions_image", PyC_FrozenSetFromStrings(imb_ext_image)); + PyModule_AddObject(submodule, "extensions_movie", PyC_FrozenSetFromStrings(imb_ext_movie)); + PyModule_AddObject(submodule, "extensions_audio", PyC_FrozenSetFromStrings(imb_ext_audio)); + + return submodule; +} + diff --git a/source/blender/python/intern/bpy_path.h b/source/blender/python/intern/bpy_path.h new file mode 100644 index 00000000000..a0f31202264 --- /dev/null +++ b/source/blender/python/intern/bpy_path.h @@ -0,0 +1,33 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_path.h + * \ingroup pythonintern + */ + + +#ifndef __BPY_PATH_H__ +#define __BPY_PATH_H__ + +PyObject *BPyInit__bpy_path(void); + +#endif diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index bd033736865..57ddee0c8c0 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -1233,6 +1233,8 @@ BPY_PROPDEF_DESC_DOC " For dynamic values a callback can be passed which returns a list in\n" " the same format as the static list.\n" " This function must take 2 arguments (self, context)\n" +" WARNING: Do not use generators here (they will work the first time, but will lead to empty values\n" +" in some unload/reload scenarii)!\n" " :type items: sequence of string triplets or a function\n" BPY_PROPDEF_UPDATE_DOC ); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 2de477c46c3..bc245ecda5c 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -7373,8 +7373,9 @@ PyDoc_STRVAR(pyrna_register_class_doc, ".. method:: register_class(cls)\n" "\n" " Register a subclass of a blender type in (:class:`bpy.types.Panel`,\n" -" :class:`bpy.types.Menu`, :class:`bpy.types.Header`, :class:`bpy.types.Operator`,\n" -" :class:`bpy.types.KeyingSetInfo`, :class:`bpy.types.RenderEngine`).\n" +" :class:`bpy.types.UIList`, :class:`bpy.types.Menu`, :class:`bpy.types.Header`,\n" +" :class:`bpy.types.Operator`, :class:`bpy.types.KeyingSetInfo`,\n" +" :class:`bpy.types.RenderEngine`).\n" "\n" " If the class has a *register* class method it will be called\n" " before registration.\n" diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 69839514a12..0acfc36bb4e 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -44,6 +44,7 @@ #include "BKE_fcurve.h" #include "RNA_access.h" +#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" @@ -147,14 +148,17 @@ static int pyrna_struct_anim_args_parse( /* internal use for insert and delete */ static int pyrna_struct_keyframe_parse( PointerRNA *ptr, PyObject *args, PyObject *kw, const char *parse_str, const char *error_prefix, - const char **path_full, int *index, float *cfra, const char **group_name) /* return values */ + const char **path_full, int *index, float *cfra, const char **group_name, int *options) /* return values */ { - static const char *kwlist[] = {"data_path", "index", "frame", "group", NULL}; + static const char *kwlist[] = {"data_path", "index", "frame", "group", "options", NULL}; + PyObject *pyoptions = NULL; const char *path; - /* note, parse_str MUST start with 's|ifs' */ - if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name)) + /* note, parse_str MUST start with 's|ifsO!' */ + if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name, + &PySet_Type, &pyoptions)) { return -1; + } if (pyrna_struct_anim_args_parse(ptr, error_prefix, path, path_full, index) < 0) return -1; @@ -162,6 +166,10 @@ static int pyrna_struct_keyframe_parse( if (*cfra == FLT_MAX) *cfra = CTX_data_scene(BPy_GetContext())->r.cfra; + /* flag may be null (no option currently for remove keyframes e.g.). */ + if (pyoptions && options && (pyrna_set_to_enum_bitfield(keying_flag_items, pyoptions, options, error_prefix) < 0)) + return -1; + return 0; /* success */ } @@ -172,12 +180,19 @@ char pyrna_struct_keyframe_insert_doc[] = "\n" " :arg data_path: path to the property to key, analogous to the fcurve's data path.\n" " :type data_path: string\n" -" :arg index: array index of the property to key. Defaults to -1 which will key all indices or a single channel if the property is not an array.\n" +" :arg index: array index of the property to key. Defaults to -1 which will key all indices or a single channel " + "if the property is not an array.\n" " :type index: int\n" " :arg frame: The frame on which the keyframe is inserted, defaulting to the current frame.\n" " :type frame: float\n" " :arg group: The name of the group the F-Curve should be added to if it doesn't exist yet.\n" " :type group: str\n" +" :arg options: Some optional flags:\n" +" 'NEEDED': Only insert keyframes where they're needed in the relevant F-Curves.\n" +" 'VISUAL': Insert keyframes based on 'visual transforms'.\n" +" 'XYZ_TO_RGB': Color for newly added transformation F-Curves (Location, Rotation, Scale) " + "and also Color is based on the transform axis.\n" +" :type flag: set\n" " :return: Success of keyframe insertion.\n" " :rtype: boolean\n" ; @@ -188,12 +203,13 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb int index = -1; float cfra = FLT_MAX; const char *group_name = NULL; + int options = 0; PYRNA_STRUCT_CHECK_OBJ(self); if (pyrna_struct_keyframe_parse(&self->ptr, args, kw, - "s|ifs:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()", - &path_full, &index, &cfra, &group_name) == -1) + "s|ifsO!:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()", + &path_full, &index, &cfra, &group_name, &options) == -1) { return NULL; } @@ -203,7 +219,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb BKE_reports_init(&reports, RPT_STORE); - result = insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0); + result = insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, options); MEM_freeN((void *)path_full); if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1) @@ -240,9 +256,9 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb PYRNA_STRUCT_CHECK_OBJ(self); if (pyrna_struct_keyframe_parse(&self->ptr, args, kw, - "s|ifs:bpy_struct.keyframe_delete()", + "s|ifsO!:bpy_struct.keyframe_delete()", "bpy_struct.keyframe_insert()", - &path_full, &index, &cfra, &group_name) == -1) + &path_full, &index, &cfra, &group_name, NULL) == -1) { return NULL; } diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index d2ffc3a0e26..64135a16f5d 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -61,6 +61,7 @@ struct Scene; #define RE_ENGINE_DO_DRAW 4 #define RE_ENGINE_DO_UPDATE 8 #define RE_ENGINE_RENDERING 16 +#define RE_ENGINE_HIGHLIGHT_TILES 32 extern ListBase R_engines; @@ -130,5 +131,7 @@ void RE_engines_exit(void); RenderEngineType *RE_engines_find(const char *idname); +void RE_engine_get_current_tiles(struct Render *re, int *total_tiles_r, rcti **tiles_r); + #endif /* __RE_ENGINE_H__ */ diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h index 5d61417cbaf..61b39a59b0b 100644 --- a/source/blender/render/intern/include/render_result.h +++ b/source/blender/render/intern/include/render_result.h @@ -91,7 +91,7 @@ void render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd struct ImBuf *ibuf); void render_result_rect_fill_zero(struct RenderResult *rr); -void render_result_rect_get_pixels(struct RenderResult *rr, struct RenderData *rd, +void render_result_rect_get_pixels(struct RenderResult *rr, unsigned int *rect, int rectx, int recty, const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings); diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index c45c6dfc1bc..3b8cd3c6aa5 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -104,13 +104,19 @@ typedef struct RenderPart { rcti disprect; /* part coordinates within total picture */ int rectx, recty; /* the size */ - short crop, ready; /* crop is amount of pixels we crop, for filter */ + short crop, status; /* crop is amount of pixels we crop, for filter */ short sample, nr; /* sample can be used by zbuffers, nr is partnr */ short thread; /* thread id */ char *clipflag; /* clipflags for part zbuffering */ } RenderPart; +enum { + PART_STATUS_NONE = 0, + PART_STATUS_IN_PROGRESS = 1, + PART_STATUS_READY = 2 +}; + /* controls state of render, everything that's read-only during render stage */ struct Render { diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h index 24989b13c48..1e81ca20d03 100644 --- a/source/blender/render/intern/include/renderdatabase.h +++ b/source/blender/render/intern/include/renderdatabase.h @@ -59,12 +59,16 @@ typedef struct VertTableNode { float *tangent; float *stress; float *winspeed; + /* Index of vertex in source mesh (before modifiers). */ + int *origindex; } VertTableNode; typedef struct VlakTableNode { struct VlakRen *vlak; struct MTFace *mtface; struct MCol *mcol; + /* Index of mpoly in source mesh (before tessellation). */ + int *origindex; int totmtface, totmcol; float *surfnor; float *tangent; @@ -114,9 +118,11 @@ float *RE_vertren_get_rad(struct ObjectRen *obr, struct VertRen *ver, int verify float *RE_vertren_get_strand(struct ObjectRen *obr, struct VertRen *ver, int verify); float *RE_vertren_get_tangent(struct ObjectRen *obr, struct VertRen *ver, int verify); float *RE_vertren_get_winspeed(struct ObjectInstanceRen *obi, struct VertRen *ver, int verify); +int *RE_vertren_get_origindex(struct ObjectRen *obr, VertRen *ver, int verify); struct MTFace *RE_vlakren_get_tface(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify); struct MCol *RE_vlakren_get_mcol(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify); +int *RE_vlakren_get_origindex(struct ObjectRen *obr, VlakRen *vlak, int verify); float *RE_vlakren_get_surfnor(struct ObjectRen *obr, VlakRen *ren, int verify); float *RE_vlakren_get_nmap_tangent(struct ObjectRen *obr, VlakRen *ren, int verify); RadFace **RE_vlakren_get_radface(struct ObjectRen *obr, VlakRen *ren, int verify); diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp index f9ed012b117..01e592cba0c 100644 --- a/source/blender/render/intern/raytrace/rayobject_instance.cpp +++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp @@ -173,13 +173,13 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec) static void RE_rayobject_instance_free(RayObject *o) { - InstanceRayObject *obj = (InstanceRayObject*)o; + InstanceRayObject *obj = (InstanceRayObject *)o; MEM_freeN(obj); } static float RE_rayobject_instance_cost(RayObject *o) { - InstanceRayObject *obj = (InstanceRayObject*)o; + InstanceRayObject *obj = (InstanceRayObject *)o; return RE_rayobject_cost(obj->target) + RE_COST_INSTANCE; } diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index cfa6bb0b11d..74aab678ea8 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -164,7 +164,7 @@ static HaloRen *initstar(Render *re, ObjectRen *obr, const float vec[3], float h */ void RE_make_stars(Render *re, Scene *scenev3d, void (*initfunc)(void), - void (*vertexfunc)(float*), void (*termfunc)(void)) + void (*vertexfunc)(float *), void (*termfunc)(void)) { extern unsigned char hash[512]; ObjectRen *obr= NULL; @@ -3258,7 +3258,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) CustomDataMask mask; float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3], float *orco=0; - int need_orco=0, need_stress=0, need_nmap_tangent=0, need_tangent=0; + int need_orco=0, need_stress=0, need_nmap_tangent=0, need_tangent=0, need_origindex=0; int a, a1, ok, vertofs; int end, do_autosmooth = FALSE, totvert = 0; int use_original_normals = FALSE; @@ -3308,6 +3308,10 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) need_nmap_tangent= 1; } + /* origindex currently only used when baking to vertex colors */ + if(re->flag & R_BAKING && re->r.bake_flag & R_BAKE_VCOL) + need_origindex= 1; + /* check autosmooth and displacement, we then have to skip only-verts optimize */ do_autosmooth |= (me->flag & ME_AUTOSMOOTH); if (do_autosmooth) @@ -3345,6 +3349,15 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) make_render_halos(re, obr, me, totvert, mvert, ma, orco); } else { + const int *index_vert_orig = NULL; + const int *index_mf_to_mpoly = NULL; + const int *index_mp_to_orig = NULL; + if (need_origindex) { + index_vert_orig = dm->getVertDataArray(dm, CD_ORIGINDEX); + /* double lookup for faces -> polys */ + index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); + } for (a=0; a<totvert; a++, mvert++) { ver= RE_findOrAddVert(obr, obr->totvert++); @@ -3361,6 +3374,18 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) ver->orco= orco; orco+=3; } + + if (need_origindex) { + int *origindex; + origindex = RE_vertren_get_origindex(obr, ver, 1); + + /* Use orig index array if it's available (e.g. in the presence + * of modifiers). */ + if (index_vert_orig) + *origindex = index_vert_orig[a]; + else + *origindex = a; + } } if (!timeoffset) { @@ -3514,6 +3539,21 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) } } } + + if (need_origindex) { + /* Find original index of mpoly for this tessface. Options: + - Modified mesh; two-step look up from tessface -> modified mpoly -> original mpoly + - OR Tesselated mesh; look up from tessface -> mpoly + - OR Failsafe; tessface == mpoly. Could probably assert(false) in this case? */ + int *origindex; + origindex = RE_vlakren_get_origindex(obr, vlr, 1); + if (index_mf_to_mpoly && index_mp_to_orig) + *origindex = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a); + else if (index_mf_to_mpoly) + *origindex = index_mf_to_mpoly[a]; + else + *origindex = a; + } } } } diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 6fdf11ba48c..296c8b6eba8 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -150,6 +150,23 @@ void RE_engine_free(RenderEngine *engine) /* Render Results */ +static RenderPart *get_part_from_result(Render *re, RenderResult *result) +{ + RenderPart *pa; + + for (pa = re->parts.first; pa; pa = pa->next) { + if (result->tilerect.xmin == pa->disprect.xmin - re->disprect.xmin && + result->tilerect.ymin == pa->disprect.ymin - re->disprect.ymin && + result->tilerect.xmax == pa->disprect.xmax - re->disprect.xmin && + result->tilerect.ymax == pa->disprect.ymax - re->disprect.ymin) + { + return pa; + } + } + + return NULL; +} + RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername) { Render *re = engine->re; @@ -179,12 +196,19 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, /* can be NULL if we CLAMP the width or height to 0 */ if (result) { + RenderPart *pa; + BLI_addtail(&engine->fullresult, result); result->tilerect.xmin += re->disprect.xmin; result->tilerect.xmax += re->disprect.xmin; result->tilerect.ymin += re->disprect.ymin; result->tilerect.ymax += re->disprect.ymin; + + pa = get_part_from_result(re, result); + + if (pa) + pa->status = PART_STATUS_IN_PROGRESS; } return result; @@ -203,7 +227,6 @@ void RE_engine_update_result(RenderEngine *engine, RenderResult *result) void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel) { Render *re = engine->re; - RenderPart *pa; if (!result) { return; @@ -212,15 +235,10 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel /* merge. on break, don't merge in result for preview renders, looks nicer */ if (!cancel) { /* for exr tile render, detect tiles that are done */ - for (pa = re->parts.first; pa; pa = pa->next) { - if (result->tilerect.xmin == pa->disprect.xmin && - result->tilerect.ymin == pa->disprect.ymin && - result->tilerect.xmax == pa->disprect.xmax && - result->tilerect.ymax == pa->disprect.ymax) - { - pa->ready = 1; - } - } + RenderPart *pa = get_part_from_result(re, result); + + if (pa) + pa->status = PART_STATUS_READY; if (re->result->do_exr_tile) render_result_exr_file_merge(re->result, result); @@ -310,6 +328,47 @@ void RE_engine_report(RenderEngine *engine, int type, const char *msg) BKE_report(engine->reports, type, msg); } +void RE_engine_get_current_tiles(Render *re, int *total_tiles_r, rcti **tiles_r) +{ + RenderPart *pa; + int total_tiles = 0; + rcti *tiles = NULL; + int allocation_size = 0, allocation_step = BLENDER_MAX_THREADS; + + if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) { + *total_tiles_r = 0; + *tiles_r = NULL; + return; + } + + for (pa = re->parts.first; pa; pa = pa->next) { + if (pa->status == PART_STATUS_IN_PROGRESS) { + if (total_tiles >= allocation_size) { + if (tiles == NULL) + tiles = MEM_mallocN(allocation_step * sizeof(rcti), "current engine tiles"); + else + tiles = MEM_reallocN(tiles, (total_tiles + allocation_step) * sizeof(rcti)); + + allocation_size += allocation_step; + } + + tiles[total_tiles] = pa->disprect; + + if (pa->crop) { + tiles[total_tiles].xmin += pa->crop; + tiles[total_tiles].ymin += pa->crop; + tiles[total_tiles].xmax -= pa->crop; + tiles[total_tiles].ymax -= pa->crop; + } + + total_tiles++; + } + } + + *total_tiles_r = total_tiles; + *tiles_r = tiles; +} + /* Render */ int RE_engine_render(Render *re, int do_all) @@ -354,9 +413,7 @@ int RE_engine_render(Render *re, int do_all) if (!engine) { engine = RE_engine_create(type); - - if (persistent_data) - re->engine = engine; + re->engine = engine; } engine->flag |= RE_ENGINE_RENDERING; diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index 7c14e0e5465..4aaa6247478 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -102,6 +102,11 @@ static void ibuf_get_color(float col[4], struct ImBuf *ibuf, int x, int y) col[1] = ((float)rect[1])*(1.0f/255.0f); col[2] = ((float)rect[2])*(1.0f/255.0f); col[3] = ((float)rect[3])*(1.0f/255.0f); + + /* bytes are internally straight, however render pipeline seems to expect premul */ + col[0] *= col[3]; + col[1] *= col[3]; + col[2] *= col[3]; } } @@ -219,10 +224,8 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul } /* keep this before interpolation [#29761] */ - if (tex->imaflag & TEX_USEALPHA) { - if ((tex->imaflag & TEX_CALCALPHA) == 0) { - texres->talpha = TRUE; - } + if ((tex->imaflag & TEX_CALCALPHA) == 0) { + texres->talpha = TRUE; } /* interpolate */ @@ -710,9 +713,10 @@ static int ibuf_get_color_clip(float col[4], ImBuf *ibuf, int x, int y, int extf } else { char *rect = (char *)(ibuf->rect + x + y*ibuf->x); - col[0] = rect[0]*(1.f/255.f); - col[1] = rect[1]*(1.f/255.f); - col[2] = rect[2]*(1.f/255.f); + float inv_alpha_fac = (1.0f / 255.0f) * rect[3] * (1.0f / 255.0f); + col[0] = rect[0] * inv_alpha_fac; + col[1] = rect[1] * inv_alpha_fac; + col[2] = rect[2] * inv_alpha_fac; col[3] = clip ? 0.f : rect[3]*(1.f/255.f); } return clip; @@ -1088,7 +1092,8 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex /* mipmap test */ image_mipmap_test(tex, ibuf); - if ((tex->imaflag & TEX_USEALPHA) && ((tex->imaflag & TEX_CALCALPHA) == 0)) texres->talpha = 1; + if ((tex->imaflag & TEX_CALCALPHA) == 0) + texres->talpha = 1; texr.talpha = texres->talpha; if (tex->imaflag & TEX_IMAROT) { @@ -1501,13 +1506,8 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const /* mipmap test */ image_mipmap_test(tex, ibuf); - if (tex->imaflag & TEX_USEALPHA) { - if (tex->imaflag & TEX_CALCALPHA) { - /* pass */ - } - else { - texres->talpha = TRUE; - } + if ((tex->imaflag & TEX_CALCALPHA) == 0) { + texres->talpha = TRUE; } texr.talpha= texres->talpha; diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c index 9785edd3288..b8784685836 100644 --- a/source/blender/render/intern/source/multires_bake.c +++ b/source/blender/render/intern/source/multires_bake.c @@ -233,8 +233,8 @@ static void set_rast_triangle(const MBakeRast *bake_rast, const int x, const int if (x >= 0 && x < w && y >= 0 && y < h) { if ((bake_rast->texels[y * w + x]) == 0) { - flush_pixel(bake_rast->data, x, y); bake_rast->texels[y * w + x] = FILTER_MASK_USED; + flush_pixel(bake_rast->data, x, y); } } } diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index c7c5fcf354f..43bada3b383 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -341,7 +341,7 @@ void RE_ResultGet32(Render *re, unsigned int *rect) RenderResult rres; RE_AcquireResultImage(re, &rres); - render_result_rect_get_pixels(&rres, &re->r, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings); + render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings); RE_ReleaseResultImage(re); } @@ -660,7 +660,9 @@ static int render_display_draw_enabled(Render *re) static void *do_part_thread(void *pa_v) { RenderPart *pa = pa_v; - + + pa->status = PART_STATUS_IN_PROGRESS; + /* need to return nicely all parts on esc */ if (R.test_break(R.tbh) == 0) { @@ -691,7 +693,7 @@ static void *do_part_thread(void *pa_v) } } - pa->ready = 1; + pa->status = PART_STATUS_READY; return NULL; } @@ -732,7 +734,7 @@ static RenderPart *find_next_pano_slice(Render *re, int *minx, rctf *viewplane) /* most left part of the non-rendering parts */ for (pa = re->parts.first; pa; pa = pa->next) { - if (pa->ready == 0 && pa->nr == 0) { + if (pa->status == PART_STATUS_NONE && pa->nr == 0) { if (pa->disprect.xmin < *minx) { best = pa; *minx = pa->disprect.xmin; @@ -770,7 +772,7 @@ static RenderPart *find_next_part(Render *re, int minx) /* find center of rendered parts, image center counts for 1 too */ for (pa = re->parts.first; pa; pa = pa->next) { - if (pa->ready) { + if (pa->status == PART_STATUS_READY) { centx += BLI_rcti_cent_x(&pa->disprect); centy += BLI_rcti_cent_y(&pa->disprect); tot++; @@ -781,7 +783,7 @@ static RenderPart *find_next_part(Render *re, int minx) /* closest of the non-rendering parts */ for (pa = re->parts.first; pa; pa = pa->next) { - if (pa->ready == 0 && pa->nr == 0) { + if (pa->status == PART_STATUS_NONE && pa->nr == 0) { long long int distx = centx - BLI_rcti_cent_x(&pa->disprect); long long int disty = centy - BLI_rcti_cent_y(&pa->disprect); distx = (long long int)sqrt(distx * distx + disty * disty); @@ -838,7 +840,7 @@ static void threaded_tile_processor(Render *re) if (re->result == NULL) return; - + /* warning; no return here without closing exr file */ RE_parts_init(re, TRUE); @@ -889,7 +891,7 @@ static void threaded_tile_processor(Render *re) rendering = 0; hasdrawn = 0; for (pa = re->parts.first; pa; pa = pa->next) { - if (pa->ready) { + if (pa->status == PART_STATUS_READY) { BLI_remove_thread(&threads, pa); @@ -1108,7 +1110,7 @@ static void do_render_blur_3d(Render *re) blurfac = 1.0f / (float)(re->r.mblur_samples - blur); - merge_renderresult_blur(rres, re->result, blurfac, re->r.alphamode & R_ALPHAKEY); + merge_renderresult_blur(rres, re->result, blurfac, FALSE); if (re->test_break(re->tbh)) break; } @@ -1253,7 +1255,7 @@ static void do_render_fields_blur_3d(Render *re) Object *camera = RE_GetCamera(re); /* also check for camera here */ if (camera == NULL) { - printf("ERROR: Cannot render, no camera\n"); + BKE_report(re->reports, RPT_ERROR, "Cannot render, no camera"); G.is_break = TRUE; return; } @@ -2209,7 +2211,7 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr } else { char name[FILE_MAX]; - BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, FALSE); + BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, FALSE); /* reports only used for Movie */ do_write_image_or_movie(re, bmain, scene, NULL, name); @@ -2279,7 +2281,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie if (name_override) BLI_strncpy(name, name_override, sizeof(name)); else - BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, TRUE); + BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, TRUE); if (re->r.im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { if (re->result) { @@ -2307,7 +2309,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie if (BLI_testextensie(name, ".exr")) name[strlen(name) - 4] = 0; - BKE_add_image_extension(name, R_IMF_IMTYPE_JPEG90); + BKE_add_image_extension(name, &imf); ibuf->planes = 24; IMB_colormanagement_imbuf_for_write(ibuf, TRUE, FALSE, &scene->view_settings, @@ -2412,7 +2414,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri /* Touch/NoOverwrite options are only valid for image's */ if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) { if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH)) - BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, TRUE); + BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, TRUE); if (scene->r.mode & R_NO_OVERWRITE && BLI_exists(name)) { printf("skipping existing frame \"%s\"\n", name); diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index fb9eb59cbbf..bef5902588c 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -81,7 +81,7 @@ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ static int test_break(void *data) { - Render *re = (Render*)data; + Render *re = (Render *)data; return re->test_break(re->tbh); } @@ -250,9 +250,9 @@ RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi) //Create Ray cast accelaration structure raytree = rayobject_create( re, re->r.raytrace_structure, faces ); if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) ) - vlakprimitive = obr->rayprimitives = (VlakPrimitive*)MEM_callocN(faces*sizeof(VlakPrimitive), "ObjectRen primitives"); + vlakprimitive = obr->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "ObjectRen primitives"); else - face = obr->rayfaces = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "ObjectRen faces"); + face = obr->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "ObjectRen faces"); obr->rayobi = obi; @@ -345,10 +345,10 @@ static void makeraytree_single(Render *re) raytree = re->raytree = rayobject_create( re, re->r.raytrace_structure, faces+special ); if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) ) { - vlakprimitive = re->rayprimitives = (VlakPrimitive*)MEM_callocN(faces*sizeof(VlakPrimitive), "Raytrace vlak-primitives"); + vlakprimitive = re->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "Raytrace vlak-primitives"); } else { - face = re->rayfaces = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "Render ray faces"); + face = re->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "Render ray faces"); } for (obi=re->instancetable.first; obi; obi=obi->next) @@ -496,8 +496,8 @@ static void shade_ray_set_derivative(ShadeInput *shi) void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) { - ObjectInstanceRen *obi= (ObjectInstanceRen*)is->hit.ob; - VlakRen *vlr= (VlakRen*)is->hit.face; + ObjectInstanceRen *obi = (ObjectInstanceRen *)is->hit.ob; + VlakRen *vlr = (VlakRen *)is->hit.face; /* set up view vector */ copy_v3_v3(shi->view, is->dir); diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 1d84f0e5a94..0587b097f36 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -438,7 +438,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf rr->renrect.xmin = 0; rr->renrect.xmax = rectx - 2 * crop; /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */ rr->crop = crop; - + /* tilerect is relative coordinates within render disprect. do not subtract crop yet */ rr->tilerect.xmin = partrct->xmin - re->disprect.xmin; rr->tilerect.xmax = partrct->xmax - re->disprect.xmin; @@ -931,7 +931,7 @@ static void save_empty_result_tiles(Render *re) IMB_exrtile_clear_channels(rl->exrhandle); for (pa = re->parts.first; pa; pa = pa->next) { - if (pa->ready == 0) { + if (pa->status != PART_STATUS_READY) { int party = pa->disprect.ymin - re->disprect.ymin + pa->crop; int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop; IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0); @@ -1084,8 +1084,7 @@ int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, c ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd) { - int flags = (rd->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE) ? IB_cm_predivide : 0; - ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, flags); + ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0); /* if not exists, BKE_imbuf_write makes one */ ibuf->rect = (unsigned int *)rr->rect32; @@ -1155,17 +1154,15 @@ void render_result_rect_fill_zero(RenderResult *rr) rr->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); } -void render_result_rect_get_pixels(RenderResult *rr, RenderData *rd, unsigned int *rect, int rectx, int recty, +void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rectx, int recty, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings) { if (rr->rect32) { memcpy(rect, rr->rect32, sizeof(int) * rr->rectx * rr->recty); } else if (rr->rectf) { - int predivide = (rd->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); - IMB_display_buffer_transform_apply((unsigned char *) rect, rr->rectf, rr->rectx, rr->recty, 4, - view_settings, display_settings, predivide); + view_settings, display_settings, TRUE); } else /* else fill with black */ diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index bd0061c0e68..14586f16478 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -20,6 +20,7 @@ * * Contributors: Hos, Robert Wenzlaff. * Contributors: 2004/2005/2006 Blender Foundation, full recode + * Contributors: Vertex color baking, Copyright 2011 AutoCRC * * ***** END GPL LICENSE BLOCK ***** */ @@ -51,9 +52,12 @@ #include "DNA_image_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_group_types.h" +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" @@ -710,9 +714,11 @@ static void sky_tile(RenderPart *pa, RenderLayer *rl) if (pass[3]==0.0f) { copy_v4_v4(pass, col); + pass[3] = 1.0f; } else { addAlphaUnderFloat(pass, col); + pass[3] = 1.0f; } } } @@ -981,29 +987,6 @@ static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect) } } -static void convert_to_key_alpha(RenderPart *pa, RenderLayer *rl) -{ - RenderLayer *rlpp[RE_MAX_OSA]; - int y, sample, totsample; - - totsample= get_sample_layers(pa, rl, rlpp); - - for (sample= 0; sample<totsample; sample++) { - float *rectf= rlpp[sample]->rectf; - - for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) { - if (rectf[3] >= 1.0f) { - /* pass */ - } - else if (rectf[3] > 0.0f) { - rectf[0] /= rectf[3]; - rectf[1] /= rectf[3]; - rectf[2] /= rectf[3]; - } - } - } -} - /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */ static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl) { @@ -1172,7 +1155,7 @@ typedef struct ZbufSolidData { static void make_pixelstructs(RenderPart *pa, ZSpan *zspan, int sample, void *data) { - ZbufSolidData *sdata= (ZbufSolidData*)data; + ZbufSolidData *sdata = (ZbufSolidData *)data; ListBase *lb= sdata->psmlist; intptr_t *rd= pa->rectdaps; int *ro= zspan->recto; @@ -1312,10 +1295,6 @@ void zbufshadeDA_tile(RenderPart *pa) /* clamp alpha to 0..1 range, can go outside due to filter */ clamp_alpha_rgb_range(pa, rl); - /* de-premul alpha */ - if (R.r.alphamode & R_ALPHAKEY) - convert_to_key_alpha(pa, rl); - /* free stuff within loop! */ MEM_freeN(pa->rectdaps); pa->rectdaps= NULL; freeps(&psmlist); @@ -1476,10 +1455,6 @@ void zbufshade_tile(RenderPart *pa) if (rl->passflag & SCE_PASS_VECTOR) reset_sky_speed(pa, rl); - /* de-premul alpha */ - if (R.r.alphamode & R_ALPHAKEY) - convert_to_key_alpha(pa, rl); - if (edgerect) MEM_freeN(edgerect); edgerect= NULL; @@ -1740,7 +1715,7 @@ void zbufshade_sss_tile(RenderPart *pa) #if 0 if (rs) { /* for each sample in this pixel, shade it */ - for (ps=(PixStr*)*rs; ps; ps=ps->next) { + for (ps = (PixStr *)(*rs); ps; ps=ps->next) { ObjectInstanceRen *obi= &re->objectinstance[ps->obi]; ObjectRen *obr= obi->obr; vlr= RE_findOrAddVlak(obr, (ps->facenr-1) & RE_QUAD_MASK); @@ -2032,6 +2007,12 @@ typedef struct BakeShade { float dir[3]; Object *actob; + + /* Output: vertex color or image data. If vcol is not NULL, rect and + * rect_float should be NULL. */ + MPoly *mpoly; + MLoop *mloop; + MLoopCol *vcol; unsigned int *rect; float *rect_float; @@ -2208,7 +2189,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua } } - if (bs->rect_float) { + if (bs->rect_float && !bs->vcol) { float *col= bs->rect_float + 4*(bs->rectx*y + x); copy_v3_v3(col, shr.combined); if (bs->type==RE_BAKE_ALL || bs->type==RE_BAKE_TEXTURE) { @@ -2219,7 +2200,8 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua } } else { - unsigned char *col= (unsigned char *)(bs->rect + bs->rectx*y + x); + /* Target is char (LDR). */ + unsigned char col[4]; if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { float rgb[3]; @@ -2239,6 +2221,19 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua else { col[3]= 255; } + + if (bs->vcol) { + /* Vertex colour baking. Vcol has no useful alpha channel (it exists + * but is used only for vertex painting). */ + bs->vcol->r = col[0]; + bs->vcol->g = col[1]; + bs->vcol->b = col[2]; + } + else { + unsigned char *imcol= (unsigned char *)(bs->rect + bs->rectx*y + x); + copy_v4_v4_char((char *)imcol, (char *)col); + } + } if (bs->rect_mask) { @@ -2258,15 +2253,28 @@ static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, disp = 0.5f + dist; /* alter the range from [-0.5,0.5] to [0,1]*/ } - if (bs->rect_float) { + if (bs->rect_float && !bs->vcol) { float *col= bs->rect_float + 4*(bs->rectx*y + x); col[0] = col[1] = col[2] = disp; col[3]= 1.0f; } else { - char *col= (char *)(bs->rect + bs->rectx*y + x); + /* Target is char (LDR). */ + unsigned char col[4]; col[0] = col[1] = col[2] = FTOCHAR(disp); - col[3]= 255; + col[3] = 255; + + if(bs->vcol) { + /* Vertex colour baking. Vcol has no useful alpha channel (it exists + * but is used only for vertex painting). */ + bs->vcol->r = col[0]; + bs->vcol->g = col[1]; + bs->vcol->b = col[2]; + } + else { + char *imcol= (char *)(bs->rect + bs->rectx*y + x); + copy_v4_v4_char((char *)imcol, (char *)col); + } } if (bs->rect_mask) { bs->rect_mask[bs->rectx*y + x] = FILTER_MASK_USED; @@ -2461,8 +2469,8 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v) /* if hit, we shade from the new point, otherwise from point one starting face */ if (hit) { - obi= (ObjectInstanceRen*)minisec.hit.ob; - vlr= (VlakRen*)minisec.hit.face; + obi = (ObjectInstanceRen *)minisec.hit.ob; + vlr = (VlakRen *)minisec.hit.face; quad= (minisec.isect == 2); copy_v3_v3(shi->co, minco); @@ -2502,13 +2510,55 @@ static int get_next_bake_face(BakeShade *bs) vlr= RE_findOrAddVlak(obr, v); if ((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) { - tface= RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); + if(R.r.bake_flag & R_BAKE_VCOL) { + /* Gather face data for vertex colour bake */ + Mesh *me; + int *origindex, vcollayer; + CustomDataLayer *cdl; + + if(obr->ob->type != OB_MESH) + continue; + me = obr->ob->data; + + origindex = RE_vlakren_get_origindex(obr, vlr, 0); + if(origindex == NULL) + continue; + if (*origindex >= me->totpoly) { + /* Small hack for Array modifier, which gives false + original indices - z0r */ + continue; + } +#if 0 + /* Only shade selected faces. */ + if((me->mface[*origindex].flag & ME_FACE_SEL) == 0) + continue; +#endif - if (tface && tface->tpage) { - Image *ima= tface->tpage; - ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL); + vcollayer = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL); + if(vcollayer == -1) + continue; + + cdl = &me->ldata.layers[vcollayer]; + bs->mpoly = me->mpoly + *origindex; + bs->vcol = ((MLoopCol*)cdl->data) + bs->mpoly->loopstart; + bs->mloop = me->mloop + bs->mpoly->loopstart; + + /* Tag mesh for reevaluation. */ + DAG_id_tag_update(&me->id, 0); + } + else { + Image *ima = NULL; + ImBuf *ibuf = NULL; const float vec_alpha[4]= {0.0f, 0.0f, 0.0f, 0.0f}; const float vec_solid[4]= {0.0f, 0.0f, 0.0f, 1.0f}; + + tface= RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); + + if (!tface || !tface->tpage) + continue; + + ima = tface->tpage; + ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); if (ibuf==NULL) continue; @@ -2544,20 +2594,17 @@ static int get_next_bake_face(BakeShade *bs) R.bakebuf= ima; } + /* Tag image for redraw. */ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - - bs->obi= obi; - bs->vlr= vlr; - - bs->vdone++; /* only for error message if nothing was rendered */ - v++; - - BLI_unlock_thread(LOCK_CUSTOM1); - BKE_image_release_ibuf(ima, ibuf, NULL); - - return 1; } + + bs->obi = obi; + bs->vlr = vlr; + bs->vdone++; /* only for error message if nothing was rendered */ + v++; + BLI_unlock_thread(LOCK_CUSTOM1); + return 1; } } } @@ -2566,6 +2613,73 @@ static int get_next_bake_face(BakeShade *bs) return 0; } +static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v) +{ + int *origindex, i; + MLoopCol *basevcol; + MLoop *mloop; + + origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0); + if (!origindex || *origindex == ORIGINDEX_NONE) + return; + + /* Search for matching vertex index and apply shading. */ + for (i = 0; i < bs->mpoly->totloop; i++) { + mloop = bs->mloop + i; + if (mloop->v != *origindex) + continue; + basevcol = bs->vcol; + bs->vcol = basevcol + i; + do_bake_shade(bs, 0, 0, u, v); + bs->vcol = basevcol; + break; + } +} + +/* Bake all vertices of a face. Actually, this still works on a face-by-face + basis, and each vertex on each face is shaded. Vertex colors are a property + of loops, not vertices. */ +static void shade_verts(BakeShade *bs) +{ + VlakRen *vlr = bs->vlr; + + /* Disable baking to image; write to vcol instead. vcol pointer is set in + * bake_single_vertex. */ + bs->ima = NULL; + bs->rect = NULL; + bs->rect_float = NULL; + + bs->quad = 0; + + /* No anti-aliasing for vertices. */ + zero_v3(bs->dxco); + zero_v3(bs->dyco); + + /* Shade each vertex of the face. u and v are barycentric coordinates; since + we're only interested in vertices, these will be 0 or 1. */ + if ((vlr->flag & R_FACE_SPLIT) == 0) { + /* Processing triangle face, whole quad, or first half of split quad. */ + + bake_single_vertex(bs, bs->vlr->v1, 1.0f, 0.0f); + bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f); + bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f); + + if (vlr->v4) { + bs->quad = 1; + bake_single_vertex(bs, bs->vlr->v4, 0.0f, 0.0f); + } + } + else { + /* Processing second half of split quad. Only one vertex to go. */ + if (vlr->flag & R_DIVIDE_24) { + bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f); + } + else { + bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f); + } + } +} + /* already have tested for tface and ima and zspan */ static void shade_tface(BakeShade *bs) { @@ -2593,6 +2707,7 @@ static void shade_tface(BakeShade *bs) bs->rect= bs->ibuf->rect; bs->rect_colorspace= bs->ibuf->rect_colorspace; bs->rect_float= bs->ibuf->rect_float; + bs->vcol = NULL; bs->quad= 0; if (bs->use_mask) { @@ -2636,7 +2751,10 @@ static void *do_bake_thread(void *bs_v) BakeShade *bs= bs_v; while (get_next_bake_face(bs)) { - shade_tface(bs); + if (R.r.bake_flag & R_BAKE_VCOL) + shade_verts(bs); + else + shade_tface(bs); /* fast threadsafe break test */ if (R.test_break(R.tbh)) @@ -2700,14 +2818,16 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up use_mask = TRUE; /* baker uses this flag to detect if image was initialized */ - for (ima= G.main->image.first; ima; ima= ima->id.next) { - ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL); - ima->id.flag |= LIB_DOIT; - ima->flag&= ~IMA_USED_FOR_RENDER; - if (ibuf) { - ibuf->userdata = NULL; /* use for masking if needed */ + if ((R.r.bake_flag & R_BAKE_VCOL) == 0) { + for (ima = G.main->image.first; ima; ima = ima->id.next) { + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ima->id.flag |= LIB_DOIT; + ima->flag &= ~IMA_USED_FOR_RENDER; + if (ibuf) { + ibuf->userdata = NULL; /* use for masking if needed */ + } + BKE_image_release_ibuf(ima, ibuf, NULL); } - BKE_image_release_ibuf(ima, ibuf, NULL); } BLI_init_threads(&threads, do_bake_thread, re->r.threads); @@ -2731,7 +2851,10 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up handles[a].type= type; handles[a].actob= actob; - handles[a].zspan= MEM_callocN(sizeof(ZSpan), "zspan for bake"); + if (R.r.bake_flag & R_BAKE_VCOL) + handles[a].zspan = NULL; + else + handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake"); handles[a].use_mask = use_mask; @@ -2758,27 +2881,29 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up } /* filter and refresh images */ - for (ima= G.main->image.first; ima; ima= ima->id.next) { - if ((ima->id.flag & LIB_DOIT)==0) { - ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL); + if ((R.r.bake_flag & R_BAKE_VCOL) == 0) { + for (ima = G.main->image.first; ima; ima = ima->id.next) { + if ((ima->id.flag & LIB_DOIT)==0) { + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - if (ima->flag & IMA_USED_FOR_RENDER) - result= BAKE_RESULT_FEEDBACK_LOOP; + if (ima->flag & IMA_USED_FOR_RENDER) + result = BAKE_RESULT_FEEDBACK_LOOP; - if (!ibuf) - continue; + if (!ibuf) + continue; - RE_bake_ibuf_filter(ibuf, (char *)ibuf->userdata, re->r.bake_filter); + RE_bake_ibuf_filter(ibuf, (char *)ibuf->userdata, re->r.bake_filter); - ibuf->userflags |= IB_BITMAPDIRTY; - BKE_image_release_ibuf(ima, ibuf, NULL); + ibuf->userflags |= IB_BITMAPDIRTY; + BKE_image_release_ibuf(ima, ibuf, NULL); + } + } + + /* calculate return value */ + for (a = 0; a < re->r.threads; a++) { + zbuf_free_span(handles[a].zspan); + MEM_freeN(handles[a].zspan); } - } - - /* calculate return value */ - for (a=0; a<re->r.threads; a++) { - zbuf_free_span(handles[a].zspan); - MEM_freeN(handles[a].zspan); } MEM_freeN(handles); diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index e189d8bdaea..7ca4f01ae47 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -105,6 +105,8 @@ #define RE_MTFACE_ELEMS 1 #define RE_MCOL_ELEMS 4 #define RE_UV_ELEMS 2 +#define RE_VLAK_ORIGINDEX_ELEMS 1 +#define RE_VERT_ORIGINDEX_ELEMS 1 #define RE_SURFNOR_ELEMS 3 #define RE_RADFACE_ELEMS 1 #define RE_SIMPLIFY_ELEMS 2 @@ -192,10 +194,26 @@ float *RE_vertren_get_winspeed(ObjectInstanceRen *obi, VertRen *ver, int verify) return winspeed + ver->index*RE_WINSPEED_ELEMS; } +int *RE_vertren_get_origindex(ObjectRen *obr, VertRen *ver, int verify) +{ + int *origindex; + int nr= ver->index>>8; + + origindex= obr->vertnodes[nr].origindex; + if (origindex==NULL) { + if (verify) + origindex= obr->vertnodes[nr].origindex= MEM_mallocN(256*RE_VERT_ORIGINDEX_ELEMS*sizeof(int), "origindex table"); + else + return NULL; + } + return origindex + (ver->index & 255)*RE_VERT_ORIGINDEX_ELEMS; +} + VertRen *RE_vertren_copy(ObjectRen *obr, VertRen *ver) { VertRen *v1= RE_findOrAddVert(obr, obr->totvert++); float *fp1, *fp2; + int *int1, *int2; int index= v1->index; *v1= *ver; @@ -221,6 +239,11 @@ VertRen *RE_vertren_copy(ObjectRen *obr, VertRen *ver) fp2= RE_vertren_get_tangent(obr, v1, 1); memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float)); } + int1= RE_vertren_get_origindex(obr, ver, 0); + if (int1) { + int2= RE_vertren_get_origindex(obr, v1, 1); + memcpy(int2, int1, RE_VERT_ORIGINDEX_ELEMS*sizeof(int)); + } return v1; } @@ -332,6 +355,21 @@ MCol *RE_vlakren_get_mcol(ObjectRen *obr, VlakRen *vlr, int n, char **name, int return node->mcol + index*RE_MCOL_ELEMS; } +int *RE_vlakren_get_origindex(ObjectRen *obr, VlakRen *vlak, int verify) +{ + int *origindex; + int nr= vlak->index>>8; + + origindex= obr->vlaknodes[nr].origindex; + if(origindex==NULL) { + if(verify) + origindex= obr->vlaknodes[nr].origindex= MEM_callocN(256*RE_VLAK_ORIGINDEX_ELEMS*sizeof(int), "origindex table"); + else + return NULL; + } + return origindex + (vlak->index & 255)*RE_VLAK_ORIGINDEX_ELEMS; +} + float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify) { float *surfnor; @@ -370,7 +408,7 @@ RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify) radface= obr->vlaknodes[nr].radface; if (radface==NULL) { if (verify) - radface= obr->vlaknodes[nr].radface= MEM_callocN(256*RE_RADFACE_ELEMS*sizeof(void*), "radface table"); + radface = obr->vlaknodes[nr].radface= MEM_callocN(256 * RE_RADFACE_ELEMS * sizeof(void *), "radface table"); else return NULL; } @@ -383,6 +421,7 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr) MTFace *mtface, *mtface1; MCol *mcol, *mcol1; float *surfnor, *surfnor1, *tangent, *tangent1; + int *origindex, *origindex1; RadFace **radface, **radface1; int i, index = vlr1->index; char *name; @@ -400,6 +439,13 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr) memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS); } + origindex= RE_vlakren_get_origindex(obr, vlr, 0); + if(origindex) { + origindex1= RE_vlakren_get_origindex(obr, vlr1, 1); + /* Just an int, but memcpy for consistency. */ + memcpy(origindex1, origindex, sizeof(int)*RE_VLAK_ORIGINDEX_ELEMS); + } + surfnor= RE_vlakren_get_surfnor(obr, vlr, 0); if (surfnor) { surfnor1= RE_vlakren_get_surfnor(obr, vlr1, 1); @@ -725,6 +771,8 @@ void free_renderdata_vertnodes(VertTableNode *vertnodes) MEM_freeN(vertnodes[a].stress); if (vertnodes[a].winspeed) MEM_freeN(vertnodes[a].winspeed); + if (vertnodes[a].origindex) + MEM_freeN(vertnodes[a].origindex); } MEM_freeN(vertnodes); @@ -743,6 +791,8 @@ void free_renderdata_vlaknodes(VlakTableNode *vlaknodes) MEM_freeN(vlaknodes[a].mtface); if (vlaknodes[a].mcol) MEM_freeN(vlaknodes[a].mcol); + if(vlaknodes[a].origindex) + MEM_freeN(vlaknodes[a].origindex); if (vlaknodes[a].surfnor) MEM_freeN(vlaknodes[a].surfnor); if (vlaknodes[a].tangent) @@ -888,9 +938,9 @@ HaloRen *RE_findOrAddHalo(ObjectRen *obr, int nr) // TABLEINITSIZE, obr->blohalen+TABLEINITSIZE ); temp=obr->bloha; - obr->bloha=(HaloRen**)MEM_callocN(sizeof(void*)*(obr->blohalen+TABLEINITSIZE), "Bloha"); - if (temp) memcpy(obr->bloha, temp, obr->blohalen*sizeof(void*)); - memset(&(obr->bloha[obr->blohalen]), 0, TABLEINITSIZE*sizeof(void*)); + obr->bloha = (HaloRen**)MEM_callocN(sizeof(void *) * (obr->blohalen + TABLEINITSIZE), "Bloha"); + if (temp) memcpy(obr->bloha, temp, obr->blohalen*sizeof(void *)); + memset(&(obr->bloha[obr->blohalen]), 0, TABLEINITSIZE * sizeof(void *)); obr->blohalen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ if (temp) MEM_freeN(temp); } diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c index 078c11a2061..87912f546e8 100644 --- a/source/blender/render/intern/source/shadbuf.c +++ b/source/blender/render/intern/source/shadbuf.c @@ -812,7 +812,7 @@ void makeshadowbuf(Render *re, LampRen *lar) static void *do_shadow_thread(void *re_v) { - Render *re= (Render*)re_v; + Render *re = (Render *)re_v; LampRen *lar; do { diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c index 569bac29205..a37ffb1eb28 100644 --- a/source/blender/render/intern/source/strand.c +++ b/source/blender/render/intern/source/strand.c @@ -522,7 +522,7 @@ static APixstrand *addpsAstrand(ZSpan *zspan) static void do_strand_fillac(void *handle, int x, int y, float u, float v, float z) { - StrandPart *spart= (StrandPart*)handle; + StrandPart *spart= (StrandPart *)handle; StrandShadeCache *cache= spart->cache; StrandSegment *sseg= spart->segment; APixstrand *apn, *apnew; diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 549148f4e29..a9db197ed48 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -493,7 +493,7 @@ typedef struct VolPrecacheQueue { */ static void *vol_precache_part(void *data) { - VolPrecacheQueue *queue = (VolPrecacheQueue*)data; + VolPrecacheQueue *queue = (VolPrecacheQueue *)data; VolPrecachePart *pa; while ((pa = BLI_thread_queue_pop(queue->work))) { diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 75ab0f5bcd7..eee4b5a3a57 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -62,6 +62,7 @@ struct MenuType; struct wmDropBox; struct wmDrag; struct ImBuf; +struct ImageFormatData; typedef struct wmJob wmJob; @@ -185,7 +186,7 @@ int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, struct wm int WM_operator_confirm (struct bContext *C, struct wmOperator *op, struct wmEvent *event); /* invoke callback, file selector "filepath" unset + exec */ int WM_operator_filesel (struct bContext *C, struct wmOperator *op, struct wmEvent *event); -int WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const char imtype); +int WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFormatData *im_format); /* poll callback, context checks */ int WM_operator_winactive (struct bContext *C); /* invoke callback, exec + redo popup */ @@ -264,6 +265,13 @@ char *WM_prop_pystring_assign(struct bContext *C, struct PointerRNA *ptr, struc void WM_operator_bl_idname(char *to, const char *from); void WM_operator_py_idname(char *to, const char *from); +/* *************** uilist types ******************** */ +void WM_uilisttype_init(void); +struct uiListType *WM_uilisttype_find(const char *idname, int quiet); +int WM_uilisttype_add(struct uiListType *ult); +void WM_uilisttype_freelink(struct uiListType *ult); +void WM_uilisttype_free(void); + /* *************** menu types ******************** */ void WM_menutype_init(void); struct MenuType *WM_menutype_find(const char *idname, int quiet); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 8fe387765ce..53e67e91bd2 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -149,7 +149,63 @@ void WM_operator_stack_clear(wmWindowManager *wm) WM_main_add_notifier(NC_WM | ND_HISTORY, NULL); } -/* ****************************************** */ + +/* ************ uiListType handling ************** */ + +static GHash *uilisttypes_hash = NULL; + +uiListType *WM_uilisttype_find(const char *idname, int quiet) +{ + uiListType *ult; + + if (idname[0]) { + ult = BLI_ghash_lookup(uilisttypes_hash, idname); + if (ult) { + return ult; + } + } + + if (!quiet) { + printf("search for unknown uilisttype %s\n", idname); + } + + return NULL; +} + +int WM_uilisttype_add(uiListType *ult) +{ + BLI_ghash_insert(uilisttypes_hash, (void *)ult->idname, ult); + return 1; +} + +void WM_uilisttype_freelink(uiListType *ult) +{ + BLI_ghash_remove(uilisttypes_hash, ult->idname, NULL, (GHashValFreeFP)MEM_freeN); +} + +/* called on initialize WM_init() */ +void WM_uilisttype_init(void) +{ + uilisttypes_hash = BLI_ghash_str_new("uilisttypes_hash gh"); +} + +void WM_uilisttype_free(void) +{ + GHashIterator *iter = BLI_ghashIterator_new(uilisttypes_hash); + + for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) { + uiListType *ult = BLI_ghashIterator_getValue(iter); + if (ult->ext.free) { + ult->ext.free(ult->ext.data); + } + } + BLI_ghashIterator_free(iter); + + BLI_ghash_free(uilisttypes_hash, NULL, (GHashValFreeFP)MEM_freeN); + uilisttypes_hash = NULL; +} + +/* ************ MenuType handling ************** */ static GHash *menutypes_hash = NULL; diff --git a/source/blender/windowmanager/intern/wm_apple.c b/source/blender/windowmanager/intern/wm_apple.c index a7bd43986dd..842fc353699 100644 --- a/source/blender/windowmanager/intern/wm_apple.c +++ b/source/blender/windowmanager/intern/wm_apple.c @@ -77,7 +77,7 @@ static int checkAppleVideoCard(void) if ((theErr == 0) && (value != 0)) { theErr = CGLDescribeRenderer(rend, j, kCGLRPCompliant, &value); if ((theErr == 0) && (value != 0)) { - /*fprintf(stderr,"make it big\n");*/ + /*fprintf(stderr, "make it big\n");*/ CGLDestroyRendererInfo(rend); macPrefState = 8; return 1; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index e462e21d9f4..a6b3efd30bf 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -66,6 +66,8 @@ #include "RNA_access.h" +#include "BIF_gl.h" + #include "UI_interface.h" #include "PIL_time.h" @@ -338,7 +340,7 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve ARegion *region = CTX_wm_region(C); ARegion *menu = CTX_wm_menu(C); static int do_wheel_ui = TRUE; - int is_wheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE); + int is_wheel = ELEM3(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN); int retval; /* UI code doesn't handle return values - it just always returns break. @@ -2180,6 +2182,13 @@ void wm_event_do_handlers(bContext *C) /* update key configuration after handling events */ WM_keyconfig_update(wm); + + if (G.debug) { + GLenum error = glGetError(); + if (error != GL_NO_ERROR) { + printf("GL error: %s\n", gluErrorString(error)); + } + } } /* ********** filesector handling ************ */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 918068cc7d1..61699c94567 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -538,7 +538,7 @@ int wm_homefile_read(bContext *C, ReportList *UNUSED(reports), short from_memory } if (U.themes.first == NULL) { - printf("\nError: No valid "STRINGIFY (BLENDER_STARTUP_FILE)", fall back to built-in default.\n\n"); + printf("\nNote: No (valid) "STRINGIFY (BLENDER_STARTUP_FILE)" found, fall back to built-in default.\n\n"); success = 0; } @@ -556,7 +556,7 @@ int wm_homefile_read(bContext *C, ReportList *UNUSED(reports), short from_memory /* check new prefs only after startup.blend was finished */ if (!from_memory && BLI_exists(prefstr)) { int done = BKE_read_file_userdef(prefstr, NULL); - if (done) printf("read new prefs: %s\n", prefstr); + if (done) printf("Read new prefs: %s\n", prefstr); } /* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 1cf44a69c17..168c2312d9f 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -258,7 +258,7 @@ static void draw_filled_lasso(wmGesture *gt) if (sf_vert_first) { const float zvec[3] = {0.0f, 0.0f, 1.0f}; BLI_scanfill_edge_add(&sf_ctx, sf_vert_first, sf_vert); - BLI_scanfill_calc_ex(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES, zvec); + BLI_scanfill_calc_ex(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES | BLI_SCANFILL_CALC_HOLES, zvec); glEnable(GL_BLEND); glColor4f(1.0, 1.0, 1.0, 0.05); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 3cffa143ebc..de0da3df868 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -66,6 +66,7 @@ #include "BKE_node.h" #include "BKE_report.h" +#include "BKE_addon.h" #include "BKE_packedFile.h" #include "BKE_sequencer.h" /* free seq clipboard */ #include "BKE_material.h" /* clear_matcopybuf */ @@ -135,8 +136,12 @@ void WM_init(bContext *C, int argc, const char **argv) wm_init_cursor_data(); } GHOST_CreateSystemPaths(); + + BKE_addon_pref_type_init(); + wm_operatortype_init(); WM_menutype_init(); + WM_uilisttype_init(); set_free_windowmanager_cb(wm_close_and_free); /* library.c */ set_blender_test_break_cb(wm_window_testbreak); /* blender.c */ @@ -400,9 +405,12 @@ void WM_exit_ext(bContext *C, const short do_python) ED_screen_exit(C, win, win->screen); } } + + BKE_addon_pref_type_free(); wm_operatortype_free(); wm_dropbox_free(); WM_menutype_free(); + WM_uilisttype_free(); /* all non-screen and non-space stuff editors did, like editmode */ if (C) diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index b5f1d590f37..bfcd4b1e955 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -583,7 +583,7 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert for (link = lb.first; link; link = link->next) { const char *identifier = link->data; - PointerRNA ctx_item_ptr = CTX_data_pointer_get(C, identifier); + PointerRNA ctx_item_ptr = {{0}}; // CTX_data_pointer_get(C, identifier); if (ctx_item_ptr.type == NULL) { continue; @@ -976,14 +976,14 @@ int WM_operator_filesel(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) } } -int WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const char imtype) +int WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFormatData *im_format) { PropertyRNA *prop; char filepath[FILE_MAX]; /* dont NULL check prop, this can only run on ops with a 'filepath' */ prop = RNA_struct_find_property(op->ptr, "filepath"); RNA_property_string_get(op->ptr, prop, filepath); - if (BKE_add_image_extension(filepath, imtype)) { + if (BKE_add_image_extension(filepath, im_format)) { RNA_property_string_set(op->ptr, prop, filepath); /* note, we could check for and update 'filename' here, * but so far nothing needs this. */ @@ -2129,8 +2129,11 @@ void wm_recover_last_session(bContext *C, ReportList *reports) /* XXX bad global... fixme */ if (G.main->name[0]) G.file_loaded = 1; /* prevents splash to show */ - else + else { G.relbase_valid = 0; + G.save_over = 0; /* start with save preference untitled.blend */ + } + } } @@ -2168,7 +2171,7 @@ static int wm_recover_auto_save_exec(bContext *C, wmOperator *op) WM_file_read(C, path, op->reports); G.fileflags &= ~G_FILE_RECOVER; - + return OPERATOR_FINISHED; } @@ -2426,9 +2429,8 @@ static int wm_console_toggle_op(bContext *UNUSED(C), wmOperator *UNUSED(op)) static void WM_OT_console_toggle(wmOperatorType *ot) { - /* XXX Have to mark these for xgettext, as under linux they do not exists... - * And even worth, have to give the context as text, as xgettext doesn't expand macros. :( */ - ot->name = CTX_N_("Operator" /* BLF_I18NCONTEXT_OPERATOR_DEFAULT */, "Toggle System Console"); + /* XXX Have to mark these for xgettext, as under linux they do not exists... */ + ot->name = CTX_N_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Toggle System Console"); ot->idname = "WM_OT_console_toggle"; ot->description = N_("Toggle System Console"); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index be202a23d33..ec94501c8be 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -544,6 +544,7 @@ void WM_window_open_temp(bContext *C, rcti *position, int type) } ED_screen_set(C, win->screen); + ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */ if (sa->spacetype == SPACE_IMAGE) GHOST_SetTitle(win->ghostwin, IFACE_("Blender Render")); diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index c90bbaf8d6c..78a67a31e0f 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -53,6 +53,9 @@ #define MOUSEX 4 #define MOUSEY 5 + +/* *** wmEvent.type *** */ + /* non-event, for example disabled timer */ #define EVENT_NONE 0 /* MOUSE : 0x00x */ @@ -154,8 +157,7 @@ enum { #define TIMERF 0x011F /* last timer */ /* test whether the event is timer event */ -#define ISTIMER(event) (event >= TIMER && event <= TIMERF) - +#define ISTIMER(event_type) (event_type >= TIMER && event_type <= TIMERF) /* standard keyboard */ #define AKEY 'a' @@ -289,29 +291,30 @@ enum { /* for event checks */ /* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */ /* UNUSED - see wm_eventmatch - BUG [#30479] */ -// #define ISTEXTINPUT(event) (event >= ' ' && event <= 255) +// #define ISTEXTINPUT(event_type) (event_type >= ' ' && event_type <= 255) +/* note, an alternative could be to check 'event->utf8_buf' */ /* test whether the event is a key on the keyboard */ -#define ISKEYBOARD(event) (event >= ' ' && event <= 320) +#define ISKEYBOARD(event_type) (event_type >= ' ' && event_type <= 320) /* test whether the event is a modifier key */ -#define ISKEYMODIFIER(event) ((event >= LEFTCTRLKEY && event <= LEFTSHIFTKEY) || event == OSKEY) +#define ISKEYMODIFIER(event_type) ((event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) || event_type == OSKEY) /* test whether the event is a mouse button */ -#define ISMOUSE(event) (event >= LEFTMOUSE && event <= MOUSEROTATE) +#define ISMOUSE(event_type) (event_type >= LEFTMOUSE && event_type <= MOUSEROTATE) /* test whether the event is tweak event */ -#define ISTWEAK(event) (event >= EVT_TWEAK_L && event <= EVT_GESTURE) +#define ISTWEAK(event_type) (event_type >= EVT_TWEAK_L && event_type <= EVT_GESTURE) /* test whether the event is a NDOF event */ -#define ISNDOF(event) (event >= NDOF_MOTION && event < NDOF_LAST) +#define ISNDOF(event_type) (event_type >= NDOF_MOTION && event_type < NDOF_LAST) /* test whether event type is acceptable as hotkey, excluding modifiers */ -#define ISHOTKEY(event) \ - ((ISKEYBOARD(event) || ISMOUSE(event) || ISNDOF(event)) && \ - (event != ESCKEY) && \ - (event >= LEFTCTRLKEY && event <= LEFTSHIFTKEY) == FALSE && \ - (event >= UNKNOWNKEY && event <= GRLESSKEY) == FALSE) +#define ISHOTKEY(event_type) \ + ((ISKEYBOARD(event_type) || ISMOUSE(event_type) || ISNDOF(event_type)) && \ + (event_type != ESCKEY) && \ + (event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) == FALSE && \ + (event_type >= UNKNOWNKEY && event_type <= GRLESSKEY) == FALSE) /* **************** BLENDER GESTURE EVENTS (0x5000) **************** */ diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index 85bb07d6e83..d606605e8d5 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -149,6 +149,7 @@ endif() bf_intern_raskter bf_intern_opencolorio bf_intern_opennl + extern_rangetree ) if(WITH_MOD_CLOTH_ELTOPO) diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index f394290d952..71881a99419 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -207,9 +207,15 @@ void WM_operator_stack_clear(struct bContext *C) {} void WM_autosave_init(struct bContext *C) {} void WM_jobs_kill_all_except(struct wmWindowManager *wm) {} -char *WM_clipboard_text_get(int selection) {return (char*)0;} +char *WM_clipboard_text_get(int selection) {return (char *)0;} void WM_clipboard_text_set(char *buf, int selection) {} +void WM_uilisttype_init(void) {} +struct uiListType *WM_uilisttype_find(const char *idname, int quiet) {return (struct uiListType *)NULL;} +int WM_uilisttype_add(struct uiListType *ult) {return 0;} +void WM_uilisttype_freelink(struct uiListType *ult) {} +void WM_uilisttype_free(void) {} + struct wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id) {return (struct wmKeyMapItem *) NULL;} int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, struct wmEvent *event) {return 0;} void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) {} @@ -407,6 +413,7 @@ void uiItemFullR(struct uiLayout *layout, struct PointerRNA *ptr, struct Propert void uiLayoutSetContextPointer(struct uiLayout *layout, char *name, struct PointerRNA *ptr) {} char *uiLayoutIntrospect(struct uiLayout *layout) {return (char *)NULL;} void UI_reinit_font(void) {} +int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, int big) {return 0;} /* rna template */ void uiTemplateAnyID(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, char *text) {} @@ -421,7 +428,9 @@ void uiTemplateCurveMapping(struct uiLayout *layout, struct CurveMapping *cumap, void uiTemplateColorRamp(struct uiLayout *layout, struct ColorBand *coba, int expand) {} void uiTemplateLayers(struct uiLayout *layout, struct PointerRNA *ptr, char *propname) {} void uiTemplateImageLayers(struct uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser) {} -ListBase uiTemplateList(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, struct PointerRNA *activeptr, char *activepropname, int rows, int listtype) {struct ListBase b = {0,0}; return b;} +void uiTemplateList(struct uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id, + PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, + const char *active_propname, int rows, int maxrows, int layout_type) {} void uiTemplateRunningJobs(struct uiLayout *layout, struct bContext *C) {} void uiTemplateOperatorSearch(struct uiLayout *layout) {} void uiTemplateHeader3D(struct uiLayout *layout, struct bContext *C) {} @@ -509,6 +518,7 @@ float sculpt_get_brush_alpha(struct Brush *brush) {return 0.0f;} void sculpt_set_brush_alpha(struct Brush *brush, float alpha) {} void ED_sculpt_modifiers_changed(struct Object *ob) {} void ED_mesh_calc_tessface(struct Mesh *mesh) {} +void BKE_brush_gen_texture_cache(struct Brush *br, int half_side) {} /* bpy/python internal api */ void operator_wrapper(struct wmOperatorType *ot, void *userdata) {} diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index e0a38096904..7db4b5bfc89 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -793,8 +793,7 @@ add_dependencies(blender makesdna) get_property(BLENDER_LINK_LIBS GLOBAL PROPERTY BLENDER_LINK_LIBS) -set(BLENDER_LINK_LIBS - ${BLENDER_LINK_LIBS} +list(APPEND BLENDER_LINK_LIBS bf_windowmanager bf_render ) @@ -908,7 +907,6 @@ endif() ge_scenegraph ge_logic_network ge_logic_ngnetwork - extern_bullet ge_logic_loopbacknetwork bf_intern_moto extern_openjpeg @@ -929,6 +927,7 @@ endif() cycles_subd bf_intern_raskter bf_intern_opencolorio + extern_rangetree ) if(WITH_COMPOSITOR) @@ -986,6 +985,10 @@ endif() list(APPEND BLENDER_SORTED_LIBS bf_intern_locale) endif() + if(WITH_BULLET AND NOT WITH_BULLET_SYSTEM) + list_insert_after(BLENDER_SORTED_LIBS "ge_logic_ngnetwork" "extern_bullet") + endif() + foreach(SORTLIB ${BLENDER_SORTED_LIBS}) set(REMLIB ${SORTLIB}) foreach(SEARCHLIB ${BLENDER_LINK_LIBS}) diff --git a/source/creator/creator.c b/source/creator/creator.c index 706ced245bb..d678df33ad0 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -1420,7 +1420,7 @@ int main(int argc, const char **argv) WM_main(C); return 0; -} /* end of int main(argc,argv) */ +} /* end of int main(argc, argv) */ #ifdef WITH_PYTHON_MODULE void main_python_exit(void) diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 482700d5958..176dc33d057 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -468,6 +468,8 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c sceneconverter->SetMaterials(true); if (useglslmat && (gs.matmode == GAME_MAT_GLSL)) sceneconverter->SetGLSLMaterials(true); + if (scene->gm.flag & GAME_NO_MATERIAL_CACHING) + sceneconverter->SetCacheMaterials(false); KX_Scene* startscene = new KX_Scene(keyboarddevice, mousedevice, diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt index 9a47d223f76..d833534605b 100644 --- a/source/gameengine/BlenderRoutines/CMakeLists.txt +++ b/source/gameengine/BlenderRoutines/CMakeLists.txt @@ -30,7 +30,6 @@ set(INC ) set(INC_SYS - ../../../extern/bullet2/src ${PTHREADS_INCLUDE_DIRS} ${GLEW_INCLUDE_PATH} ${BOOST_INCLUDE_DIR} @@ -70,4 +69,12 @@ if(WITH_CODEC_FFMPEG) add_definitions(-DWITH_FFMPEG) endif() +if(WITH_BULLET) + list(APPEND INC_SYS + ${BULLET_INCLUDE_DIRS} + ) + add_definitions(-DUSE_BULLET) +endif() + + blender_add_lib(ge_blen_routines "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp index 346d2017ef0..719041e8d41 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp @@ -178,6 +178,18 @@ SetViewPort( glScissor(minx + x1, miny + y1, vp_width, vp_height); } + void +KX_BlenderCanvas:: +UpdateViewPort( + int x1, int y1, + int x2, int y2 +) { + m_viewport[0] = x1; + m_viewport[1] = y1; + m_viewport[2] = x2; + m_viewport[3] = y2; +} + const int* KX_BlenderCanvas:: GetViewPort() { diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h index 244394a115d..4117c13aede 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h @@ -151,6 +151,13 @@ public: int x1, int y1, int x2, int y2 ); + + void + UpdateViewPort( + int x1, int y1, + int x2, int y2 + ); + const int* GetViewPort(); diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp index 00836fa8ecb..f8ad8870e83 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp @@ -259,7 +259,7 @@ void BL_MakeScreenShot(ScrArea *curarea, const char* filename) ImBuf *ibuf; BLI_path_abs(path, G.main->name); /* BKE_add_image_extension() checks for if extension was already set */ - BKE_add_image_extension(path, R_IMF_IMTYPE_PNG); /* scene->r.im_format.imtype */ + BKE_add_image_extension_from_type(path, R_IMF_IMTYPE_PNG); /* scene->r.im_format.imtype */ ibuf= IMB_allocImBuf(dumpsx, dumpsy, 24, 0); ibuf->rect= dumprect; ibuf->ftype= PNG; diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index 1f1c404efcb..395a57d753c 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -112,7 +112,8 @@ void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) if (copy_constraint) { ListBase listb; // copy all constraint for backward compatibility - copy_constraints(&listb, &pchan->constraints, FALSE); // copy_constraints NULLs listb, no need to make extern for this operation. + // BKE_copy_constraints NULLs listb, no need to make extern for this operation. + BKE_copy_constraints(&listb, &pchan->constraints, FALSE); pchan->constraints= listb; } else { pchan->constraints.first = NULL; @@ -304,7 +305,7 @@ void BL_ArmatureObject::LoadConstraints(KX_BlenderSceneConverter* converter) case CONSTRAINT_TYPE_TRANSFORM: case CONSTRAINT_TYPE_DISTLIMIT: case CONSTRAINT_TYPE_TRANSLIKE: - cti = constraint_get_typeinfo(pcon); + cti = BKE_constraint_get_typeinfo(pcon); gametarget = gamesubtarget = NULL; if (cti && cti->get_constraint_targets) { ListBase listb = { NULL, NULL }; diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 874bf614413..a4c4253754e 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -922,6 +922,9 @@ static RAS_MaterialBucket *material_from_mesh(Material *ma, MFace *mface, MTFace /* do Texture Face materials */ Image* bima = (tface)? (Image*)tface->tpage: NULL; STR_String imastr = (tface)? (bima? (bima)->id.name : "" ) : ""; + + if (!converter->GetCacheMaterials()) + polymat = NULL; char alpha_blend=0; short tile=0; @@ -1044,7 +1047,8 @@ static RAS_MaterialBucket *material_from_mesh(Material *ma, MFace *mface, MTFace polymat->m_shininess = 35.0; } - converter->CachePolyMaterial(ma, polymat); + if (converter->GetCacheMaterials()) + converter->CachePolyMaterial(ma, polymat); } } @@ -1260,7 +1264,7 @@ static PHY_MaterialProps *CreateMaterialFromBlenderObject(struct Object* blender MT_assert(materialProps && "Create physics material properties failed"); - Material* blendermat = give_current_material(blenderobject, 0); + Material* blendermat = give_current_material(blenderobject, 1); if (blendermat) { @@ -1345,11 +1349,7 @@ static float my_boundbox_mesh(Mesh *me, float *loc, float *size) int a; if (me->bb==0) { - // This can be called in a seperate (not main) thread when doing async libload, - // so lets try to be safe... - BLI_begin_threaded_malloc(); - me->bb= (struct BoundBox *)MEM_callocN(sizeof(BoundBox), "boundbox"); - BLI_end_threaded_malloc(); + me->bb = BKE_boundbox_alloc_unit(); } bb= me->bb; @@ -2360,6 +2360,10 @@ void BL_ConvertBlenderObjects(struct Main* maggie, set<Object*> allblobj; // all objects converted set<Object*> groupobj; // objects from groups (never in active layer) + // This is bad, but we use this to make sure the first time this is called + // is not in a separate thread. + BL_Texture::GetMaxUnits(); + if (alwaysUseExpandFraming) { frame_type = RAS_FrameSettings::e_frame_extend; aspect_width = canvas->GetWidth(); diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index e01729e156f..8ac9e523d5d 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -112,7 +112,7 @@ set(SRC if(WITH_BULLET) list(APPEND INC_SYS - ../../../extern/bullet2/src + ${BULLET_INCLUDE_DIRS} ) add_definitions(-DUSE_BULLET) endif() diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index ceaa0a5f5a8..5524612f707 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -131,7 +131,8 @@ KX_BlenderSceneConverter::KX_BlenderSceneConverter( m_ketsjiEngine(engine), m_alwaysUseExpandFraming(false), m_usemat(false), - m_useglslmat(false) + m_useglslmat(false), + m_use_mat_cache(true) { tag_main(maggie, 0); /* avoid re-tagging later on */ m_newfilename = ""; @@ -488,6 +489,11 @@ void KX_BlenderSceneConverter::SetGLSLMaterials(bool val) m_useglslmat = val; } +void KX_BlenderSceneConverter::SetCacheMaterials(bool val) +{ + m_use_mat_cache = val; +} + bool KX_BlenderSceneConverter::GetMaterials() { return m_usemat; @@ -498,6 +504,11 @@ bool KX_BlenderSceneConverter::GetGLSLMaterials() return m_useglslmat; } +bool KX_BlenderSceneConverter::GetCacheMaterials() +{ + return m_use_mat_cache; +} + void KX_BlenderSceneConverter::RegisterBlenderMaterial(BL_Material *mat) { // First make sure we don't register the material twice diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h index f7723350eee..06dac1707c5 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.h +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h @@ -91,6 +91,7 @@ class KX_BlenderSceneConverter : public KX_ISceneConverter bool m_alwaysUseExpandFraming; bool m_usemat; bool m_useglslmat; + bool m_use_mat_cache; public: KX_BlenderSceneConverter( @@ -160,6 +161,10 @@ public: virtual void SetGLSLMaterials(bool val); virtual bool GetGLSLMaterials(); + // cache materials during conversion + virtual void SetCacheMaterials(bool val); + virtual bool GetCacheMaterials(); + struct Scene* GetBlenderSceneForName(const STR_String& name); // struct Main* GetMain() { return m_maggie; } diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/KX_ConvertControllers.cpp index 769abd01ce0..5d3d0f33bec 100644 --- a/source/gameengine/Converter/KX_ConvertControllers.cpp +++ b/source/gameengine/Converter/KX_ConvertControllers.cpp @@ -157,7 +157,7 @@ void BL_ConvertControllers( SCA_PythonController* pyctrl = new SCA_PythonController(gameobj, pycont->mode); gamecontroller = pyctrl; #ifdef WITH_PYTHON - + PyGILState_STATE gstate = PyGILState_Ensure(); pyctrl->SetNamespace(converter->GetPyNamespace()); if (pycont->mode==SCA_PythonController::SCA_PYEXEC_SCRIPT) { @@ -186,6 +186,7 @@ void BL_ConvertControllers( } } + PyGILState_Release(gstate); #endif // WITH_PYTHON break; @@ -218,6 +219,7 @@ void BL_ConvertControllers( converter->RegisterGameController(gamecontroller, bcontr); #ifdef WITH_PYTHON + PyGILState_STATE gstate = PyGILState_Ensure(); if (bcontr->type==CONT_PYTHON) { SCA_PythonController *pyctrl= static_cast<SCA_PythonController*>(gamecontroller); /* not strictly needed but gives syntax errors early on and @@ -232,6 +234,8 @@ void BL_ConvertControllers( // pyctrl->Import(); } } + + PyGILState_Release(gstate); #endif // WITH_PYTHON //done with gamecontroller diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index 11b00b7bbf5..4e910a885eb 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -118,16 +118,16 @@ PyTypeObject PyObjectPlus::Type = { 0, /* setattrfunc tp_setattr; */ 0, /* tp_compare */ /* DEPRECATED in python 3.0! */ py_base_repr, /* tp_repr */ - 0,0,0,0,0,0,0,0,0, /* Method suites for standard classes */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* long tp_flags; */ - 0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Method suites for standard classes */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* long tp_flags; */ + 0, 0, 0, 0, /* weak reference enabler */ #ifdef USE_WEAKREFS offsetof(PyObjectPlus_Proxy, in_weakreflist), /* long tp_weaklistoffset; */ #else 0, #endif - 0,0, + 0, 0, Methods, 0, 0, @@ -311,14 +311,14 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * { bool *val = reinterpret_cast<bool*>(ptr); ptr += sizeof(bool); - PyList_SET_ITEM(resultlist,i,PyBool_FromLong(*val)); + PyList_SET_ITEM(resultlist, i, PyBool_FromLong(*val)); break; } case KX_PYATTRIBUTE_TYPE_SHORT: { short int *val = reinterpret_cast<short int*>(ptr); ptr += sizeof(short int); - PyList_SET_ITEM(resultlist,i,PyLong_FromLong(*val)); + PyList_SET_ITEM(resultlist, i, PyLong_FromLong(*val)); break; } case KX_PYATTRIBUTE_TYPE_ENUM: @@ -333,14 +333,14 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * { int *val = reinterpret_cast<int*>(ptr); ptr += sizeof(int); - PyList_SET_ITEM(resultlist,i,PyLong_FromLong(*val)); + PyList_SET_ITEM(resultlist, i, PyLong_FromLong(*val)); break; } case KX_PYATTRIBUTE_TYPE_FLOAT: { float *val = reinterpret_cast<float*>(ptr); ptr += sizeof(float); - PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(*val)); + PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble(*val)); break; } default: @@ -423,7 +423,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * PyObject *resultlist = PyList_New(attrdef->m_imax); for (unsigned int i=0; i<attrdef->m_imax; i++) { - PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(val[i])); + PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble(val[i])); } return resultlist; #endif @@ -443,9 +443,9 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * PyObject *col = PyList_New(attrdef->m_imax); for (unsigned int j=0; j<attrdef->m_imax; j++) { - PyList_SET_ITEM(col,j,PyFloat_FromDouble(val[j])); + PyList_SET_ITEM(col, j, PyFloat_FromDouble(val[j])); } - PyList_SET_ITEM(collist,i,col); + PyList_SET_ITEM(collist, i, col); val += attrdef->m_imax; } return collist; @@ -463,7 +463,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * PyObject *resultlist = PyList_New(3); for (unsigned int i=0; i<3; i++) { - PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble((*val)[i])); + PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble((*val)[i])); } return resultlist; #endif @@ -1110,7 +1110,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt ------------------------------*/ PyObject *PyObjectPlus::py_repr(void) { - PyErr_SetString(PyExc_SystemError, "Representation not overridden by object."); + PyErr_SetString(PyExc_SystemError, "Representation not overridden by object."); return NULL; } @@ -1187,7 +1187,7 @@ void PyObjectPlus::SetDeprecationWarnings(bool ignoreDeprecationWarnings) m_ignore_deprecation_warnings = ignoreDeprecationWarnings; } -void PyObjectPlus::ShowDeprecationWarning_func(const char* old_way,const char* new_way) +void PyObjectPlus::ShowDeprecationWarning_func(const char *old_way, const char *new_way) { printf("Method %s is deprecated, please use %s instead.\n", old_way, new_way); PyC_LineSpit(); diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index 37e26e88750..e2e7c248795 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -389,139 +389,139 @@ typedef struct KX_PYATTRIBUTE_DEF { } m_typeCheck; } PyAttributeDef; -#define KX_PYATTRIBUTE_BOOL_RW(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_BOOL_RW_CHECK(name,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_BOOL_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_BOOL_RW(name, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_BOOL_RW_CHECK(name, object, field, function) \ + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_BOOL_RO(name, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } /* attribute points to a single bit of an integer field, attribute=true if bit is set */ -#define KX_PYATTRIBUTE_FLAG_RW(name,object,field,bit) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLAG_RW_CHECK(name,object,field,bit,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLAG_RO(name,object,field,bit) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_RW(name, object, field, bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_RW_CHECK(name, object, field, bit, function) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_RO(name, object, field, bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } /* attribute points to a single bit of an integer field, attribute=true if bit is set*/ -#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW(name,object,field,bit) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW_CHECK(name,object,field,bit,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RO(name,object,field,bit) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW(name, object, field, bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW_CHECK(name, object, field, bit, function) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RO(name, object, field, bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } // enum field cannot be mapped to pointer (because we would need a pointer for each enum) // use field size to verify mapping at runtime only, assuming enum size is equal to int size. -#define KX_PYATTRIBUTE_ENUM_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_ENUM_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_ENUM_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } - -#define KX_PYATTRIBUTE_SHORT_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_ENUM_RW(name, min, max, clamp, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_ENUM_RW_CHECK(name, min, max, clamp, object, field, function) \ + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_ENUM_RO(name, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } + +#define KX_PYATTRIBUTE_SHORT_RW(name, min, max, clamp, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_RW_CHECK(name, min, max, clamp, object, field, function) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_RO(name, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name, min, max, clamp, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name, min, max, clamp, object, field, length, function) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } // SHORT_LIST -#define KX_PYATTRIBUTE_SHORT_LIST_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_LIST_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } - -#define KX_PYATTRIBUTE_INT_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_ARRAY_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_LIST_RW(name, min, max, clamp, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_LIST_RW_CHECK(name, min, max, clamp, object, field, length, function) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_LIST_RO(name, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } + +#define KX_PYATTRIBUTE_INT_RW(name, min, max, clamp, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_RW_CHECK(name, min, max, clamp, object, field, function) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_RO(name, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_ARRAY_RW(name, min, max, clamp, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name, min, max, clamp, object, field, length, function) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_ARRAY_RO(name, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } // INT_LIST -#define KX_PYATTRIBUTE_INT_LIST_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_LIST_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_LIST_RW(name, min, max, clamp, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_LIST_RW_CHECK(name, min, max, clamp, object, field, length, function) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_LIST_RO(name, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } // always clamp for float -#define KX_PYATTRIBUTE_FLOAT_RW(name,min,max,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name,min,max,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_RW(name, min, max, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name, min, max, object, field, function) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_RO(name, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } // field must be float[n], returns a sequence -#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name,min,max,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name, min, max, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name, min, max, object, field, length, function) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } // field must be float[n], returns a vector -#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW(name,min,max,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW_CHECK(name,min,max,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_VECTOR_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, length, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW(name, min, max, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW_CHECK(name, min, max, object, field, length, function) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_VECTOR_RO(name, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, length, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } // field must be float[n][n], returns a matrix -#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW(name,min,max,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW_CHECK(name,min,max,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_MATRIX_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, length, length, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW(name, min, max, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW_CHECK(name, min, max, object, field, length, function) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_MATRIX_RO(name, object, field, length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, length, length, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } // only for STR_String member -#define KX_PYATTRIBUTE_STRING_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } -#define KX_PYATTRIBUTE_STRING_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } -#define KX_PYATTRIBUTE_STRING_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } +#define KX_PYATTRIBUTE_STRING_RW(name, min, max, clamp, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } +#define KX_PYATTRIBUTE_STRING_RW_CHECK(name, min, max, clamp, object, field, function) \ + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } +#define KX_PYATTRIBUTE_STRING_RO(name, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } // only for char [] array -#define KX_PYATTRIBUTE_CHAR_RW(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } -#define KX_PYATTRIBUTE_CHAR_RW_CHECK(name,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } -#define KX_PYATTRIBUTE_CHAR_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } +#define KX_PYATTRIBUTE_CHAR_RW(name, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } +#define KX_PYATTRIBUTE_CHAR_RW_CHECK(name, object, field, function) \ + { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } +#define KX_PYATTRIBUTE_CHAR_RO(name, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } // for MT_Vector3 member -#define KX_PYATTRIBUTE_VECTOR_RW(name,min,max,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } -#define KX_PYATTRIBUTE_VECTOR_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } -#define KX_PYATTRIBUTE_VECTOR_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } - -#define KX_PYATTRIBUTE_RW_FUNCTION(name,object,getfunction,setfunction) \ +#define KX_PYATTRIBUTE_VECTOR_RW(name, min, max, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } +#define KX_PYATTRIBUTE_VECTOR_RW_CHECK(name, min, max, clamp, object, field, function) \ + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } +#define KX_PYATTRIBUTE_VECTOR_RO(name, object, field) \ + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } + +#define KX_PYATTRIBUTE_RW_FUNCTION(name, object, getfunction, setfunction) \ { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_RO_FUNCTION(name,object,getfunction) \ +#define KX_PYATTRIBUTE_RO_FUNCTION(name, object, getfunction) \ { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_ARRAY_RW_FUNCTION(name,object,length,getfunction,setfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0,f, false, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_ARRAY_RO_FUNCTION(name,object,length,getfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0,f, false, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_ARRAY_RW_FUNCTION(name, object, length, getfunction, setfunction) \ + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0, f, false, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_ARRAY_RO_FUNCTION(name, object, length, getfunction) \ + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0, f, false, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } /*------------------------------ @@ -614,7 +614,7 @@ public: /** enable/disable display of deprecation warnings */ static void SetDeprecationWarnings(bool ignoreDeprecationWarnings); /** Shows a deprecation warning */ - static void ShowDeprecationWarning_func(const char* method,const char* prop); + static void ShowDeprecationWarning_func(const char *method, const char *prop); static void ClearDeprecationWarning(); #endif diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp index 5ad5aedbd39..6a87d3ccb98 100644 --- a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp +++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp @@ -97,6 +97,11 @@ bool SCA_2DFilterActuator::Update() } +void SCA_2DFilterActuator::SetScene(SCA_IScene *scene) +{ + m_scene = scene; +} + void SCA_2DFilterActuator::SetShaderText(const char *text) { m_shaderText = text; diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.h b/source/gameengine/GameLogic/SCA_2DFilterActuator.h index a754d950859..4635a8ad9f8 100644 --- a/source/gameengine/GameLogic/SCA_2DFilterActuator.h +++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.h @@ -64,6 +64,8 @@ public: virtual ~SCA_2DFilterActuator(); virtual bool Update(); + void SetScene(SCA_IScene *scene); + virtual CValue* GetReplica(); }; #endif diff --git a/source/gameengine/GameLogic/SCA_PythonJoystick.cpp b/source/gameengine/GameLogic/SCA_PythonJoystick.cpp index ee792111705..8c0a0c5ae33 100644 --- a/source/gameengine/GameLogic/SCA_PythonJoystick.cpp +++ b/source/gameengine/GameLogic/SCA_PythonJoystick.cpp @@ -122,14 +122,14 @@ PyObject* SCA_PythonJoystick::pyattr_get_active_buttons(void *self_v, const KX_P { SCA_PythonJoystick* self = static_cast<SCA_PythonJoystick*>(self_v); - int button_index = self->m_joystick->GetNumberOfButtons(); + const int button_number = self->m_joystick->GetNumberOfButtons(); PyObject *list = PyList_New(0); PyObject *value; - for (int i=0; i < self->m_joystick->GetNumberOfButtons(); i++) { + for (int i=0; i < button_number; i++) { if (self->m_joystick->aButtonPressIsPositive(i)) { - value = PyLong_FromSsize_t(i); + value = PyLong_FromLong(i); PyList_Append(list, value); Py_DECREF(value); } diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp index b5c1c29238a..058454ca352 100644 --- a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp +++ b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp @@ -131,7 +131,15 @@ void GPC_Canvas::SetViewPort(int x1, int y1, int x2, int y2) glViewport(x1,y1,x2-x1 + 1,y2-y1 + 1); glScissor(x1,y1,x2-x1 + 1,y2-y1 + 1); -}; +} + +void GPC_Canvas::UpdateViewPort(int x1, int y1, int x2, int y2) +{ + m_viewport[0] = x1; + m_viewport[1] = y1; + m_viewport[2] = x2; + m_viewport[3] = y2; +} const int *GPC_Canvas::GetViewPort() { diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.h b/source/gameengine/GamePlayer/common/GPC_Canvas.h index ec5375c0e13..00c5911a8b4 100644 --- a/source/gameengine/GamePlayer/common/GPC_Canvas.h +++ b/source/gameengine/GamePlayer/common/GPC_Canvas.h @@ -155,6 +155,7 @@ public: ); void SetViewPort(int x1, int y1, int x2, int y2); + void UpdateViewPort(int x1, int y1, int x2, int y2); const int *GetViewPort(); void ClearColor(float r, float g, float b, float a); diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index 1dcc68c8e75..89d11515bb3 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -703,6 +703,8 @@ bool GPG_Application::startEngine(void) m_sceneconverter->SetMaterials(true); if (m_blenderglslmat && (m_globalSettings->matmode == GAME_MAT_GLSL)) m_sceneconverter->SetGLSLMaterials(true); + if (m_startScene->gm.flag & GAME_NO_MATERIAL_CACHING) + m_sceneconverter->SetCacheMaterials(false); KX_Scene* startscene = new KX_Scene(m_keyboard, m_mouse, diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 524a38a4c26..e42c2a74a8e 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -252,7 +252,7 @@ if(WITH_BULLET) ../Physics/Bullet ) list(APPEND INC - ../../../extern/bullet2/src + ${BULLET_INCLUDE_DIRS} ) add_definitions(-DUSE_BULLET) endif() diff --git a/source/gameengine/Ketsji/KX_CharacterWrapper.cpp b/source/gameengine/Ketsji/KX_CharacterWrapper.cpp index ce208f3a75f..64bbbb7d344 100644 --- a/source/gameengine/Ketsji/KX_CharacterWrapper.cpp +++ b/source/gameengine/Ketsji/KX_CharacterWrapper.cpp @@ -45,6 +45,8 @@ PyTypeObject KX_CharacterWrapper::Type = { PyAttributeDef KX_CharacterWrapper::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("onGround", KX_CharacterWrapper, pyattr_get_onground), KX_PYATTRIBUTE_RW_FUNCTION("gravity", KX_CharacterWrapper, pyattr_get_gravity, pyattr_set_gravity), + KX_PYATTRIBUTE_RW_FUNCTION("maxJumps", KX_CharacterWrapper, pyattr_get_max_jumps, pyattr_set_max_jumps), + KX_PYATTRIBUTE_RO_FUNCTION("jumpCount", KX_CharacterWrapper, pyattr_get_jump_count), { NULL } //Sentinel }; @@ -77,6 +79,35 @@ int KX_CharacterWrapper::pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_D return PY_SET_ATTR_SUCCESS; } +PyObject *KX_CharacterWrapper::pyattr_get_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_CharacterWrapper* self = static_cast<KX_CharacterWrapper*>(self_v); + + return PyLong_FromLong(self->m_character->GetMaxJumps()); +} + +int KX_CharacterWrapper::pyattr_set_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_CharacterWrapper* self = static_cast<KX_CharacterWrapper*>(self_v); + long param = PyLong_AsLong(value); + + if (param == -1) + { + PyErr_SetString(PyExc_ValueError, "KX_CharacterWrapper.maxJumps: expected an integer"); + return PY_SET_ATTR_FAIL; + } + + self->m_character->SetMaxJumps((int)param); + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_CharacterWrapper::pyattr_get_jump_count(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_CharacterWrapper* self = static_cast<KX_CharacterWrapper*>(self_v); + + return PyLong_FromLong(self->m_character->GetJumpCount()); +} + PyMethodDef KX_CharacterWrapper::Methods[] = { KX_PYMETHODTABLE_NOARGS(KX_CharacterWrapper, jump), {NULL,NULL} //Sentinel diff --git a/source/gameengine/Ketsji/KX_CharacterWrapper.h b/source/gameengine/Ketsji/KX_CharacterWrapper.h index 3b0058aca6f..f1c977f4e5d 100644 --- a/source/gameengine/Ketsji/KX_CharacterWrapper.h +++ b/source/gameengine/Ketsji/KX_CharacterWrapper.h @@ -26,6 +26,9 @@ public: static PyObject* pyattr_get_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_jump_count(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); #endif // WITH_PYTHON private: diff --git a/source/gameengine/Ketsji/KX_ISceneConverter.h b/source/gameengine/Ketsji/KX_ISceneConverter.h index 7c1d593a81e..616895a8269 100644 --- a/source/gameengine/Ketsji/KX_ISceneConverter.h +++ b/source/gameengine/Ketsji/KX_ISceneConverter.h @@ -89,6 +89,10 @@ public: virtual void SetGLSLMaterials(bool val) =0; virtual bool GetGLSLMaterials()=0; + // cache materials during conversion + virtual void SetCacheMaterials(bool val) =0; + virtual bool GetCacheMaterials()=0; + virtual struct Scene* GetBlenderSceneForName(const STR_String& name)=0; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 6638b711a1b..f0d5d5c6685 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -1167,7 +1167,7 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) m_rasterizer->SetDrawingMode(RAS_IRasterizer::KX_SHADOW); /* binds framebuffer object, sets up camera .. */ - light->BindShadowBuffer(m_rasterizer, cam, camtrans); + light->BindShadowBuffer(m_rasterizer, m_canvas, cam, camtrans); /* update scene */ scene->CalculateVisibleMeshes(m_rasterizer, cam, light->GetShadowLayer()); diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index cf58d18838a..5414a4df0f8 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -236,7 +236,7 @@ int KX_LightObject::GetShadowLayer() return 0; } -void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_Transform& camtrans) +void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, RAS_ICanvas *canvas, KX_Camera *cam, MT_Transform& camtrans) { GPULamp *lamp; float viewmat[4][4], winmat[4][4]; @@ -246,6 +246,9 @@ void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_T lamp = GetGPULamp(); GPU_lamp_shadow_buffer_bind(lamp, viewmat, &winsize, winmat); + /* GPU_lamp_shadow_buffer_bind() changes the viewport, so update the canvas */ + canvas->UpdateViewPort(0, 0, winsize, winsize); + /* setup camera transformation */ MT_Matrix4x4 modelviewmat((float*)viewmat); MT_Matrix4x4 projectionmat((float*)winmat); diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h index 52f076c772a..f88fc7f6a1b 100644 --- a/source/gameengine/Ketsji/KX_Light.h +++ b/source/gameengine/Ketsji/KX_Light.h @@ -64,7 +64,7 @@ public: struct GPULamp *GetGPULamp(); bool HasShadowBuffer(); int GetShadowLayer(); - void BindShadowBuffer(class RAS_IRasterizer *ras, class KX_Camera *cam, class MT_Transform& camtrans); + void BindShadowBuffer(class RAS_IRasterizer *ras, class RAS_ICanvas *canvas, class KX_Camera *cam, class MT_Transform& camtrans); void UnbindShadowBuffer(class RAS_IRasterizer *ras); struct Image *GetTextureImage(short texslot); void Update(); diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 0d39eb844b5..02995a53954 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -1921,6 +1921,9 @@ PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur PySys_SetObject("argv", py_argv); Py_DECREF(py_argv); } + + /* Initialize thread support (also acquires lock) */ + PyEval_InitThreads(); bpy_import_init(PyEval_GetBuiltins()); diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 72be5f57b95..55c9ff5307f 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -47,6 +47,7 @@ //#include "SCA_AlwaysEventManager.h" //#include "SCA_RandomEventManager.h" //#include "KX_RayEventManager.h" +#include "SCA_2DFilterActuator.h" #include "KX_TouchEventManager.h" #include "SCA_KeyboardManager.h" #include "SCA_MouseManager.h" @@ -227,7 +228,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, } #ifdef WITH_PYTHON - m_attr_dict = PyDict_New(); /* new ref */ + m_attr_dict = NULL; m_draw_call_pre = NULL; m_draw_call_post = NULL; #endif @@ -287,9 +288,11 @@ KX_Scene::~KX_Scene() } #ifdef WITH_PYTHON - PyDict_Clear(m_attr_dict); - /* Py_CLEAR: Py_DECREF's and NULL's */ - Py_CLEAR(m_attr_dict); + if (m_attr_dict) { + PyDict_Clear(m_attr_dict); + /* Py_CLEAR: Py_DECREF's and NULL's */ + Py_CLEAR(m_attr_dict); + } /* these may be NULL but the macro checks */ Py_CLEAR(m_draw_call_pre); @@ -1779,6 +1782,11 @@ static void MergeScene_LogicBrick(SCA_ILogicBrick* brick, KX_Scene *to) if (sensor) { sensor->Replace_EventManager(logicmgr); } + + SCA_2DFilterActuator *filter_actuator = dynamic_cast<class SCA_2DFilterActuator*>(brick); + if (filter_actuator) { + filter_actuator->SetScene(to); + } } #ifdef USE_BULLET @@ -2062,6 +2070,9 @@ static PyObject *Map_GetItem(PyObject *self_v, PyObject *item) PyErr_SetString(PyExc_SystemError, "val = scene[key]: KX_Scene, "BGE_PROXY_ERROR_MSG); return NULL; } + + if (!self->m_attr_dict) + self->m_attr_dict = PyDict_New(); if (self->m_attr_dict && (pyconvert=PyDict_GetItem(self->m_attr_dict, item))) { @@ -2089,7 +2100,10 @@ static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) PyErr_SetString(PyExc_SystemError, "scene[key] = value: KX_Scene, "BGE_PROXY_ERROR_MSG); return -1; } - + + if (!self->m_attr_dict) + self->m_attr_dict = PyDict_New(); + if (val==NULL) { /* del ob["key"] */ int del= 0; @@ -2133,7 +2147,10 @@ static int Seq_Contains(PyObject *self_v, PyObject *value) PyErr_SetString(PyExc_SystemError, "val in scene: KX_Scene, "BGE_PROXY_ERROR_MSG); return -1; } - + + if (!self->m_attr_dict) + self->m_attr_dict = PyDict_New(); + if (self->m_attr_dict && PyDict_GetItem(self->m_attr_dict, value)) return 1; diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt index 43b1bfe7468..afb166eee57 100644 --- a/source/gameengine/Physics/Bullet/CMakeLists.txt +++ b/source/gameengine/Physics/Bullet/CMakeLists.txt @@ -44,7 +44,6 @@ set(INC ) set(INC_SYS - ../../../../extern/bullet2/src ${GLEW_INCLUDE_PATH} ${PYTHON_INCLUDE_DIRS} ) @@ -60,6 +59,9 @@ set(SRC ) if(WITH_BULLET) + list(APPEND INC + ${BULLET_INCLUDE_DIRS} + ) add_definitions(-DUSE_BULLET) endif() diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index a1b30ccb001..cf96f22a345 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -68,6 +68,53 @@ float gAngularSleepingTreshold; btVector3 startVel(0,0,0);//-10000); +BlenderBulletCharacterController::BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight) + : btKinematicCharacterController(ghost,shape,stepHeight,2), + m_motionState(motionState), + m_jumps(0), + m_maxJumps(1) +{ +} + +void BlenderBulletCharacterController::updateAction(btCollisionWorld *collisionWorld, btScalar dt) +{ + btKinematicCharacterController::updateAction(collisionWorld,dt); + m_motionState->setWorldTransform(getGhostObject()->getWorldTransform()); +} + +int BlenderBulletCharacterController::getMaxJumps() const +{ + return m_maxJumps; +} + +void BlenderBulletCharacterController::setMaxJumps(int maxJumps) +{ + m_maxJumps = maxJumps; +} + +int BlenderBulletCharacterController::getJumpCount() const +{ + return m_jumps; +} + +bool BlenderBulletCharacterController::canJump() const +{ + return onGround() || m_jumps < m_maxJumps; +} + +void BlenderBulletCharacterController::jump() +{ + if (onGround()) + m_jumps = 0; + + if (!canJump()) + return; + + m_verticalVelocity = m_jumpSpeed; + m_wasJumping = true; + m_jumps++; +} + CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) :m_cci(ci) { @@ -154,25 +201,6 @@ public: }; -class BlenderBulletCharacterController : public btKinematicCharacterController -{ -private: - btMotionState* m_motionState; - -public: - BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight) - : btKinematicCharacterController(ghost,shape,stepHeight,2), - m_motionState(motionState) - { - } - - virtual void updateAction(btCollisionWorld *collisionWorld, btScalar dt) - { - btKinematicCharacterController::updateAction(collisionWorld,dt); - m_motionState->setWorldTransform(getGhostObject()->getWorldTransform()); - } -}; - btRigidBody* CcdPhysicsController::GetRigidBody() { return btRigidBody::upcast(m_object); @@ -463,9 +491,6 @@ bool CcdPhysicsController::CreateCharacterController() m_characterController = new BlenderBulletCharacterController(m_bulletMotionState,(btPairCachingGhostObject*)m_object,(btConvexShape*)m_collisionShape,m_cci.m_stepHeight); - PHY__Vector3 gravity; - m_cci.m_physicsEnv->getGravity(gravity); - m_characterController->setGravity(-gravity.m_vec[2]); // need positive gravity m_characterController->setJumpSpeed(m_cci.m_jumpSpeed); m_characterController->setFallSpeed(m_cci.m_fallSpeed); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 6df5c85f5c0..b151c2f6b59 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -391,10 +391,33 @@ struct CcdConstructionInfo }; - class btRigidBody; class btCollisionObject; class btSoftBody; +class btPairCachingGhostObject; + +class BlenderBulletCharacterController : public btKinematicCharacterController +{ +private: + btMotionState* m_motionState; + int m_jumps; + int m_maxJumps; + +public: + BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight); + + virtual void updateAction(btCollisionWorld *collisionWorld, btScalar dt); + + int getMaxJumps() const; + + void setMaxJumps(int maxJumps); + + int getJumpCount() const; + + virtual bool canJump() const; + + virtual void jump(); +}; ///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution. class CcdPhysicsController : public PHY_IPhysicsController diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index 486411d7e35..cadba97023e 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -270,10 +270,10 @@ public: class CharacterWrapper : public PHY_ICharacter { private: - btKinematicCharacterController* m_controller; + BlenderBulletCharacterController* m_controller; public: - CharacterWrapper(btKinematicCharacterController* cont) + CharacterWrapper(BlenderBulletCharacterController* cont) : m_controller(cont) {} @@ -295,6 +295,21 @@ public: { m_controller->setGravity(gravity); } + + virtual int GetMaxJumps() + { + return m_controller->getMaxJumps(); + } + + virtual void SetMaxJumps(int maxJumps) + { + m_controller->setMaxJumps(maxJumps); + } + + virtual int GetJumpCount() + { + return m_controller->getJumpCount(); + } }; class CcdOverlapFilterCallBack : public btOverlapFilterCallback @@ -2320,7 +2335,7 @@ PHY_ICharacter* CcdPhysicsEnvironment::getCharacterController(KX_GameObject *ob) { CcdPhysicsController* controller = (CcdPhysicsController*)ob->GetPhysicsController()->GetUserData(); if (controller->GetCharacterController()) - return new CharacterWrapper(controller->GetCharacterController()); + return new CharacterWrapper((BlenderBulletCharacterController*)controller->GetCharacterController()); return NULL; } diff --git a/source/gameengine/Physics/common/PHY_ICharacter.h b/source/gameengine/Physics/common/PHY_ICharacter.h index e2fc5e45125..63f6c0bd18a 100644 --- a/source/gameengine/Physics/common/PHY_ICharacter.h +++ b/source/gameengine/Physics/common/PHY_ICharacter.h @@ -21,6 +21,11 @@ public: virtual float GetGravity()= 0; virtual void SetGravity(float gravity)= 0; + + virtual int GetMaxJumps()= 0; + virtual void SetMaxJumps(int maxJumps)= 0; + + virtual int GetJumpCount()= 0; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_ICharacter") diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp index cf869e71945..ab0f62c84c7 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp @@ -428,8 +428,7 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) // reverting to texunit 0, without this we get bug [#28462] glActiveTextureARB(GL_TEXTURE0); - - glViewport(rect.GetLeft(), rect.GetBottom(), rect_width, rect_height); + canvas->SetViewPort(0, 0, rect_width-1, rect_height-1); glDisable(GL_DEPTH_TEST); // in case the previous material was wire @@ -466,7 +465,7 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) } glEnable(GL_DEPTH_TEST); - glViewport(viewport[0],viewport[1],viewport[2],viewport[3]); + canvas->SetViewPort(viewport[0],viewport[1],viewport[2],viewport[3]); EndShaderProgram(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.h b/source/gameengine/Rasterizer/RAS_ICanvas.h index 60b9f052075..63ad7892aa5 100644 --- a/source/gameengine/Rasterizer/RAS_ICanvas.h +++ b/source/gameengine/Rasterizer/RAS_ICanvas.h @@ -178,7 +178,19 @@ public: SetViewPort( int x1, int y1, int x2, int y2 - ) = 0; + ) = 0; + + /** + * Update the Canvas' viewport (used when the viewport changes without using SetViewPort() + * eg: Shadow buffers and FBOs + */ + + virtual + void + UpdateViewPort( + int x1, int y1, + int x2, int y2 + ) = 0; /** * Get the visible viewport diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h index 0eddde7c203..558850a9173 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h @@ -51,7 +51,6 @@ typedef std::map<DerivedMesh*, RAS_ListSlots*> RAS_DerivedMeshLists; class RAS_ListRasterizer : public RAS_OpenGLRasterizer { - bool mUseVertexArrays; bool mATI; RAS_ArrayLists mArrayLists; RAS_DerivedMeshLists mDerivedMeshLists; diff --git a/source/tests/check_deprecated.py b/source/tests/check_deprecated.py index c5c7bdcdcb0..bb9fcd818d2 100644 --- a/source/tests/check_deprecated.py +++ b/source/tests/check_deprecated.py @@ -31,12 +31,12 @@ SKIP_DIRS = ("extern", def is_c_header(filename): ext = splitext(filename)[1] - return (ext in (".h", ".hpp", ".hxx")) + return (ext in {".h", ".hpp", ".hxx", ".hh"}) def is_c(filename): ext = splitext(filename)[1] - return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc", ".cc", ".inl")) + return (ext in {".c", ".cpp", ".cxx", ".m", ".mm", ".rc", ".cc", ".inl"}) def is_c_any(filename): |