diff --git a/source/Makefile b/source/Makefile index f0273954440..ec78763506a 100644 --- a/source/Makefile +++ b/source/Makefile @@ -83,7 +83,6 @@ PYPLAYERLIB ?= $(PYLIB) GRPLIB += $(NAN_SOUNDSYSTEM)/lib/$(DEBUG_DIR)libSoundSystem.a GRPLIB += $(NAN_GHOST)/lib/$(DEBUG_DIR)libghost.a GRPLIB += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a - GRPLIB += $(OCGDIR)/blender/img/$(DEBUG_DIR)libimg.a GRPLIB += $(OCGDIR)/blender/render/$(DEBUG_DIR)librender.a GRPLIB += $(OCGDIR)/blender/radiosity/$(DEBUG_DIR)libradiosity.a GRPLIB += $(NAN_OPENNL)/lib/$(DEBUG_DIR)libopennl.a diff --git a/source/blender/Makefile b/source/blender/Makefile index ebae59ef0de..5888186fcfc 100644 --- a/source/blender/Makefile +++ b/source/blender/Makefile @@ -34,7 +34,7 @@ include nan_definitions.mk DIRS = blenloader readblenfile -DIRS += avi imbuf img render radiosity blenlib blenkernel blenpluginapi +DIRS += avi imbuf render radiosity blenlib blenkernel blenpluginapi DIRS += makesdna src yafray DIRS += python diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h new file mode 100644 index 00000000000..89c6a3adf2a --- /dev/null +++ b/source/blender/blenkernel/BKE_brush.h @@ -0,0 +1,57 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * General operations for brushes. + */ + +#ifndef BKE_BRUSH_H +#define BKE_BRUSH_H + +struct ID; +struct Brush; + +struct Brush *add_brush(char *name); +struct Brush *copy_brush(struct Brush *brush); +void make_local_brush(struct Brush *brush); +void free_brush(struct Brush *brush); + +/* implementation of blending modes for use by different paint modes */ +void brush_blend_rgb(char *outcol, char *col1, char *col2, int fac, short mode); + +/* functions for brush datablock browsing used by different paint panels */ +int brush_set_nr(struct Brush **current_brush, int nr); +int brush_delete(struct Brush **current_brush); +void brush_toggle_fake_user(struct Brush *brush); +int brush_clone_image_delete(struct Brush *brush); +int brush_clone_image_set_nr(struct Brush *brush, int nr); +void brush_check_exists(struct Brush **brush); + +#endif + diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 1512ea28d4a..d385e357365 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -75,6 +75,7 @@ typedef struct Main { ListBase armature; ListBase action; ListBase nodetree; + ListBase brush; } Main; diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c new file mode 100644 index 00000000000..ca9d1154024 --- /dev/null +++ b/source/blender/blenkernel/intern/brush.c @@ -0,0 +1,317 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_image_types.h" +#include "DNA_scene_types.h" + +#include "BLI_blenlib.h" + +#include "BKE_brush.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" + +Brush *add_brush(char *name) +{ + Brush *brush; + + brush= alloc_libblock(&G.main->brush, ID_BR, name); + + brush->rgb[0]= 1.0f; + brush->rgb[1]= 1.0f; + brush->rgb[2]= 1.0f; + brush->alpha= 0.2f; + brush->size= 25; + brush->timing= 100.0f; + brush->innerradius= 0.5f; + brush->clone.alpha= 0.5; + + /* enable fake user by default */ + brush_toggle_fake_user(brush); + + return brush; +} + +Brush *copy_brush(Brush *brush) +{ + Brush *brushn; + + brushn= copy_libblock(brush); + + /* enable fake user by default */ + if (!(brushn->id.flag & LIB_FAKEUSER)) + brush_toggle_fake_user(brushn); + + return brushn; +} + +/* not brush itself */ +void free_brush(Brush *brush) +{ +} + +void make_local_brush(Brush *brush) +{ + /* don't forget: add stuff texture make local once texture bruses are added*/ + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + Brush *brushn; + Scene *scene; + int local= 0, lib= 0; + + if(brush->id.lib==0) return; + + if(brush->clone.image) { + /* special case: ima always local immediately */ + brush->clone.image->id.lib= 0; + brush->clone.image->id.flag= LIB_LOCAL; + new_id(0, (ID *)brush->clone.image, 0); + } + + for(scene= G.main->scene.first; scene; scene=scene->id.next) + if(scene->toolsettings->imapaint.brush==brush) { + if(scene->id.lib) lib= 1; + else local= 1; + } + + if(local && lib==0) { + brush->id.lib= 0; + brush->id.flag= LIB_LOCAL; + new_id(0, (ID *)brush, 0); + + /* enable fake user by default */ + if (!(brush->id.flag & LIB_FAKEUSER)) + brush_toggle_fake_user(brush); + } + else if(local && lib) { + brushn= copy_brush(brush); + brushn->id.us= 1; /* only keep fake user */ + brushn->id.flag |= LIB_FAKEUSER; + + for(scene= G.main->scene.first; scene; scene=scene->id.next) + if(scene->toolsettings->imapaint.brush==brush) + if(scene->id.lib==0) { + scene->toolsettings->imapaint.brush= brushn; + brushn->id.us++; + brush->id.us--; + } + } +} + +static void brush_blend_mix(char *cp, char *cp1, char *cp2, int fac) +{ + /* this and other blending modes previously used >>8 instead of /255. both + are not equivalent (>>8 is /256), and the former results in rounding + errors that can turn colors black fast */ + int mfac= 255-fac; + cp[0]= (mfac*cp1[0]+fac*cp2[0])/255; + cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; + cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; +} + +static void brush_blend_add(char *cp, char *cp1, char *cp2, int fac) +{ + int temp; + + temp= cp1[0] + ((fac*cp2[0])/255); + if(temp>254) cp[0]= 255; else cp[0]= temp; + temp= cp1[1] + ((fac*cp2[1])/255); + if(temp>254) cp[1]= 255; else cp[1]= temp; + temp= cp1[2] + ((fac*cp2[2])/255); + if(temp>254) cp[2]= 255; else cp[2]= temp; +} + +static void brush_blend_sub(char *cp, char *cp1, char *cp2, int fac) +{ + int temp; + + temp= cp1[0] - ((fac*cp2[0])/255); + if(temp<0) cp[0]= 0; else cp[0]= temp; + temp= cp1[1] - ((fac*cp2[1])/255); + if(temp<0) cp[1]= 0; else cp[1]= temp; + temp= cp1[2] - ((fac*cp2[2])/255); + if(temp<0) cp[2]= 0; else cp[2]= temp; +} + +static void brush_blend_mul(char *cp, char *cp1, char *cp2, int fac) +{ + int mfac= 255-fac; + + /* first mul, then blend the fac */ + cp[0]= (mfac*cp1[0] + fac*((cp2[0]*cp1[0])/255))/255; + cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])/255))/255; + cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])/255))/255; +} + +static void brush_blend_lighten(char *cp, char *cp1, char *cp2, int fac) +{ + /* See if are lighter, if so mix, else dont do anything. + if the paint col is darker then the original, then ignore */ + if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) { + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + else + brush_blend_mix(cp, cp1, cp2, fac); +} + +static void brush_blend_darken(char *cp, char *cp1, char *cp2, int fac) +{ + /* See if were darker, if so mix, else dont do anything. + if the paint col is brighter then the original, then ignore */ + if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) { + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + else + brush_blend_mix(cp, cp1, cp2, fac); +} + +void brush_blend_rgb(char *outcol, char *col1, char *col2, int fac, short mode) +{ + if (fac==0) { + outcol[0]= col1[0]; + outcol[1]= col1[1]; + outcol[2]= col1[2]; + } + else { + switch (mode) { + case BRUSH_BLEND_MIX: + brush_blend_mix(outcol, col1, col2, fac); break; + case BRUSH_BLEND_ADD: + brush_blend_add(outcol, col1, col2, fac); break; + case BRUSH_BLEND_SUB: + brush_blend_sub(outcol, col1, col2, fac); break; + case BRUSH_BLEND_MUL: + brush_blend_mul(outcol, col1, col2, fac); break; + case BRUSH_BLEND_LIGHTEN: + brush_blend_lighten(outcol, col1, col2, fac); break; + case BRUSH_BLEND_DARKEN: + brush_blend_darken(outcol, col1, col2, fac); break; + default: + brush_blend_mix(outcol, col1, col2, fac); break; + } + } +} + +int brush_set_nr(Brush **current_brush, int nr) +{ + ID *idtest, *id; + + id= (ID*)(*current_brush); + idtest= (ID*)BLI_findlink(&G.main->brush, nr-1); + + if(idtest==0) { /* new brush */ + if(id) idtest= (ID *)copy_brush((Brush *)id); + else idtest= (ID *)add_brush("Brush"); + idtest->us--; + } + if(idtest!=id) { + brush_delete(current_brush); + *current_brush= (Brush *)idtest; + id_us_plus(idtest); + + return 1; + } + + return 0; +} + +int brush_delete(Brush **current_brush) +{ + if (*current_brush) { + (*current_brush)->id.us--; + *current_brush= NULL; + return 1; + } + + return 0; +} + +void brush_toggle_fake_user(Brush *brush) +{ + ID *id= (ID*)brush; + if(id) { + if(id->flag & LIB_FAKEUSER) { + id->flag -= LIB_FAKEUSER; + id->us--; + } else { + id->flag |= LIB_FAKEUSER; + id_us_plus(id); + } + } +} + +int brush_clone_image_set_nr(Brush *brush, int nr) +{ + if(brush && nr > 0) { + Image *ima= (Image*)BLI_findlink(&G.main->image, nr-1); + + if(ima) { + brush_clone_image_delete(brush); + brush->clone.image= ima; + id_us_plus(&ima->id); + brush->clone.offset[0]= brush->clone.offset[1]= 0.0f; + + return 1; + } + } + + return 0; +} + +int brush_clone_image_delete(Brush *brush) +{ + if (brush && brush->clone.image) { + brush->clone.image->id.us--; + brush->clone.image= NULL; + return 1; + } + + return 0; +} + +void brush_check_exists(Brush **brush) +{ + if(*brush==NULL) + brush_set_nr(brush, 1); +} + diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 6992f2b2918..5628e4bc491 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -77,6 +77,7 @@ #include "DNA_node_types.h" #include "DNA_nla_types.h" #include "DNA_effect_types.h" +#include "DNA_brush_types.h" #include "BLI_blenlib.h" #include "BLI_dynstr.h" @@ -108,6 +109,7 @@ #include "BKE_action.h" #include "BKE_node.h" #include "BKE_effect.h" +#include "BKE_brush.h" #include "BPI_script.h" @@ -193,6 +195,8 @@ ListBase *wich_libbase(Main *mainlib, short type) return &(mainlib->action); case ID_NT: return &(mainlib->nodetree); + case ID_BR: + return &(mainlib->brush); } return 0; } @@ -233,12 +237,13 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[21]= &(main->sound); lb[22]= &(main->group); lb[23]= &(main->nodetree); + lb[24]= &(main->brush); - lb[24]= samples; - lb[25]= &(main->script); - lb[26]= NULL; + lb[25]= samples; + lb[26]= &(main->script); + lb[27]= NULL; - return 26; + return 27; } /* *********** ALLOC AND FREE ***************** @@ -332,7 +337,10 @@ static ID *alloc_libblock_notest(short type) id = MEM_callocN(sizeof(bAction), "action"); break; case ID_NT: - id = MEM_callocN(sizeof(bNodeTree), "action"); + id = MEM_callocN(sizeof(bNodeTree), "nodetree"); + break; + case ID_BR: + id = MEM_callocN(sizeof(Brush), "brush"); break; } return id; @@ -477,6 +485,9 @@ void free_libblock(ListBase *lb, void *idv) case ID_NT: ntreeFreeTree((bNodeTree *)id); break; + case ID_BR: + free_brush((Brush *)id); + break; } BLI_remlink(lb, id); diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index 2da43013318..a16bd5a3972 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -81,6 +81,7 @@ typedef struct { static IDType idtypes[]= { { ID_AC, "Action", IDTYPE_FLAGS_ISLINKABLE}, { ID_AR, "Armature", IDTYPE_FLAGS_ISLINKABLE}, + { ID_BR, "Brush", IDTYPE_FLAGS_ISLINKABLE}, { ID_CA, "Camera", IDTYPE_FLAGS_ISLINKABLE}, { ID_CU, "Curve", IDTYPE_FLAGS_ISLINKABLE}, { ID_GR, "Group", IDTYPE_FLAGS_ISLINKABLE}, diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 51dfc927251..17bf34f6f45 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -58,6 +58,7 @@ #include "DNA_armature_types.h" #include "DNA_ID.h" #include "DNA_actuator_types.h" +#include "DNA_brush_types.h" #include "DNA_camera_types.h" #include "DNA_color_types.h" #include "DNA_controller_types.h" @@ -1182,6 +1183,28 @@ static void test_pointer_array(FileData *fd, void **mat) } } +/* ************ READ BRUSH *************** */ + +/* library brush linking after fileread */ +static void lib_link_brush(FileData *fd, Main *main) +{ + Brush *brush; + + /* only link ID pointers */ + for(brush= main->brush.first; brush; brush= brush->id.next) { + if(brush->id.flag & LIB_NEEDLINK) { + brush->id.flag -= LIB_NEEDLINK; + /* nothing to do yet - until brush gets textures */ + } + } +} + +/* brush itself has been read! */ +static void direct_link_brush(FileData *fd, Brush *brush) +{ + /* nothing to do yet - until brush gets textures */ +} + /* ************ READ CurveMapping *************** */ /* cuma itself has been read! */ @@ -2639,6 +2662,8 @@ static void lib_link_scene(FileData *fd, Main *main) sce->world= newlibadr_us(fd, sce->id.lib, sce->world); sce->set= newlibadr(fd, sce->id.lib, sce->set); sce->ima= newlibadr_us(fd, sce->id.lib, sce->ima); + sce->toolsettings->imapaint.brush= + newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.brush); base= sce->base.first; while(base) { @@ -3471,6 +3496,8 @@ static char *dataname(short id_code) case ID_TXT : return "Data from TXT"; case ID_SO: return "Data from SO"; case ID_SAMPLE: return "Data from SAMPLE"; + case ID_NT: return "Data from NT"; + case ID_BR: return "Data from BR"; } return "Data from Lib Block"; @@ -3604,6 +3631,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID case ID_NT: direct_link_nodetree(fd, (bNodeTree*)id); break; + case ID_BR: + direct_link_brush(fd, (Brush*)id); + break; } oldnewmap_free_unused(fd->datamap); @@ -5555,6 +5585,7 @@ static void lib_link_all(FileData *fd, Main *main) lib_link_vfont(fd, main); lib_link_screen_sequence_ipos(main); lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */ + lib_link_brush(fd, main); lib_link_mesh(fd, main); /* as last: tpage images with users at zero */ @@ -5769,6 +5800,11 @@ static void expand_texture(FileData *fd, Main *mainvar, Tex *tex) expand_doit(fd, mainvar, tex->ipo); } +static void expand_brush(FileData *fd, Main *mainvar, Brush *brush) +{ + /* nothing to do yet - until brush gets texture */ +} + static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree) { bNode *node; @@ -6232,6 +6268,9 @@ static void expand_main(FileData *fd, Main *mainvar) case ID_NT: expand_nodetree(fd, mainvar, (bNodeTree *)id); break; + case ID_BR: + expand_brush(fd, mainvar, (Brush *)id); + break; case ID_IP: expand_ipo(fd, mainvar, (Ipo *)id); break; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ca7f75526dc..e3a67da94c3 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -105,6 +105,7 @@ Important to know is that 'streaming' has been added to files, for Blender Publi #include "DNA_armature_types.h" #include "DNA_action_types.h" #include "DNA_actuator_types.h" +#include "DNA_brush_types.h" #include "DNA_controller_types.h" #include "DNA_curve_types.h" #include "DNA_constraint_types.h" @@ -1592,6 +1593,15 @@ static void write_nodetrees(WriteData *wd, ListBase *idbase) } } +static void write_brushes(WriteData *wd, ListBase *idbase) +{ + Brush *brush; + + for(brush=idbase->first; brush; brush= brush->id.next) + if (brush->id.us>0 || wd->current) + writestruct(wd, ID_BR, "Brush", 1, brush); +} + static void write_global(WriteData *wd) { FileGlobal fg; @@ -1650,6 +1660,7 @@ static int write_file_handle(int handle, MemFile *compare, MemFile *current, int write_textures (wd, &G.main->tex); write_meshs (wd, &G.main->mesh); write_nodetrees(wd, &G.main->nodetree); + write_brushes (wd, &G.main->brush); write_libraries(wd, G.main->next); write_global(wd); diff --git a/source/blender/include/BDR_editface.h b/source/blender/include/BDR_editface.h index abce31796db..d46f05667ba 100644 --- a/source/blender/include/BDR_editface.h +++ b/source/blender/include/BDR_editface.h @@ -54,7 +54,6 @@ void face_borderselect(void); void uv_autocalc_tface(void); void set_faceselect(void); void set_texturepaint(void); -void face_draw(void); void get_same_uv(void); void seam_mark_clear_tface(short mode); diff --git a/source/blender/include/BDR_imagepaint.h b/source/blender/include/BDR_imagepaint.h index 5fd725ba934..8824c63071d 100644 --- a/source/blender/include/BDR_imagepaint.h +++ b/source/blender/include/BDR_imagepaint.h @@ -33,47 +33,11 @@ #ifndef BDR_IMAGEPAINT_H #define BDR_IMAGEPAINT_H -/* ImagePaint.current */ -#define IMAGEPAINT_BRUSH 0 -#define IMAGEPAINT_AIRBRUSH 1 -#define IMAGEPAINT_SOFTEN 2 -#define IMAGEPAINT_AUX1 3 -#define IMAGEPAINT_AUX2 4 -#define IMAGEPAINT_SMEAR 5 -#define IMAGEPAINT_CLONE 6 -#define IMAGEPAINT_TOOL_SIZE 7 - -/* ImagePaint.flag */ -#define IMAGEPAINT_DRAW_TOOL 1 -#define IMAGEPAINT_DRAW_TOOL_DRAWING 2 -#define IMAGEPAINT_DRAWING 4 -#define IMAGEPAINT_TORUS 8 -#define IMAGEPAINT_TIMED 16 - -typedef struct ImagePaintTool { - float rgba[4]; - int size; - float innerradius; - float timing; -} ImagePaintTool; - -typedef struct ImagePaint { - struct Clone { - Image *image; - float offset[2]; - float alpha; - } clone; - - ImagePaintTool tool[IMAGEPAINT_TOOL_SIZE]; - - short flag, current; -} ImagePaint; - -extern struct ImagePaint Gip; - void imagepaint_redraw_tool(void); void imagepaint_paint(short mousebutton); void imagepaint_pick(short mousebutton); +void texturepaint_paint(); + #endif /* BDR_IMAGEPAINT_H */ diff --git a/source/blender/include/blendef.h b/source/blender/include/blendef.h index 3dd0dda31d3..49873674917 100644 --- a/source/blender/include/blendef.h +++ b/source/blender/include/blendef.h @@ -317,6 +317,9 @@ #define B_SIMA_USE_ALPHA 371 #define B_SIMA_SHOW_ALPHA 372 #define B_SIMA_SHOW_ZBUF 373 +#define B_BRUSHBROWSE 374 +#define B_BRUSHDELETE 375 +#define B_BRUSHLOCAL 376 /* BUTS: 400 */ #define B_BUTSHOME 401 diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 7e71da6df76..f9a824eec27 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -129,6 +129,7 @@ typedef struct Library { #define ID_SCRIPT MAKE_ID2('P', 'Y') #define ID_FLUIDSIM MAKE_ID2('F', 'S') #define ID_NT MAKE_ID2('N', 'T') +#define ID_BR MAKE_ID2('B', 'R') /* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */ #define ID_SEQ MAKE_ID2('S', 'Q') diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h new file mode 100644 index 00000000000..ff578494339 --- /dev/null +++ b/source/blender/makesdna/DNA_brush_types.h @@ -0,0 +1,70 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef DNA_BRUSH_TYPES_H +#define DNA_BRUSH_TYPES_H + +#include "DNA_ID.h" + +typedef struct Brush { + ID id; + + short flag, blend; + int size; + float innerradius; + float timing; + + float rgb[3]; /* color */ + float alpha; /* opacity */ + + struct Clone { + struct Image *image; /* image for clone tool */ + float offset[2]; /* offset of clone image from canvas */ + float alpha; /* transparency for drawing of clone image */ + } clone; +} Brush; + +/* Brush.flag */ +#define BRUSH_AIRBRUSH 1 + +/* Brush.blend */ +#define BRUSH_BLEND_MIX 0 +#define BRUSH_BLEND_ADD 1 +#define BRUSH_BLEND_SUB 2 +#define BRUSH_BLEND_MUL 3 +#define BRUSH_BLEND_LIGHTEN 4 +#define BRUSH_BLEND_DARKEN 5 + +#define PAINT_TOOL_DRAW 0 +#define PAINT_TOOL_SOFTEN 1 +#define PAINT_TOOL_SMEAR 2 +#define PAINT_TOOL_CLONE 3 + +#endif + diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 33edf65454e..fe2b0cfa015 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -344,6 +344,12 @@ typedef struct ToolSettings { /* Select Group Threshold */ float select_thresh; + /* Image Paint */ + struct ImagePaintSettings { + struct Brush *brush; + short flag, tool; + int pad3; + } imapaint; } ToolSettings; typedef struct Scene { @@ -537,6 +543,13 @@ typedef struct Scene { #define FFMPEG_MULTIPLEX_AUDIO 1 #define FFMPEG_AUTOSPLIT_OUTPUT 2 +/* toolsettings->imagepaint_flag */ +#define IMAGEPAINT_TORUS 1 +#define IMAGEPAINT_DRAWING 2 +#define IMAGEPAINT_TIMED 4 +#define IMAGEPAINT_DRAW_TOOL 8 +#define IMAGEPAINT_DRAW_TOOL_DRAWING 16 + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 87174abab38..e7abcb1508e 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -125,6 +125,7 @@ char *includefiles[] = { "DNA_nla_types.h", "DNA_node_types.h", "DNA_color_types.h", + "DNA_brush_types.h", // if you add files here, please add them at the end // of makesdna.c (this file) as well @@ -1133,4 +1134,5 @@ int main(int argc, char ** argv) #include "DNA_nla_types.h" #include "DNA_node_types.h" #include "DNA_color_types.h" +#include "DNA_brush_types.h" /* end of list */ diff --git a/source/blender/src/Makefile b/source/blender/src/Makefile index dc7acc3d0d2..3bfb17dc586 100644 --- a/source/blender/src/Makefile +++ b/source/blender/src/Makefile @@ -69,7 +69,6 @@ CPPFLAGS += -I../blenlib CPPFLAGS += -I../python CPPFLAGS += -I../makesdna CPPFLAGS += -I../imbuf -CPPFLAGS += -I../img CPPFLAGS += -I../blenloader CPPFLAGS += -I.. CPPFLAGS += -I../../kernel/gen_system diff --git a/source/blender/src/SConscript b/source/blender/src/SConscript index 8c3de925450..fdd920e2713 100644 --- a/source/blender/src/SConscript +++ b/source/blender/src/SConscript @@ -11,7 +11,7 @@ incs += ' ../include #/intern/bmfont ../imbuf ../render/extern/include' incs += ' #/intern/bsp/extern ../radiosity/extern/include' incs += ' #/intern/decimation/extern ../blenloader ../python' incs += ' ../../kernel/gen_system #/intern/SoundSystem ../readstreamglue' -incs += ' ../img ../quicktime #/intern/elbeem/extern' +incs += ' ../quicktime #/intern/elbeem/extern' incs += ' #/intern/ghost #/intern/opennl/extern' incs += ' ' + env['BF_PYTHON_INC'] diff --git a/source/blender/src/drawimage.c b/source/blender/src/drawimage.c index 5486c093bcf..94d7ddd0b23 100644 --- a/source/blender/src/drawimage.c +++ b/source/blender/src/drawimage.c @@ -50,6 +50,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "DNA_brush_types.h" #include "DNA_camera_types.h" #include "DNA_color_types.h" #include "DNA_image_types.h" @@ -62,6 +63,7 @@ #include "DNA_space_types.h" #include "DNA_userdef_types.h" +#include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_utildefines.h" #include "BKE_global.h" @@ -92,9 +94,11 @@ #include "BIF_renderwin.h" #include "BIF_space.h" #include "BIF_screen.h" +#include "BIF_toolbox.h" #include "BIF_transform.h" #include "BSE_drawipo.h" +#include "BSE_filesel.h" #include "BSE_headerbuttons.h" #include "BSE_trans_types.h" #include "BSE_view.h" @@ -112,28 +116,30 @@ static unsigned char *alloc_alpha_clone_image(int *width, int *height) { + Brush *brush = G.scene->toolsettings->imapaint.brush; + Image *image; unsigned int size, alpha; unsigned char *rect, *cp; - if(!Gip.clone.image) + if(!brush || !brush->clone.image) + return NULL; + + image= brush->clone.image; + if(!image->ibuf) + load_image(image, IB_rect, G.sce, G.scene->r.cfra); + + if(!image->ibuf || !image->ibuf->rect) return NULL; - if(!Gip.clone.image->ibuf) - load_image(Gip.clone.image, IB_rect, G.sce, G.scene->r.cfra); - - if(!Gip.clone.image->ibuf || !Gip.clone.image->ibuf->rect) - return NULL; - - rect= MEM_dupallocN(Gip.clone.image->ibuf->rect); - + rect= MEM_dupallocN(image->ibuf->rect); if(!rect) return NULL; - *width= Gip.clone.image->ibuf->x; - *height= Gip.clone.image->ibuf->y; + *width= image->ibuf->x; + *height= image->ibuf->y; size= (*width)*(*height); - alpha= (unsigned char)255*Gip.clone.alpha; + alpha= (unsigned char)255*brush->clone.alpha; cp= rect; while(size-- > 0) { @@ -144,18 +150,6 @@ static unsigned char *alloc_alpha_clone_image(int *width, int *height) return rect; } -static void setcloneimage() -{ - if(G.sima->menunr > 0) { - Image *ima= (Image*)BLI_findlink(&G.main->image, G.sima->menunr-1); - - if(ima) { - Gip.clone.image= ima; - Gip.clone.offset[0]= Gip.clone.offset[0]= 0.0; - } - } -} - static int image_preview_active(ScrArea *sa, float *xim, float *yim) { SpaceImage *sima= sa->spacedata.first; @@ -692,27 +686,30 @@ static void draw_image_view_icon(void) static void draw_image_view_tool(void) { - ImagePaintTool *tool = &Gip.tool[Gip.current]; + ToolSettings *settings= G.scene->toolsettings; + Brush *brush= settings->imapaint.brush; short mval[2]; float radius; int draw= 0; - if(Gip.flag & IMAGEPAINT_DRAWING) { - if(Gip.flag & IMAGEPAINT_DRAW_TOOL_DRAWING) + if(brush) { + if(settings->imapaint.flag & IMAGEPAINT_DRAWING) { + if(settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL_DRAWING) + draw= 1; + } + else if(settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL) draw= 1; - } - else if(Gip.flag & IMAGEPAINT_DRAW_TOOL) - draw= 1; - - if(draw) { - getmouseco_areawin(mval); + + if(draw) { + getmouseco_areawin(mval); - radius= tool->size*G.sima->zoom/2; - fdrawXORcirc(mval[0], mval[1], radius); - - if (tool->innerradius != 1.0) { - radius *= tool->innerradius; + radius= brush->size*G.sima->zoom/2; fdrawXORcirc(mval[0], mval[1], radius); + + if (brush->innerradius != 1.0) { + radius *= brush->innerradius; + fdrawXORcirc(mval[0], mval[1], radius); + } } } } @@ -845,6 +842,8 @@ static void image_editvertex_buts(uiBlock *block) void do_imagebuts(unsigned short event) { + ToolSettings *settings= G.scene->toolsettings; + switch(event) { case B_TRANS_IMAGE: image_editvertex_buts(NULL); @@ -884,13 +883,15 @@ void do_imagebuts(unsigned short event) break; case B_SIMACLONEBROWSE: - setcloneimage(); - allqueue(REDRAWIMAGE, 0); + if (settings->imapaint.brush) + if (brush_clone_image_set_nr(settings->imapaint.brush, G.sima->menunr)) + allqueue(REDRAWIMAGE, 0); break; case B_SIMACLONEDELETE: - Gip.clone.image= NULL; - allqueue(REDRAWIMAGE, 0); + if (settings->imapaint.brush) + if (brush_clone_image_delete(settings->imapaint.brush)) + allqueue(REDRAWIMAGE, 0); break; case B_SIMABRUSHCHANGE: @@ -907,6 +908,37 @@ void do_imagebuts(unsigned short event) curvemapping_do_image(G.sima->cumap, G.sima->image); allqueue(REDRAWIMAGE, 0); break; + + case B_BRUSHBROWSE: + if(G.sima->menunr==-2) { + activate_databrowse((ID*)settings->imapaint.brush, ID_BR, 0, B_BRUSHBROWSE, &G.sima->menunr, do_global_buttons); + break; + } + else if(G.sima->menunr < 0) break; + + if(brush_set_nr(&settings->imapaint.brush, G.sima->menunr)) { + BIF_undo_push("Browse Brush"); + allqueue(REDRAWIMAGE, 0); + } + break; + case B_BRUSHDELETE: + if(brush_delete(&settings->imapaint.brush)) { + BIF_undo_push("Unlink Brush"); + allqueue(REDRAWIMAGE, 0); + } + break; + case B_KEEPDATA: + brush_toggle_fake_user(settings->imapaint.brush); + allqueue(REDRAWIMAGE, 0); + break; + case B_BRUSHLOCAL: + if(settings->imapaint.brush && settings->imapaint.brush->id.lib) { + if(okee("Make local")) { + make_local_brush(settings->imapaint.brush); + allqueue(REDRAWIMAGE, 0); + } + } + break; } } @@ -964,9 +996,11 @@ static void image_panel_paint(short cntrl) // IMAGE_HANDLER_PROPERTIES /* B_SIMABRUSHCHANGE only redraws and eats the mouse messages */ /* so that LEFTMOUSE does not 'punch' through the floating panel */ /* B_SIMANOTHING */ - ImagePaintTool *tool= &Gip.tool[Gip.current]; + ToolSettings *settings= G.scene->toolsettings; + Brush *brush= settings->imapaint.brush; uiBlock *block; ID *id; + int yco, xco, butw; block= uiNewBlock(&curarea->uiblocks, "image_panel_paint", UI_EMBOSS, UI_HELV, curarea->win); uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl); @@ -974,39 +1008,63 @@ static void image_panel_paint(short cntrl) // IMAGE_HANDLER_PROPERTIES if(uiNewPanel(curarea, block, "Image Paint", "Image", 10, 230, 318, 204)==0) return; - uiBlockBeginAlign(block); - uiDefButF(block, COL, B_VPCOLSLI, "", 979,160,230,19, tool->rgba, 0, 0, 0, 0, ""); - uiDefButF(block, NUMSLI, B_SIMANOTHING , "Opacity ", 979,140,230,19, tool->rgba+3, 0.0, 1.0, 0, 0, "The amount of pressure on the brush"); - uiDefButI(block, NUMSLI, B_SIMANOTHING , "Size ", 979,120,230,19, &tool->size, 2, 64, 0, 0, "The size of the brush"); - uiDefButF(block, NUMSLI, B_SIMANOTHING , "Fall ", 979,100,230,19, &tool->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush"); - - if(Gip.current == IMAGEPAINT_BRUSH || Gip.current == IMAGEPAINT_SMEAR) - uiDefButF(block, NUMSLI, B_SIMANOTHING , "Stepsize ",979,80,230,19, &tool->timing, 1.0, 100.0, 0, 0, "Repeating Paint On %of Brush diameter"); - else - uiDefButF(block, NUMSLI, B_SIMANOTHING , "Flow ", 979,80,230,19, &tool->timing, 1.0, 100.0, 0, 0, "Paint Flow for Air Brush"); - uiBlockEndAlign(block); + yco= 160; uiBlockBeginAlign(block); - uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Brush", 890,160,80,19, &Gip.current, 7.0, IMAGEPAINT_BRUSH, 0, 0, "Brush"); - uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "AirBrush", 890,140,80,19, &Gip.current, 7.0, IMAGEPAINT_AIRBRUSH, 0, 0, "AirBrush"); - uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Soften", 890,120,80,19, &Gip.current, 7.0, IMAGEPAINT_SOFTEN, 0, 0, "Soften"); - uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Aux AB1", 890,100,80,19, &Gip.current, 7.0, IMAGEPAINT_AUX1, 0, 0, "Auxiliary Air Brush1"); - uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Aux AB2", 890,80,80,19, &Gip.current, 7.0, IMAGEPAINT_AUX2, 0, 0, "Auxiliary Air Brush2"); - uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Smear", 890,60,80,19, &Gip.current, 7.0, IMAGEPAINT_SMEAR, 0, 0, "Smear"); - uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Clone", 890,40,80,19, &Gip.current, 7.0, IMAGEPAINT_CLONE, 0, 0, "Clone Brush / use RMB to drag source image"); + uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Draw", 0 ,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_DRAW, 0, 0, "Draw brush"); + uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Soften", 80 ,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SOFTEN, 0, 0, "Soften brush"); + uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Smear", 160,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SMEAR, 0, 0, "Smear brush"); + uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Clone", 240,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_CLONE, 0, 0, "Clone brush, use RMB to drag source image"); uiBlockEndAlign(block); + yco -= 30; - uiBlockBeginAlign(block); - id= (ID*)Gip.clone.image; - std_libbuttons(block, 979, 40, 0, NULL, B_SIMACLONEBROWSE, ID_IM, 0, id, 0, &G.sima->menunr, 0, 0, B_SIMACLONEDELETE, 0, 0); - uiDefButF(block, NUMSLI, B_SIMABRUSHCHANGE, "B ",979,20,230,19, &Gip.clone.alpha , 0.0, 1.0, 0, 0, "Blend clone image"); - uiBlockEndAlign(block); + uiBlockSetCol(block, TH_BUT_SETTING2); + id= (ID*)settings->imapaint.brush; + xco= std_libbuttons(block, 0, yco, 0, NULL, B_BRUSHBROWSE, ID_BR, 0, id, NULL, &(G.sima->menunr), 0, B_BRUSHLOCAL, B_BRUSHDELETE, 0, B_KEEPDATA); + uiBlockSetCol(block, TH_AUTO); + + if(brush && !brush->id.lib) { + butw= 320-(xco+10); + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, B_SIMABRUSHCHANGE, "Airbrush", xco+10,yco,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)"); + uiDefButBitS(block, TOG|BIT, IMAGEPAINT_TORUS, B_SIMABRUSHCHANGE, "Wrap", xco+10,yco-20,butw,19, &settings->imapaint.flag, 0, 0, 0, 0, "Enables torus wrapping"); + uiBlockEndAlign(block); + + uiDefButS(block, MENU, B_SIMANOTHING, "Mix %x0|Add %x1|Subtract %x2|Multiply %x3|Lighten %x4|Darken %x5", xco+10,yco-45,butw,19, &brush->blend, 0, 0, 0, 0, "Blending method for applying brushes"); + + yco -= 25; + + uiBlockBeginAlign(block); + uiDefButF(block, COL, B_VPCOLSLI, "", 0,yco,200,19, brush->rgb, 0, 0, 0, 0, ""); + uiDefButF(block, NUMSLI, B_SIMANOTHING, "Opacity ", 0,yco-20,200,19, &brush->alpha, 0.0, 1.0, 0, 0, "The amount of pressure on the brush"); + uiDefButI(block, NUMSLI, B_SIMANOTHING, "Size ", 0,yco-40,200,19, &brush->size, 1, 200, 0, 0, "The size of the brush"); + uiDefButF(block, NUMSLI, B_SIMANOTHING, "Falloff ", 0,yco-60,200,19, &brush->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush"); + + if(brush->flag & BRUSH_AIRBRUSH) + uiDefButF(block, NUMSLI, B_SIMANOTHING, "Flow ", 0,yco-80,200,19, &brush->timing, 1.0, 100.0, 0, 0, "Paint Flow for Air Brush"); + else + uiDefButF(block, NUMSLI, B_SIMANOTHING, "Stepsize ",0,yco-80,200,19, &brush->timing, 1.0, 100.0, 0, 0, "Repeating Paint On %% of Brush diameter"); + uiBlockEndAlign(block); + + yco -= 110; + + if(settings->imapaint.tool == PAINT_TOOL_CLONE) { + id= (ID*)brush->clone.image; + uiBlockSetCol(block, TH_BUT_SETTING2); + xco= std_libbuttons(block, 0, yco, 0, NULL, B_SIMACLONEBROWSE, ID_IM, 0, id, 0, &G.sima->menunr, 0, 0, B_SIMACLONEDELETE, 0, 0); + uiBlockSetCol(block, TH_AUTO); + if(id) { + butw= 320-(xco+5); + uiDefButF(block, NUMSLI, B_SIMABRUSHCHANGE, "B ",xco+5,yco,butw,19, &brush->clone.alpha , 0.0, 1.0, 0, 0, "Opacity of clone image display"); + } + } + } #if 0 - uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL_DRAWING, B_SIMABRUSHCHANGE, "TD", 890,1,50,19, &Gip.flag, 0, 0, 0, 0, "Enables tool shape while drawing"); - uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL, B_SIMABRUSHCHANGE, "TP", 940,1,50,19, &Gip.flag, 0, 0, 0, 0, "Enables tool shape while not drawing"); + uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL_DRAWING, B_SIMABRUSHCHANGE, "TD", 0,1,50,19, &settings->imapaint.flag.flag, 0, 0, 0, 0, "Enables brush shape while drawing"); + uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL, B_SIMABRUSHCHANGE, "TP", 50,1,50,19, &settings->imapaint.flag.flag, 0, 0, 0, 0, "Enables brush shape while not drawing"); #endif - uiDefButBitS(block, TOG|BIT, IMAGEPAINT_TORUS, B_SIMABRUSHCHANGE, "Wrap", 890,1,50,19, &Gip.flag, 0, 0, 0, 0, "Enables torus wrapping"); } static void image_panel_curves_reset(void *cumap_v, void *unused) @@ -1444,6 +1502,7 @@ void drawimagespace(ScrArea *sa, void *spacedata) { SpaceImage *sima= spacedata; ImBuf *ibuf= NULL; + Brush *brush; float col[3]; unsigned int *rect; float x1, y1; @@ -1617,7 +1676,8 @@ void drawimagespace(ScrArea *sa, void *spacedata) } } - if(Gip.current == IMAGEPAINT_CLONE) { + brush= G.scene->toolsettings->imapaint.brush; + if(brush && (G.scene->toolsettings->imapaint.tool == PAINT_TOOL_CLONE)) { int w, h; unsigned char *clonerect; @@ -1627,8 +1687,8 @@ void drawimagespace(ScrArea *sa, void *spacedata) if(clonerect) { int offx, offy; - offx = sima->zoom*ibuf->x * + Gip.clone.offset[0]; - offy = sima->zoom*ibuf->y * + Gip.clone.offset[1]; + offx = sima->zoom*ibuf->x * + brush->clone.offset[0]; + offy = sima->zoom*ibuf->y * + brush->clone.offset[1]; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); diff --git a/source/blender/src/editface.c b/source/blender/src/editface.c index a906cc275fd..9c6e244e549 100644 --- a/source/blender/src/editface.c +++ b/source/blender/src/editface.c @@ -54,7 +54,6 @@ #include "DNA_screen_types.h" #include "DNA_scene_types.h" #include "DNA_view3d_types.h" -#include "DNA_userdef_types.h" #include "BKE_utildefines.h" #include "BKE_depsgraph.h" @@ -88,7 +87,6 @@ #include "blendef.h" #include "butspace.h" -#include "../img/IMG_Api.h" #include "BSE_trans_types.h" #include "BDR_unwrapper.h" @@ -121,7 +119,7 @@ /* returns 0 if not found, otherwise 1 */ -static int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect) +int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect) { if (!me->tface || me->totface==0) return 0; @@ -1506,7 +1504,7 @@ void set_texturepaint() /* toggle */ * @param org origin of the view ray. * @param dir direction of the view ray. */ -static void get_pick_ray(short x, short y, float org[3], float dir[3]) +static void get_pick_ray(short *xy, float org[3], float dir[3]) { double mvmatrix[16]; double projmatrix[16]; @@ -1525,10 +1523,10 @@ static void get_pick_ray(short x, short y, float org[3], float dir[3]) /* printf("viewport = (%4d, %4d, %4d, %4d)\n", viewport[0], viewport[1], viewport[2], viewport[3]); */ /* printf("cursor = (%4d, %4d)\n", x, y); */ - gluUnProject((GLdouble) x, (GLdouble) y, 0.0, mvmatrix, projmatrix, viewport, &px, &py, &pz); + gluUnProject((GLdouble) xy[0], (GLdouble) xy[1], 0.0, mvmatrix, projmatrix, viewport, &px, &py, &pz); org[0] = (float)px; org[1] = (float)py; org[2] = (float)pz; /* printf("world point at z=0.0 is (%f, %f, %f)\n", org[0], org[1], org[2]); */ - gluUnProject((GLdouble) x, (GLdouble) y, 1.0, mvmatrix, projmatrix, viewport, &px, &py, &pz); + gluUnProject((GLdouble) xy[0], (GLdouble) xy[1], 1.0, mvmatrix, projmatrix, viewport, &px, &py, &pz); /* printf("world point at z=1.0 is (%f, %f, %f)\n", px, py, pz); */ dir[0] = ((float)px) - org[0]; dir[1] = ((float)py) - org[1]; @@ -1668,7 +1666,7 @@ static int face_get_vertex_coordinates(Mesh* mesh, TFace* face, float v1[3], flo * @param u (u,v) coordinate. * @param v (u,v) coordinate. */ -static void face_get_uv(TFace* face, int v1, int v2, int v3, float a, float b, float* u, float* v) +static void face_get_uv(TFace* face, int v1, int v2, int v3, float a, float b, float *uv) { float uv01[2], uv21[2]; @@ -1692,8 +1690,8 @@ static void face_get_uv(TFace* face, int v1, int v2, int v3, float a, float b, f uv01[1] *= a; uv21[0] *= b; uv21[1] *= b; - *u = face->uv[v1][0] + (uv01[0] + uv21[0]); - *v = face->uv[v1][1] + (uv01[1] + uv21[1]); + uv[0] = face->uv[v1][0] + (uv01[0] + uv21[0]); + uv[1] = face->uv[v1][1] + (uv01[1] + uv21[1]); } /** @@ -1711,7 +1709,7 @@ static void face_get_uv(TFace* face, int v1, int v2, int v3, float a, float b, f * 0 == no intersection, (u,v) invalid * 1 == intersection, (u,v) valid */ -static int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short x, short y, float* u, float* v) +int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short *xy, float *uv) { float org[3], dir[3]; float ab[2]; @@ -1720,7 +1718,7 @@ static int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short x, short int num_verts; /* Get a view ray to intersect with the face */ - get_pick_ray(x, y, org, dir); + get_pick_ray(xy, org, dir); /* Convert local vertex coordinates to world */ num_verts = face_get_vertex_coordinates(mesh, face, v1, v2, v3, v4); @@ -1738,178 +1736,18 @@ static int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short x, short result = triangle_ray_intersect(v2, v1, v3, org, dir, ab); if ( (num_verts == 3) || ((num_verts == 4) && (result > 1)) ) { /* Face is a triangle or a quad with a hit on the first triangle */ - face_get_uv(face, 1, 0, 2, ab[0], ab[1], u, v); + face_get_uv(face, 1, 0, 2, ab[0], ab[1], uv); /* printf("triangle 1, texture (u,v)=(%f, %f)\n", *u, *v); */ } else { /* Face is a quad and no intersection with first triangle */ result = triangle_ray_intersect(v4, v3, v1, org, dir, ab); - face_get_uv(face, 3, 2, 0, ab[0], ab[1], u, v); + face_get_uv(face, 3, 2, 0, ab[0], ab[1], uv); /* printf("triangle 2, texture (u,v)=(%f, %f)\n", *u, *v); */ } return result > 0; } -/** - * First attempt at drawing in the texture of a face. - * @author Maarten Gribnau - */ -void face_draw() -{ - Object *ob; - Mesh *me; - TFace *face, *face_old = 0; - short xy[2], xy_old[2]; - //int a, index; - Image *img=NULL, *img_old = NULL; - IMG_BrushPtr brush; - IMG_CanvasPtr canvas = 0; - unsigned int rowBytes, face_index; - char *warn_packed_file = 0; - float uv[2], uv_old[2]; - extern VPaint Gvp; - short mousebut; - - ob = OBACT; - if (!ob) { - error("No active object"); return; - } - if (!(ob->lay & G.vd->lay)) { - error("The active object is not in this layer"); return; - } - me = get_mesh(ob); - if (!me) { - error("The active object does not have a mesh obData"); return; - } - - brush = IMG_BrushCreate(Gvp.size, Gvp.size, &Gvp.r); - if (!brush) { - error("Can't create brush"); return; - } - - if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE; - else mousebut = L_MOUSE; - - persp(PERSP_VIEW); - - getmouseco_areawin(xy_old); - while (get_mbut() & mousebut) { - getmouseco_areawin(xy); - /* Check if cursor has moved */ - if ((xy[0] != xy_old[0]) || (xy[1] != xy_old[1])) { - - /* Get face to draw on */ - if (!facesel_face_pick(me, xy, &face_index, 0)) face = NULL; - else face = (((TFace*)me->tface)+face_index); - - /* Check if this is another face. */ - if (face != face_old) { - /* The active face changed, check the texture */ - if (face) { - img = face->tpage; - } - else { - img = 0; - } - - if (img != img_old) { - /* Faces have different textures. Finish drawing in the old face. */ - if (face_old && canvas) { - face_pick_uv(ob, me, face_old, xy[0], xy[1], &uv[0], &uv[1]); - IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]); - img_old->ibuf->userflags |= IB_BITMAPDIRTY; - /* Delete old canvas */ - IMG_CanvasDispose(canvas); - canvas = 0; - } - - /* Create new canvas and start drawing in the new face. */ - if (img) { - if (img->ibuf && img->packedfile == 0) { - /* MAART: skipx is not set most of the times. Make a guess. */ - rowBytes = img->ibuf->skipx ? img->ibuf->skipx : img->ibuf->x * 4; - canvas = IMG_CanvasCreateFromPtr(img->ibuf->rect, img->ibuf->x, img->ibuf->y, rowBytes); - if (canvas) { - face_pick_uv(ob, me, face, xy_old[0], xy_old[1], &uv_old[0], &uv_old[1]); - face_pick_uv(ob, me, face, xy[0], xy[1], &uv[0], &uv[1]); - IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]); - img->ibuf->userflags |= IB_BITMAPDIRTY; - } - } - else { - /* TODO: should issue warning that no texture is assigned */ - if (img->packedfile) { - warn_packed_file = img->id.name + 2; - img = 0; - } - } - } - } - else { - /* Face changed and faces have the same texture. */ - if (canvas) { - /* Finish drawing in the old face. */ - if (face_old) { - face_pick_uv(ob, me, face_old, xy[0], xy[1], &uv[0], &uv[1]); - IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]); - img_old->ibuf->userflags |= IB_BITMAPDIRTY; - } - - /* Start drawing in the new face. */ - if (face) { - face_pick_uv(ob, me, face, xy_old[0], xy_old[1], &uv_old[0], &uv_old[1]); - face_pick_uv(ob, me, face, xy[0], xy[1], &uv[0], &uv[1]); - IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]); - img->ibuf->userflags |= IB_BITMAPDIRTY; - } - } - } - } - else { - /* Same face, continue drawing */ - if (face && canvas) { - /* Get the new (u,v) coordinates */ - face_pick_uv(ob, me, face, xy[0], xy[1], &uv[0], &uv[1]); - IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]); - img->ibuf->userflags |= IB_BITMAPDIRTY; - } - } - - if (face && img) { - /* Make OpenGL aware of a change in the texture */ - free_realtime_image(img); - /* Redraw the view */ - scrarea_do_windraw(curarea); - screen_swapbuffers(); - } - - xy_old[0] = xy[0]; - xy_old[1] = xy[1]; - uv_old[0] = uv[0]; - uv_old[1] = uv[1]; - face_old = face; - img_old = img; - } - } - - IMG_BrushDispose(brush); - if (canvas) { - IMG_CanvasDispose(canvas); - canvas = 0; - } - - if (warn_packed_file) { - error("Painting in packed images is not supported: %s", warn_packed_file); - } - - persp(PERSP_WIN); - - BIF_undo_push("UV face draw"); - allqueue(REDRAWVIEW3D, 0); - allqueue(REDRAWIMAGE, 0); - allqueue(REDRAWHEADERS, 0); -} - /* Selects all faces which have the same uv-texture as the active face * @author Roel Spruit * @return Void diff --git a/source/blender/src/filesel.c b/source/blender/src/filesel.c index cb478bf9f59..bc1bfba9161 100644 --- a/source/blender/src/filesel.c +++ b/source/blender/src/filesel.c @@ -2464,7 +2464,7 @@ void main_to_filelist(SpaceFile *sfile) if( sfile->dir[0]==0) { /* make directories */ - sfile->totfile= 23; + sfile->totfile= 24; sfile->filelist= (struct direntry *)malloc(sfile->totfile * sizeof(struct direntry)); for(a=0; atotfile; a++) { @@ -2495,6 +2495,7 @@ void main_to_filelist(SpaceFile *sfile) sfile->filelist[20].relname= BLI_strdup("Armature"); sfile->filelist[21].relname= BLI_strdup("Action"); sfile->filelist[22].relname= BLI_strdup("NodeTree"); + sfile->filelist[23].relname= BLI_strdup("Brush"); qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_name); } diff --git a/source/blender/src/header_image.c b/source/blender/src/header_image.c index 4d87f3c9c56..a21518c17e1 100644 --- a/source/blender/src/header_image.c +++ b/source/blender/src/header_image.c @@ -54,6 +54,7 @@ #include "BDR_drawmesh.h" #include "BDR_unwrapper.h" +#include "BKE_brush.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_library.h" @@ -315,7 +316,9 @@ void do_image_buttons(unsigned short event) break; case B_SIMAGEPAINTTOOL: - // check for packed file here + if(G.sima->flag & SI_DRAWTOOL) + /* add new brush if none exists */ + brush_check_exists(&G.scene->toolsettings->imapaint.brush); allqueue(REDRAWIMAGE, 0); allqueue(REDRAWVIEW3D, 0); break; diff --git a/source/blender/src/headerbuttons.c b/source/blender/src/headerbuttons.c index 3440b5b0c18..3ec3a58f9b3 100644 --- a/source/blender/src/headerbuttons.c +++ b/source/blender/src/headerbuttons.c @@ -251,7 +251,7 @@ int std_libbuttons(uiBlock *block, short xco, short yco, if(browse) { char *extrastr= NULL; - if(ELEM(id_code, ID_MA, ID_TE)) add_addbutton= 1; + if(ELEM3(id_code, ID_MA, ID_TE, ID_BR)) add_addbutton= 1; lb= wich_libbase(G.main, id_code); @@ -261,7 +261,7 @@ int std_libbuttons(uiBlock *block, short xco, short yco, uiBlockSetCol(block, TH_BUT_SETTING2); } - if ELEM7( id_code, ID_SCE, ID_SCR, ID_MA, ID_TE, ID_WO, ID_IP, ID_AC) extrastr= "ADD NEW %x 32767"; + if ELEM8( id_code, ID_SCE, ID_SCR, ID_MA, ID_TE, ID_WO, ID_IP, ID_AC, ID_BR) extrastr= "ADD NEW %x 32767"; else if (id_code==ID_TXT) extrastr= "OPEN NEW %x 32766 |ADD NEW %x 32767"; else if (id_code==ID_SO) extrastr= "OPEN NEW %x 32766"; diff --git a/source/blender/src/imagepaint.c b/source/blender/src/imagepaint.c index 3aed860442f..627d3aaf18f 100644 --- a/source/blender/src/imagepaint.c +++ b/source/blender/src/imagepaint.c @@ -43,17 +43,29 @@ #include #endif +#include "MEM_guardedalloc.h" + #ifdef WIN32 #include "BLI_winstuff.h" #endif #include "IMB_imbuf_types.h" +#include "DNA_brush_types.h" #include "DNA_image_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "DNA_userdef_types.h" +#include "DNA_view3d_types.h" +#include "BKE_brush.h" #include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_utildefines.h" #include "BIF_mywindow.h" #include "BIF_screen.h" @@ -62,15 +74,450 @@ #include "BSE_drawipo.h" #include "BSE_trans_types.h" +#include "BSE_view.h" #include "BDR_drawmesh.h" #include "BDR_imagepaint.h" #include "BDR_vpaint.h" -#include "IMG_Api.h" - +#include "blendef.h" #include "mydevice.h" +/* ImagePaintPixmap */ + +#define IMAPAINT_FLOAT_TO_CHAR(f) ((char)(f*255)) +#define IMAPAINT_CHAR_TO_FLOAT(c) (c/255.0f) +#define IMAPAINT_FLOAT_CLAMP(f) ((f < 0.0)? 0.0: (f > 1.0)? 1.0: f) + +#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { c[0]=IMAPAINT_FLOAT_TO_CHAR(f[0]); \ + c[1]=IMAPAINT_FLOAT_TO_CHAR(f[1]); c[2]=IMAPAINT_FLOAT_TO_CHAR(f[2]); } +#define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f) { \ + c[0]=IMAPAINT_FLOAT_TO_CHAR(f[0]); c[1]=IMAPAINT_FLOAT_TO_CHAR(f[1]); \ + c[2]=IMAPAINT_FLOAT_TO_CHAR(f[2]); c[2]=IMAPAINT_FLOAT_TO_CHAR(f[3]);} +#define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { f[0]=IMAPAINT_CHAR_TO_FLOAT(c[0]); \ + f[1]=IMAPAINT_CHAR_TO_FLOAT(c[1]); f[2]=IMAPAINT_CHAR_TO_FLOAT(c[2]); } +#define IMAPAINT_CHAR_RGBA_TO_FLOAT(f, c) { \ + f[0]=IMAPAINT_CHAR_TO_FLOAT(c[0]); f[1]=IMAPAINT_CHAR_TO_FLOAT(c[1]); \ + f[2]=IMAPAINT_CHAR_TO_FLOAT(c[2]); f[3]=IMAPAINT_CHAR_TO_FLOAT(c[3]); } + +#define IMAPAINT_FLOAT_RGB_COPY(a, b) VECCOPY(a, b) +#define IMAPAINT_FLOAT_RGB_ADD(a, b) VECADD(a, a, b) + +#define IMAPAINT_RGB_COPY(a, b) { a[0]=b[0]; a[1]=b[1]; a[2]=b[2]; } +#define IMAPAINT_RGBA_COPY(a, b) { *((int*)a)=*((int*)b); } + +typedef struct ImagePaintPixmap { + unsigned int width, height, rowbytes, shared; + char *rect; +} ImagePaintPixmap; + +static ImagePaintPixmap *imapaint_pixmap_new(unsigned int w, unsigned int h, char *rect) +{ + ImagePaintPixmap *pm = MEM_callocN(sizeof(ImagePaintPixmap), "ImagePaintPixmap"); + + pm->width = w; + pm->height = h; + pm->rowbytes = sizeof(char)*w*4; + + if (rect) { + pm->rect = rect; + pm->shared = 1; + } + else + pm->rect = MEM_mallocN(pm->rowbytes*h, "ImagePaintPixmapRect"); + + return pm; +} + +static void imapaint_pixmap_free(ImagePaintPixmap *pm) +{ + if (!pm->shared) + MEM_freeN(pm->rect); + MEM_freeN(pm); +} + +/* ImagePaintBrush */ + +typedef struct ImagePaintBrush { + ImagePaintPixmap *pixmap; + float rgb[3], alpha; + unsigned int inner_radius, outer_radius; + short torus, blend; +} ImagePaintBrush; + +static void imapaint_brush_pixmap_refresh(ImagePaintBrush *brush) +{ + ImagePaintPixmap *pm = brush->pixmap; + char *dst, src[4], src_alpha[4]; + unsigned int y, x, outer, inner; + float w_2, h_2, dX, dY, d, a; + + w_2 = pm->width/2.0f; + h_2 = pm->height/2.0f; + + outer = brush->outer_radius; + inner = brush->inner_radius; + + IMAPAINT_FLOAT_RGB_TO_CHAR(src, brush->rgb); + src[3] = 0; + IMAPAINT_RGB_COPY(src_alpha, src); + src_alpha[3] = IMAPAINT_FLOAT_TO_CHAR(brush->alpha); + + for (y=0; y < pm->height; y++) { + dst = pm->rect + y*pm->rowbytes; + + for (x=0; x < pm->width; x++, dst+=4) { + dX = x + 0.5f - w_2; + dY = y + 0.5f - h_2; + d = sqrt(dX*dX + dY*dY); + + if (d <= inner) { + IMAPAINT_RGBA_COPY(dst, src_alpha); + } + else if ((d < outer) && (inner < outer)) { + a = sqrt((d - inner)/(outer - inner)); + a = (1 - a)*brush->alpha; + + IMAPAINT_RGB_COPY(dst, src); + dst[3] = IMAPAINT_FLOAT_TO_CHAR(a); + } + else { + IMAPAINT_RGBA_COPY(dst, src); + } + } + } +} + +static void imapaint_brush_set_radius_ratio(ImagePaintBrush *brush, float ratio) +{ + ImagePaintPixmap *pm = brush->pixmap; + unsigned int si, w_2 = pm->width/2, h_2 = pm->height/2; + + si = (pm->width < pm->height)? pm->width: pm->height; + brush->inner_radius = (int)((ratio*si)/2); + brush->outer_radius = si/2; + + if (brush->outer_radius > w_2) + brush->outer_radius = w_2; + if (brush->outer_radius > h_2) + brush->outer_radius = h_2; + if (brush->inner_radius > brush->outer_radius) + brush->inner_radius = brush->outer_radius; +} + +static ImagePaintBrush *imapaint_brush_new(unsigned int w, unsigned int h, float *rgb, float alpha, float radius_ratio) +{ + ImagePaintBrush *brush = MEM_callocN(sizeof(ImagePaintBrush), "ImagePaintBrush"); + + IMAPAINT_FLOAT_RGB_COPY(brush->rgb, rgb); + brush->alpha = alpha; + brush->pixmap = imapaint_pixmap_new(w, h, NULL); + + imapaint_brush_set_radius_ratio(brush, radius_ratio); + imapaint_brush_pixmap_refresh(brush); + + return brush; +} + +static void imapaint_brush_free(ImagePaintBrush *brush) +{ + imapaint_pixmap_free(brush->pixmap); + MEM_freeN(brush); +} + +/* ImagePaintPixmap Utilities */ + +static char *imapaint_pixmap_get_rgba(ImagePaintPixmap *pm, unsigned int x, unsigned int y) +{ + return &pm->rect[pm->rowbytes*y + x*4]; +} + +static char *imapaint_pixmap_get_rgba_torus(ImagePaintPixmap *pm, unsigned int x, unsigned int y) +{ + x %= pm->width; + y %= pm->height; + + return &pm->rect[pm->rowbytes*y + x*4]; +} + +static void imapaint_pixmap_clip(ImagePaintPixmap *pm, ImagePaintPixmap *bpm, float *pos, unsigned int *off, unsigned int *boff, unsigned int *dim) +{ + int x = (int)(pos[0]*pm->width - bpm->width/2); + int y = (int)(pos[1]*pm->height - bpm->height/2); + + dim[0] = bpm->width; + dim[1] = bpm->height; + + if (((x + (int)dim[0]) <= 0) || (x >= (int)pm->width) || + ((y + (int)dim[1]) <= 0) || (y >= (int)pm->height)) { + dim[0] = 0; + dim[1] = 0; + return; + } + + if (x < 0) { + dim[0] += x; + off[0] = 0; + boff[0] = -x; + } + else { + off[0] = x; + boff[0] = 0; + } + + if (y < 0) { + dim[1] += y; + off[1] = 0; + boff[1] = -y; + } + else { + off[1] = y; + boff[1] = 0; + } + + if (off[0] + dim[0] > pm->width) + dim[0] -= (off[0] + dim[0]) - pm->width; + if (off[1] + dim[1] > pm->height) + dim[1] -= (off[1] + dim[1]) - pm->height; +} + +static void imapaint_pixmap_blend(ImagePaintPixmap *pm, ImagePaintPixmap *bpm, float *pos, short mode) +{ + unsigned int x, y, dim[2], out_off[2], in_off[2]; + char *out, *in; + + imapaint_pixmap_clip(pm, bpm, pos, out_off, in_off, dim); + + if ((dim[0] == 0) || (dim[1] == 0)) + return; + + for (y=0; y < dim[1]; y++) { + out = imapaint_pixmap_get_rgba(pm, out_off[0], out_off[1]+y); + in = imapaint_pixmap_get_rgba(bpm, in_off[0], in_off[1]+y); + + for (x=0; x < dim[0]; x++, out+=4, in+=4) + brush_blend_rgb(out, out, in, in[3], mode); + } +} + +static void imapaint_pixmap_blend_torus(ImagePaintPixmap *pm, ImagePaintPixmap *bpm, float *pos, short mode) +{ + unsigned int x, y, out_off[2], mx, my; + char *out, *in; + + out_off[0] = (int)(pos[0]*pm->width - bpm->width/2); + out_off[1] = (int)(pos[1]*pm->height - bpm->height/2); + + for (y=0; y < bpm->height; y++) { + in = imapaint_pixmap_get_rgba(bpm, 0, y); + + for (x=0; x < bpm->width; x++, out+=4, in+=4) { + mx = (out_off[0]+x) % pm->width; + my = (out_off[1]+y) % pm->height; + out = imapaint_pixmap_get_rgba(pm, mx, my); + + brush_blend_rgb(out, out, in, in[3], mode); + } + } +} + +static int imapaint_pixmap_add_if(ImagePaintPixmap *pm, unsigned int x, unsigned int y, float *outrgb, short torus) +{ + char *inrgb; + float finrgb[3]; + + if ((x >= pm->width) || (y >= pm->height)) { + if (torus) + inrgb = imapaint_pixmap_get_rgba_torus(pm, x, y); + else + return 0; + } + else + inrgb = imapaint_pixmap_get_rgba(pm, x, y); + + IMAPAINT_CHAR_RGB_TO_FLOAT(finrgb, inrgb); + IMAPAINT_FLOAT_RGB_ADD(outrgb, finrgb); + + return 1; +} + +/* ImagePaintPixmap Tools */ + +static void imapaint_blend_line(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *start, float *end) +{ + float numsteps, t, pos[2]; + int step, d[2]; + + d[0] = (int)((end[0] - start[0])*pm->width); + d[1] = (int)((end[1] - start[1])*pm->height); + numsteps = sqrt(d[0]*d[0] + d[1]*d[1])/(brush->pixmap->width/4.0f); + + if(numsteps < 1.0) + numsteps = 1.0f; + + for (step=0; step < numsteps; step++) { + t = (step+1)/numsteps; + pos[0] = start[0] + d[0]*t/pm->width; + pos[1] = start[1] + d[1]*t/pm->height; + + if (brush->torus) + imapaint_pixmap_blend_torus(pm, brush->pixmap, pos, brush->blend); + else + imapaint_pixmap_blend(pm, brush->pixmap, pos, brush->blend); + } +} + +static void imapaint_soften_sharpen(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos, short sharpen) +{ + ImagePaintPixmap *bpm = brush->pixmap; + unsigned int x, y, count, xi, yi, xo, yo; + unsigned int out_off[2], in_off[2], dim[2]; + float outrgb[3], finrgb[3]; + short torus= brush->torus; + char *inrgb, *out; + + if (torus) { + dim[0] = bpm->width; + dim[1] = bpm->width; + in_off[0] = (int)(pos[0]*pm->width - bpm->width/2); + in_off[1] = (int)(pos[1]*pm->height - bpm->width/2); + out_off[0] = out_off[1] = 0; + } + else { + imapaint_pixmap_clip(pm, bpm, pos, in_off, out_off, dim); + if ((dim[0] == 0) || (dim[1] == 0)) + return; + } + + for (y=0; y < dim[1]; y++) { + for (x=0; x < dim[0]; x++) { + /* get input pixel */ + xi = in_off[0] + x; + yi = in_off[1] + y; + if (torus) + inrgb = imapaint_pixmap_get_rgba_torus(pm, xi, yi); + else + inrgb = imapaint_pixmap_get_rgba(pm, xi, yi); + + /* sum and average surrounding pixels */ + count = 1; + IMAPAINT_CHAR_RGB_TO_FLOAT(outrgb, inrgb); + if (sharpen) + IMAPAINT_FLOAT_RGB_COPY(finrgb, outrgb); + + count += imapaint_pixmap_add_if(pm, xi-1, yi-1, outrgb, torus); + count += imapaint_pixmap_add_if(pm, xi-1, yi , outrgb, torus); + count += imapaint_pixmap_add_if(pm, xi-1, yi+1, outrgb, torus); + + count += imapaint_pixmap_add_if(pm, xi , yi-1, outrgb, torus); + count += imapaint_pixmap_add_if(pm, xi , yi+1, outrgb, torus); + + count += imapaint_pixmap_add_if(pm, xi+1, yi-1, outrgb, torus); + count += imapaint_pixmap_add_if(pm, xi+1, yi , outrgb, torus); + count += imapaint_pixmap_add_if(pm, xi+1, yi+1, outrgb, torus); + + outrgb[0] /= count; + outrgb[1] /= count; + outrgb[2] /= count; + + if (sharpen) { + /* unsharp masking - creates ugly artifacts and is disabled + for now, needs some sort of clamping to reduce artifacts */ + outrgb[0] = 2*finrgb[0] - outrgb[0]; + outrgb[1] = 2*finrgb[1] - outrgb[1]; + outrgb[2] = 2*finrgb[2] - outrgb[2]; + + outrgb[0] = IMAPAINT_FLOAT_CLAMP(outrgb[0]); + outrgb[1] = IMAPAINT_FLOAT_CLAMP(outrgb[1]); + outrgb[2] = IMAPAINT_FLOAT_CLAMP(outrgb[2]); + } + + /* write into brush buffer */ + xo = out_off[0] + x; + yo = out_off[1] + y; + out = imapaint_pixmap_get_rgba(bpm, xo, yo); + IMAPAINT_FLOAT_RGB_TO_CHAR(out, outrgb); + } + } + + if (torus) + imapaint_pixmap_blend_torus(pm, bpm, pos, brush->blend); + else + imapaint_pixmap_blend(pm, bpm, pos, brush->blend); +} + +static void imapaint_lift_smear(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos) +{ + ImagePaintPixmap *bpm = brush->pixmap; + int in_off[2], x, y; + char *out, *in; + + in_off[0] = (int)(pos[0]*pm->width - bpm->width/2); + in_off[1] = (int)(pos[1]*pm->height - bpm->height/2); + + for (y=0; y < bpm->height; y++) { + out = imapaint_pixmap_get_rgba(bpm, 0, y); + for (x=0; x < bpm->width; x++, out+=4) { + in = imapaint_pixmap_get_rgba_torus(pm, in_off[0]+x, in_off[1]+y); + IMAPAINT_RGB_COPY(out, in); + } + } +} + +static void imapaint_smear(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *start, float *end) +{ + float pos[2]; + + pos[0]= 2*start[0] - end[0]; + pos[1]= 2*start[1] - end[1]; + + imapaint_lift_smear(pm, brush, pos); + imapaint_blend_line(pm, brush, start, end); +} + +static void imapaint_lift_clone(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos) +{ + ImagePaintPixmap *bpm = brush->pixmap; + int in_off[2], x, y, xi, yi; + char *out, *in; + + /* we overwrite alphas for pixels outside clone, so need to reload them */ + imapaint_brush_pixmap_refresh(brush); + + in_off[0] = (int)(pos[0]*pm->width - bpm->width/2); + in_off[1] = (int)(pos[1]*pm->height - bpm->height/2); + + for (y=0; y < bpm->height; y++) { + out = imapaint_pixmap_get_rgba(bpm, 0, y); + for (x=0; x < bpm->width; x++, out+=4) { + xi = in_off[0] + x; + yi = in_off[1] + y; + + if ((xi < 0) || (yi < 0) || (xi >= pm->width) || (yi >= pm->height)) { + out[0] = out[1] = out[2] = out[3] = 0; + } + else { + in = imapaint_pixmap_get_rgba(pm, xi, yi); + IMAPAINT_RGB_COPY(out, in); + } + } + } +} + +static void imapaint_clone(ImagePaintPixmap *pm, ImagePaintPixmap *cpm, ImagePaintBrush *brush, float *start, float *off) +{ + float pos[2]; + + pos[0]= start[0] - off[0]; + pos[1]= start[1] - off[1]; + + imapaint_lift_clone(cpm, brush, pos); + imapaint_pixmap_blend(pm, brush->pixmap, start, brush->blend); +} + +/* 2D image paint */ + +#if 0 struct ImagePaint Gip = { {NULL, {0.0f, 0.0f}, 0.5f}, {{{1.0f, 1.0f, 1.0f, 0.2f}, 25, 0.5f, 100.0f}, /* brush */ @@ -82,73 +529,83 @@ struct ImagePaint Gip = { {{1.0f, 1.0f, 1.0f, 0.5f}, 25, 0.1f, 20.0f}}, /* clone */ 0, IMAGEPAINT_BRUSH }; +#endif -static int imagepaint_init(IMG_BrushPtr **brush, IMG_CanvasPtr **canvas, IMG_CanvasPtr **clonecanvas) +static ImagePaintBrush *imapaint_init_brush() { - ImBuf *ibuf= NULL, *cloneibuf= NULL; - ImagePaintTool *tool= &Gip.tool[Gip.current]; + ToolSettings *settings= G.scene->toolsettings; + Brush *brush= settings->imapaint.brush; - /* verify that we can paint */ - if(!G.sima->image || !G.sima->image->ibuf || !G.sima->image->ibuf->rect) - return 0; - else if(G.sima->image->packedfile) { - error("Painting in packed images not supported"); - return 0; - } + if (!brush) + return NULL; - ibuf= G.sima->image->ibuf; - - if(Gip.current == IMAGEPAINT_CLONE) { - if(!Gip.clone.image || !Gip.clone.image->ibuf) - return 0; - - cloneibuf= Gip.clone.image->ibuf; - } + /* initialize paint settings */ + if(brush->flag & BRUSH_AIRBRUSH) + settings->imapaint.flag |= IMAGEPAINT_TIMED; + else + settings->imapaint.flag &= ~IMAGEPAINT_TIMED; /* create brush */ - *brush= IMG_BrushCreate(tool->size, tool->size, tool->rgba); - IMG_BrushSetInnerRaduisRatio(*brush, tool->innerradius); + return imapaint_brush_new(brush->size, brush->size, brush->rgb, brush->alpha, brush->innerradius); +} - /* create canvas */ - *canvas= IMG_CanvasCreateFromPtr(ibuf->rect, ibuf->x, ibuf->y, ibuf->x*4); +static void imapaint_free_brush(ImagePaintBrush *brush) +{ + imapaint_brush_free(brush); +} - if(Gip.current == IMAGEPAINT_CLONE) { - int w= cloneibuf->x, h= cloneibuf->y; - *clonecanvas= IMG_CanvasCreateFromPtr(cloneibuf->rect, w, h, cloneibuf->x*4); +static ImagePaintPixmap *imapaint_init_canvas(ImagePaintPixmap **clonecanvas) +{ + ImBuf *ibuf= NULL, *cloneibuf= NULL; + ImagePaintPixmap *canvas; + ToolSettings *settings= G.scene->toolsettings; + Brush *brush= settings->imapaint.brush; + + /* verify that we can paint and create canvas */ + if(!G.sima->image || !G.sima->image->ibuf || !G.sima->image->ibuf->rect) + return NULL; + else if(G.sima->image->packedfile) + return NULL; + + ibuf= G.sima->image->ibuf; + canvas= imapaint_pixmap_new(ibuf->x, ibuf->y, (char*)ibuf->rect); + + if (clonecanvas) { + /* create clone canvas */ + if(brush && (settings->imapaint.tool == PAINT_TOOL_CLONE)) { + int w, h; + if(!brush->clone.image || !brush->clone.image->ibuf) + return 0; + + cloneibuf= brush->clone.image->ibuf; + w = cloneibuf->x; + h = cloneibuf->y; + *clonecanvas= imapaint_pixmap_new(w, h, (char*)cloneibuf->rect); + } + else + *clonecanvas= NULL; } - else - *clonecanvas= NULL; - - /* initialize paint settings */ - if((Gip.current == IMAGEPAINT_AIRBRUSH) || - (Gip.current == IMAGEPAINT_AUX1) || - (Gip.current == IMAGEPAINT_AUX2)) - Gip.flag |= IMAGEPAINT_TIMED; - else - Gip.flag &= ~IMAGEPAINT_TIMED; - - return 1; + + return canvas; } -static void imagepaint_free(IMG_BrushPtr *brush, IMG_CanvasPtr *canvas, IMG_CanvasPtr *clonecanvas) +static void imapaint_free_canvas(ImagePaintPixmap *canvas, ImagePaintPixmap *clonecanvas) { - IMG_BrushDispose(brush); - IMG_CanvasDispose(canvas); - - if(Gip.current == IMAGEPAINT_CLONE) - IMG_CanvasDispose(clonecanvas); + imapaint_pixmap_free(canvas); + if(clonecanvas) + imapaint_pixmap_free(clonecanvas); } -void imagepaint_redraw_tool(void) +void imapaint_redraw_tool(void) { - if(Gip.flag & IMAGEPAINT_DRAW_TOOL_DRAWING) + if(G.scene->toolsettings->imapaint.flag & IMAGEPAINT_DRAW_TOOL_DRAWING) force_draw(0); } -static void imagepaint_redraw(int final, int painted) +static void imapaint_redraw(int final, int painted) { if(!final && !painted) { - imagepaint_redraw_tool(); + imapaint_redraw_tool(); return; } @@ -166,66 +623,76 @@ static void imagepaint_redraw(int final, int painted) allqueue(REDRAWHEADERS, 0); } -static void imagepaint_compute_uvco(short *mval, float *uv) +static void imapaint_compute_uvco(short *mval, float *uv) { areamouseco_to_ipoco(G.v2d, mval, &uv[0], &uv[1]); } -static void imagepaint_paint_tool(IMG_BrushPtr *brush, IMG_CanvasPtr *canvas, IMG_CanvasPtr *clonecanvas, float *prevuv, float *uv) +static void imapaint_paint_tool(ImagePaintBrush *brush, ImagePaintPixmap *canvas, ImagePaintPixmap *clonecanvas, float *prevuv, float *uv) { - int torus = Gip.flag & IMAGEPAINT_TORUS; - ImagePaintTool *tool= &Gip.tool[Gip.current]; + ToolSettings *settings= G.scene->toolsettings; + Brush *curbrush= settings->imapaint.brush; - if(Gip.current == IMAGEPAINT_SOFTEN) - IMG_CanvasSoftenAt(canvas, prevuv[0], prevuv[1], tool->size, tool->rgba[3], tool->innerradius, torus); - else if(Gip.current == IMAGEPAINT_SMEAR) - IMG_CanvasSmear(canvas, prevuv[0], prevuv[1], uv[0], uv[1], tool->size, tool->rgba[3], tool->innerradius, torus); - else if(Gip.current == IMAGEPAINT_CLONE) { - float offx= Gip.clone.offset[0]; - float offy= Gip.clone.offset[1]; + brush->torus= (settings->imapaint.flag & IMAGEPAINT_TORUS)? 1: 0; + brush->blend= curbrush->blend; - IMG_CanvasCloneAt(canvas, clonecanvas, prevuv[0], prevuv[1], offx, offy, tool->size, tool->rgba[3], tool->innerradius); - } - else if(Gip.flag & IMAGEPAINT_TIMED) - IMG_CanvasDrawLineUVEX(canvas, brush, uv[0], uv[1],uv[0], uv[1], torus); + if(settings->imapaint.tool == PAINT_TOOL_SOFTEN) + imapaint_soften_sharpen(canvas, brush, prevuv, 0); + else if(settings->imapaint.tool == PAINT_TOOL_SMEAR) + imapaint_smear(canvas, brush, prevuv, uv); + else if(settings->imapaint.tool == PAINT_TOOL_CLONE) + imapaint_clone(canvas, clonecanvas, brush, prevuv, curbrush->clone.offset); + else if(curbrush->flag & BRUSH_AIRBRUSH) + imapaint_blend_line(canvas, brush, uv, uv); else - IMG_CanvasDrawLineUVEX(canvas, brush, prevuv[0], prevuv[1], uv[0], uv[1], torus); + imapaint_blend_line(canvas, brush, prevuv, uv); } void imagepaint_paint(short mousebutton) { - IMG_BrushPtr *brush; - IMG_CanvasPtr *canvas, *clonecanvas; + ImagePaintBrush *brush; + ImagePaintPixmap *canvas, *clonecanvas=NULL; short prevmval[2], mval[2]; double prevtime, curtime; float prevuv[2], uv[2]; int paint= 0, moved= 0, firsttouch=1 ; - ImagePaintTool *tool= &Gip.tool[Gip.current]; + ToolSettings *settings= G.scene->toolsettings; + Brush *curbrush= settings->imapaint.brush; - if(!imagepaint_init(&brush, &canvas, &clonecanvas)) + if (!(canvas = imapaint_init_canvas(&clonecanvas))) { + if(G.sima->image && G.sima->image->packedfile) + error("Painting in packed images not supported"); return; + } + else if (!(brush = imapaint_init_brush())) { + imapaint_free_canvas(canvas, clonecanvas); + return; + } getmouseco_areawin(prevmval); prevtime = PIL_check_seconds_timer(); - Gip.flag |= IMAGEPAINT_DRAWING; + settings->imapaint.flag |= IMAGEPAINT_DRAWING; while(get_mbut() & mousebutton) { getmouseco_areawin(mval); - moved= paint= (prevmval[0] != mval[0]) || (prevmval[1] != mval[1]); + if(firsttouch) + moved= paint= 1; + else + moved= paint= (prevmval[0] != mval[0]) || (prevmval[1] != mval[1]); - if(Gip.flag & IMAGEPAINT_TIMED) { + if(settings->imapaint.flag & IMAGEPAINT_TIMED) { /* see if need to draw because of timer */ curtime = PIL_check_seconds_timer(); - if(((curtime - prevtime) > (5.0/tool->timing)) || firsttouch) { + if(((curtime - prevtime) > (5.0/curbrush->timing)) || firsttouch) { prevtime= curtime; paint= 1; } else paint= 0; } - else if(paint) { + else if(paint && !firsttouch) { /* check if we moved enough to draw */ float dmval[2], d, dlimit; @@ -233,7 +700,7 @@ void imagepaint_paint(short mousebutton) dmval[1]= prevmval[1] - mval[1]; d= sqrt(dmval[0]*dmval[0] + dmval[1]*dmval[1]); - dlimit= tool->size*G.sima->zoom*tool->timing/200.0; + dlimit= curbrush->size*G.sima->zoom*curbrush->timing/200.0; if (d < dlimit) paint= 0; @@ -241,10 +708,10 @@ void imagepaint_paint(short mousebutton) if(paint) { /* do the actual painting */ - imagepaint_compute_uvco(prevmval, prevuv); - imagepaint_compute_uvco(mval, uv); + imapaint_compute_uvco(prevmval, prevuv); + imapaint_compute_uvco(mval, uv); - imagepaint_paint_tool(brush, canvas, clonecanvas, prevuv, uv); + imapaint_paint_tool(brush, canvas, clonecanvas, prevuv, uv); prevmval[0]= mval[0]; prevmval[1]= mval[1]; @@ -252,25 +719,27 @@ void imagepaint_paint(short mousebutton) firsttouch = 0; if(paint) - imagepaint_redraw(0, paint); - else if(moved && (Gip.flag & IMAGEPAINT_DRAW_TOOL)) - imagepaint_redraw(0, paint); + imapaint_redraw(0, paint); + else if(moved && (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL)) + imapaint_redraw(0, paint); } - Gip.flag &= ~IMAGEPAINT_DRAWING; + settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; - imagepaint_free(brush, canvas, clonecanvas); + imapaint_free_brush(brush); + imapaint_free_canvas(canvas, clonecanvas); G.sima->image->ibuf->userflags |= IB_BITMAPDIRTY; - imagepaint_redraw(1, 0); + imapaint_redraw(1, 0); } void imagepaint_pick(short mousebutton) { - ImagePaintTool *tool= &Gip.tool[Gip.current]; + ToolSettings *settings= G.scene->toolsettings; + Brush *brush= settings->imapaint.brush; - if(Gip.current == IMAGEPAINT_CLONE) { - if(Gip.clone.image && Gip.clone.image->ibuf) { + if(brush && (settings->imapaint.tool == PAINT_TOOL_CLONE)) { + if(brush->clone.image && brush->clone.image->ibuf) { short prevmval[2], mval[2]; float prevuv[2], uv[2]; @@ -281,11 +750,11 @@ void imagepaint_pick(short mousebutton) if((prevmval[0] != mval[0]) || (prevmval[1] != mval[1]) ) { /* mouse moved, so move the clone image */ - imagepaint_compute_uvco(prevmval, prevuv); - imagepaint_compute_uvco(mval, uv); + imapaint_compute_uvco(prevmval, prevuv); + imapaint_compute_uvco(mval, uv); - Gip.clone.offset[0] += uv[0] - prevuv[0]; - Gip.clone.offset[1] += uv[1] - prevuv[1]; + brush->clone.offset[0] += uv[0] - prevuv[0]; + brush->clone.offset[1] += uv[1] - prevuv[1]; force_draw(0); @@ -295,13 +764,172 @@ void imagepaint_pick(short mousebutton) } } } - else { + else if(brush) { extern VPaint Gvp; sample_vpaint(); - tool->rgba[0]= Gvp.r; - tool->rgba[1]= Gvp.g; - tool->rgba[2]= Gvp.b; + brush->rgb[0]= Gvp.r; + brush->rgb[1]= Gvp.g; + brush->rgb[2]= Gvp.b; } } +/* these will be moved */ +int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect); +int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short *xy, float *uv); + +void texturepaint_paint() +{ + Object *ob; + Mesh *me; + TFace *face, *face_old = 0; + short xy[2], xy_old[2]; + //int a, index; + Image *img=NULL, *img_old = NULL; + ImagePaintBrush *brush; + ImagePaintPixmap *canvas = 0; + unsigned int face_index, mousebutton; + char *warn_packed_file = 0; + float uv[2], uv_old[2]; + extern VPaint Gvp; + ImBuf *ibuf= NULL; + + ob = OBACT; + if (!ob) { + error("No active object"); return; + } + if (!(ob->lay & G.vd->lay)) { + error("The active object is not in this layer"); return; + } + me = get_mesh(ob); + if (!me) { + error("The active object does not have a mesh obData"); return; + } + + brush = imapaint_brush_new(Gvp.size, Gvp.size, &Gvp.r, Gvp.a, 0.5); + if (!brush) { + error("Can't create brush"); return; + } + + persp(PERSP_VIEW); + + if (U.flag & USER_LMOUSESELECT) mousebutton = R_MOUSE; + else mousebutton = L_MOUSE; + + getmouseco_areawin(xy_old); + while (get_mbut() & mousebutton) { + getmouseco_areawin(xy); + /* Check if cursor has moved */ + if ((xy[0] != xy_old[0]) || (xy[1] != xy_old[1])) { + + /* Get face to draw on */ + if (!facesel_face_pick(me, xy, &face_index, 0)) face = NULL; + else face = (((TFace*)me->tface)+face_index); + + /* Check if this is another face. */ + if (face != face_old) { + /* The active face changed, check the texture */ + if (face) { + img = face->tpage; + ibuf = (img)? img->ibuf: NULL; + } + else { + img = 0; + } + + if (img != img_old) { + /* Faces have different textures. Finish drawing in the old face. */ + if (face_old && canvas) { + face_pick_uv(ob, me, face_old, xy, uv); + imapaint_blend_line(canvas, brush, uv_old, uv); + img_old->ibuf->userflags |= IB_BITMAPDIRTY; + /* Delete old canvas */ + imapaint_pixmap_free(canvas); + canvas = 0; + } + + /* Create new canvas and start drawing in the new face. */ + if (img) { + if (ibuf && img->packedfile == 0) { + /* MAART: skipx is not set most of the times. Make a guess. */ + canvas = imapaint_pixmap_new(ibuf->x, ibuf->y, (char*)ibuf->rect); + if (canvas) { + face_pick_uv(ob, me, face, xy_old, uv_old); + face_pick_uv(ob, me, face, xy, uv); + imapaint_blend_line(canvas, brush, uv_old, uv); + ibuf->userflags |= IB_BITMAPDIRTY; + } + } + else { + if (img->packedfile) { + warn_packed_file = img->id.name + 2; + img = 0; + } + } + } + } + else { + /* Face changed and faces have the same texture. */ + if (canvas) { + /* Finish drawing in the old face. */ + if (face_old) { + face_pick_uv(ob, me, face_old, xy, uv); + imapaint_blend_line(canvas, brush, uv_old, uv); + img_old->ibuf->userflags |= IB_BITMAPDIRTY; + } + + /* Start drawing in the new face. */ + if (face) { + face_pick_uv(ob, me, face, xy_old, uv_old); + face_pick_uv(ob, me, face, xy, uv); + imapaint_blend_line(canvas, brush, uv_old, uv); + ibuf->userflags |= IB_BITMAPDIRTY; + } + } + } + } + else { + /* Same face, continue drawing */ + if (face && canvas) { + /* Get the new (u,v) coordinates */ + face_pick_uv(ob, me, face, xy, uv); + imapaint_blend_line(canvas, brush, uv_old, uv); + ibuf->userflags |= IB_BITMAPDIRTY; + } + } + + if (face && img) { + /* Make OpenGL aware of a change in the texture */ + free_realtime_image(img); + /* Redraw the view */ + scrarea_do_windraw(curarea); + screen_swapbuffers(); + } + + xy_old[0] = xy[0]; + xy_old[1] = xy[1]; + uv_old[0] = uv[0]; + uv_old[1] = uv[1]; + face_old = face; + img_old = img; + } + } + + imapaint_brush_free(brush); + if (canvas) { + imapaint_pixmap_free(canvas); + canvas = 0; + } + + if (warn_packed_file) { + error("Painting in packed images is not supported: %s", warn_packed_file); + } + + persp(PERSP_WIN); + + BIF_undo_push("UV face draw"); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWIMAGE, 0); + allqueue(REDRAWHEADERS, 0); +} + diff --git a/source/blender/src/space.c b/source/blender/src/space.c index 235c9bcea4b..538f664663d 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -157,7 +157,6 @@ #include "BKE_depsgraph.h" #include "BSE_trans_types.h" -#include "IMG_Api.h" #include "SYS_System.h" /* for the user def menu ... should move elsewhere. */ @@ -1012,7 +1011,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) vertex_paint(); } else if (G.f & G_TEXTUREPAINT) { - face_draw(); + texturepaint_paint(); } break; case MIDDLEMOUSE: diff --git a/source/nan_definitions.mk b/source/nan_definitions.mk index 70ec992917c..9920c2a509b 100644 --- a/source/nan_definitions.mk +++ b/source/nan_definitions.mk @@ -80,7 +80,6 @@ endif export NAN_MEMUTIL ?= $(LCGDIR)/memutil export NAN_CONTAINER ?= $(LCGDIR)/container export NAN_ACTION ?= $(LCGDIR)/action - export NAN_IMG ?= $(LCGDIR)/img export NAN_GHOST ?= $(LCGDIR)/ghost export NAN_TEST_VERBOSITY ?= 1 export NAN_BMFONT ?= $(LCGDIR)/bmfont