diff options
Diffstat (limited to 'source')
48 files changed, 1106 insertions, 192 deletions
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index 92544f19721..16ca5d7542d 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -465,6 +465,9 @@ void init_actuator(bActuator *act) case ACT_PARENT: act->data = MEM_callocN(sizeof( bParentActuator ), "parent act"); break; + case ACT_STATE: + act->data = MEM_callocN(sizeof( bStateActuator ), "state act"); + break; default: ; /* this is very severe... I cannot make any memory for this */ /* logic brick... */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index fa7cbb06139..9cfce5e34fa 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3011,6 +3011,9 @@ static void lib_link_object(FileData *fd, Main *main) bParentActuator *parenta = act->data; parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob); } + else if(act->type==ACT_STATE) { + /* bStateActuator *statea = act->data; */ + } act= act->next; } @@ -3307,11 +3310,19 @@ static void direct_link_object(FileData *fd, Object *ob) direct_link_constraints(fd, &ob->constraints); link_glob_list(fd, &ob->controllers); + if (ob->init_state) { + /* if a known first state is specified, set it so that the game will start ok */ + ob->state = ob->init_state; + } else if (!ob->state) { + ob->state = 1; + } cont= ob->controllers.first; while(cont) { cont->data= newdataadr(fd, cont->data); cont->links= newdataadr(fd, cont->links); test_pointer_array(fd, (void **)&cont->links); + if (cont->state_mask == 0) + cont->state_mask = 1; cont= cont->next; } @@ -7635,6 +7646,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } + /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */ diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 2595b95bbf0..9f28e13ff7b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -715,6 +715,9 @@ static void write_actuators(WriteData *wd, ListBase *lb) case ACT_PARENT: writestruct(wd, DATA, "bParentActuator", 1, act->data); break; + case ACT_STATE: + writestruct(wd, DATA, "bStateActuator", 1, act->data); + break; default: ; /* error: don't know how to write this file */ } diff --git a/source/blender/include/BIF_butspace.h b/source/blender/include/BIF_butspace.h index cbbd8013c82..f0b37814947 100644 --- a/source/blender/include/BIF_butspace.h +++ b/source/blender/include/BIF_butspace.h @@ -99,6 +99,8 @@ extern void validate_editbonebutton_cb(void *bonev, void *namev); #define BUTS_ACT_SEL 64 #define BUTS_ACT_ACT 128 #define BUTS_ACT_LINK 256 +#define BUTS_SENS_STATE 512 +#define BUTS_ACT_STATE 1024 /* buttons grid */ diff --git a/source/blender/include/BIF_interface.h b/source/blender/include/BIF_interface.h index fbd4e4ecd91..3da4466d4d3 100644 --- a/source/blender/include/BIF_interface.h +++ b/source/blender/include/BIF_interface.h @@ -185,6 +185,7 @@ void uiDrawBlock(struct uiBlock *block); void uiGetMouse(int win, short *adr); void uiComposeLinks(uiBlock *block); void uiSetButLock(int val, char *lockstr); +uiBut *uiFindInlink(uiBlock *block, void *poin); void uiClearButLock(void); int uiDoBlocks(struct ListBase *lb, int event, int movemouse_quit); void uiSetCurFont(uiBlock *block, int index); diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index 7571d64be91..c0542e3f34c 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -52,6 +52,8 @@ struct Image; #define BUTS_ACT_SEL 64 #define BUTS_ACT_ACT 128 #define BUTS_ACT_LINK 256 +#define BUTS_SENS_STATE 512 +#define BUTS_ACT_STATE 1024 /* internal */ @@ -583,6 +585,8 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la #define B_SETACTOR 2715 #define B_SETMAINACTOR 2716 #define B_SETDYNA 2717 +#define B_SET_STATE_BIT 2718 +#define B_INIT_STATE_BIT 2719 /* *********************** */ #define B_FPAINTBUTS 2900 diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h index a326f5b01d6..417ba540e2c 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -208,6 +208,11 @@ typedef struct bParentActuator { struct Object *ob; } bParentActuator; +typedef struct bStateActuator { + int type; /* 0=Set, 1=Add, 2=Rem, 3=Chg */ + unsigned int mask; /* the bits to change */ +} bStateActuator; + typedef struct bActuator { struct bActuator *next, *prev, *mynew; short type; @@ -279,11 +284,14 @@ typedef struct FreeCamera { #define ACT_2DFILTER 19 #define ACT_PARENT 20 #define ACT_SHAPEACTION 21 +#define ACT_STATE 22 /* actuator flag */ #define ACT_SHOW 1 #define ACT_DEL 2 #define ACT_NEW 4 +#define ACT_LINKED 8 +#define ACT_VISIBLE 16 /* link codes */ #define LINK_SENSOR 0 diff --git a/source/blender/makesdna/DNA_controller_types.h b/source/blender/makesdna/DNA_controller_types.h index 95c9b0d0cf7..cc9215e7d14 100644 --- a/source/blender/makesdna/DNA_controller_types.h +++ b/source/blender/makesdna/DNA_controller_types.h @@ -57,7 +57,7 @@ typedef struct bController { struct bSensor **slinks; short val, valo; - int pad5; + unsigned int state_mask; } bController; @@ -71,6 +71,7 @@ typedef struct bController { #define CONT_SHOW 1 #define CONT_DEL 2 #define CONT_NEW 4 +#define CONT_MASK 8 #endif diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 83168248b9a..c4e8cb4925b 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -216,7 +216,9 @@ typedef struct Object { struct DerivedMesh *derivedDeform, *derivedFinal; int lastDataMask; /* the custom data layer mask that was last used to calculate derivedDeform and derivedFinal */ - int pad; + unsigned int state; /* bit masks of game controllers that are active */ + unsigned int init_state; /* bit masks of initial state as recorded by the users */ + int pad2; /*#ifdef WITH_VERSE*/ void *vnode; /* pointer at object VerseNode */ @@ -440,6 +442,8 @@ extern Object workob; #define OB_ADDCONT 512 #define OB_ADDACT 1024 #define OB_SHOWCONT 2048 +#define OB_SETSTBIT 4096 +#define OB_INITSTBIT 8192 /* ob->restrictflag */ #define OB_RESTRICT_VIEW 1 diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h index 90e2b8f9f41..3fd57a85349 100644 --- a/source/blender/makesdna/DNA_sensor_types.h +++ b/source/blender/makesdna/DNA_sensor_types.h @@ -202,6 +202,7 @@ typedef struct bJoystickSensor { #define SENS_DEL 2 #define SENS_NEW 4 #define SENS_NOT 8 +#define SENS_VISIBLE 16 /* sensor->pulse */ #define SENS_PULSE_CONT 0 diff --git a/source/blender/src/buttons_logic.c b/source/blender/src/buttons_logic.c index b6877b2e2b7..c4fc17bc4d0 100644 --- a/source/blender/src/buttons_logic.c +++ b/source/blender/src/buttons_logic.c @@ -88,6 +88,7 @@ #include "mydevice.h" #include "nla.h" /* For __NLA : Important, do not remove */ #include "butspace.h" // own module +#include "interface.h" /* internals */ void buttons_enji(uiBlock *, Object *); @@ -228,7 +229,7 @@ static void sca_move_sensor(void *datav, void *data2_unused) bSensor *sens_to_delete= datav; int val; Base *base; - bSensor *sens; + bSensor *sens, *tmp; val= pupmenu("Move up%x1|Move down %x2"); @@ -245,12 +246,24 @@ static void sca_move_sensor(void *datav, void *data2_unused) if(sens) { if( val==1 && sens->prev) { - BLI_remlink(&base->object->sensors, sens); - BLI_insertlinkbefore(&base->object->sensors, sens->prev, sens); + for (tmp=sens->prev; tmp; tmp=tmp->prev) { + if (tmp->flag & SENS_VISIBLE) + break; + } + if (tmp) { + BLI_remlink(&base->object->sensors, sens); + BLI_insertlinkbefore(&base->object->sensors, tmp, sens); + } } else if( val==2 && sens->next) { - BLI_remlink(&base->object->sensors, sens); - BLI_insertlink(&base->object->sensors, sens->next, sens); + for (tmp=sens->next; tmp; tmp=tmp->next) { + if (tmp->flag & SENS_VISIBLE) + break; + } + if (tmp) { + BLI_remlink(&base->object->sensors, sens); + BLI_insertlink(&base->object->sensors, tmp, sens); + } } BIF_undo_push("Move sensor"); allqueue(REDRAWBUTSLOGIC, 0); @@ -267,7 +280,7 @@ static void sca_move_controller(void *datav, void *data2_unused) bController *controller_to_del= datav; int val; Base *base; - bController *cont; + bController *cont, *tmp; val= pupmenu("Move up%x1|Move down %x2"); @@ -284,12 +297,27 @@ static void sca_move_controller(void *datav, void *data2_unused) if(cont) { if( val==1 && cont->prev) { - BLI_remlink(&base->object->controllers, cont); - BLI_insertlinkbefore(&base->object->controllers, cont->prev, cont); + /* locate the controller that has the same state mask but is earlier in the list */ + tmp = cont->prev; + while(tmp) { + if(tmp->state_mask & cont->state_mask) + break; + tmp = tmp->prev; + } + if (tmp) { + BLI_remlink(&base->object->controllers, cont); + BLI_insertlinkbefore(&base->object->controllers, tmp, cont); + } } else if( val==2 && cont->next) { + tmp = cont->next; + while(tmp) { + if(tmp->state_mask & cont->state_mask) + break; + tmp = tmp->next; + } BLI_remlink(&base->object->controllers, cont); - BLI_insertlink(&base->object->controllers, cont->next, cont); + BLI_insertlink(&base->object->controllers, tmp, cont); } BIF_undo_push("Move controller"); allqueue(REDRAWBUTSLOGIC, 0); @@ -306,7 +334,7 @@ static void sca_move_actuator(void *datav, void *data2_unused) bActuator *actuator_to_move= datav; int val; Base *base; - bActuator *act; + bActuator *act, *tmp; val= pupmenu("Move up%x1|Move down %x2"); @@ -323,12 +351,25 @@ static void sca_move_actuator(void *datav, void *data2_unused) if(act) { if( val==1 && act->prev) { - BLI_remlink(&base->object->actuators, act); - BLI_insertlinkbefore(&base->object->actuators, act->prev, act); + /* locate the first visible actuators before this one */ + for (tmp = act->prev; tmp; tmp=tmp->prev) { + if (tmp->flag & ACT_VISIBLE) + break; + } + if (tmp) { + BLI_remlink(&base->object->actuators, act); + BLI_insertlinkbefore(&base->object->actuators, tmp, act); + } } else if( val==2 && act->next) { - BLI_remlink(&base->object->actuators, act); - BLI_insertlink(&base->object->actuators, act->next, act); + for (tmp=act->next; tmp; tmp=tmp->next) { + if (tmp->flag & ACT_VISIBLE) + break; + } + if (tmp) { + BLI_remlink(&base->object->actuators, act); + BLI_insertlink(&base->object->actuators, tmp, act); + } } BIF_undo_push("Move actuator"); allqueue(REDRAWBUTSLOGIC, 0); @@ -348,7 +389,7 @@ void do_logic_buts(unsigned short event) bActuator *act; Base *base; Object *ob; - int didit; + int didit, bit; ob= OBACT; if(ob==0) return; @@ -462,6 +503,18 @@ void do_logic_buts(unsigned short event) make_unique_prop_names(cont->name); base->object->scaflag |= OB_SHOWCONT; BLI_addtail(&(base->object->controllers), cont); + /* set the controller state mask from the current object state. + A controller is always in a single state, so select the lowest bit set + from the object state */ + for (bit=0; bit<32; bit++) { + if (base->object->state & (1<<bit)) + break; + } + cont->state_mask = (1<<bit); + if (cont->state_mask == 0) { + /* shouldn't happen, object state is never 0 */ + cont->state_mask = 1; + } } base= base->next; } @@ -469,6 +522,32 @@ void do_logic_buts(unsigned short event) allqueue(REDRAWBUTSLOGIC, 0); break; + case B_SET_STATE_BIT: + base= FIRSTBASE; + while(base) { + if(base->object->scaflag & OB_SETSTBIT) { + base->object->scaflag &= ~OB_SETSTBIT; + base->object->state = 0x3FFFFFFF; + } + base= base->next; + } + allqueue(REDRAWBUTSLOGIC, 0); + break; + + case B_INIT_STATE_BIT: + base= FIRSTBASE; + while(base) { + if(base->object->scaflag & OB_INITSTBIT) { + base->object->scaflag &= ~OB_INITSTBIT; + base->object->state = base->object->init_state; + if (!base->object->state) + base->object->state = 1; + } + base= base->next; + } + allqueue(REDRAWBUTSLOGIC, 0); + break; + case B_CHANGE_CONT: base= FIRSTBASE; while(base) { @@ -505,7 +584,7 @@ void do_logic_buts(unsigned short event) BIF_undo_push("Delete controller"); allqueue(REDRAWBUTSLOGIC, 0); break; - + case B_ADD_ACT: base= FIRSTBASE; while(base) { @@ -717,6 +796,8 @@ static char *actuator_name(int type) return "2D Filter"; case ACT_PARENT: return "Parent"; + case ACT_STATE: + return "State"; } return "unknown"; } @@ -732,21 +813,21 @@ static char *actuator_pup(Object *owner) return "Actuators %t|Action %x15|Motion %x0|Constraint %x9|Ipo %x1" "|Camera %x3|Sound %x5|Property %x6|Edit Object %x10" "|Scene %x11|Random %x13|Message %x14|CD %x16|Game %x17" - "|Visibility %x18|2D Filter %x19|Parent %x20"; + "|Visibility %x18|2D Filter %x19|Parent %x20|State %x22"; break; case OB_MESH: return "Actuators %t|Shape Action %x21|Motion %x0|Constraint %x9|Ipo %x1" "|Camera %x3|Sound %x5|Property %x6|Edit Object %x10" "|Scene %x11|Random %x13|Message %x14|CD %x16|Game %x17" - "|Visibility %x18|2D Filter %x19|Parent %x20"; + "|Visibility %x18|2D Filter %x19|Parent %x20|State %x22"; break; default: return "Actuators %t|Motion %x0|Constraint %x9|Ipo %x1" "|Camera %x3|Sound %x5|Property %x6|Edit Object %x10" "|Scene %x11|Random %x13|Message %x14|CD %x16|Game %x17" - "|Visibility %x18|2D Filter %x19|Parent %x20"; + "|Visibility %x18|2D Filter %x19|Parent %x20|State %x22"; } } @@ -815,7 +896,8 @@ static ID **get_selected_and_linked_obs(short *count, short scavisflag) if(scavisflag & BUTS_ACT_ACT) OBACT->scavisflag |= OB_VIS_ACT; } - if(scavisflag & (BUTS_SENS_LINK|BUTS_CONT_LINK|BUTS_ACT_LINK)) { + /* BUTS_XXX_STATE are similar to BUTS_XXX_LINK for selecting the object */ + if(scavisflag & (BUTS_SENS_LINK|BUTS_CONT_LINK|BUTS_ACT_LINK|BUTS_SENS_STATE|BUTS_ACT_STATE)) { doit= 1; while(doit) { doit= 0; @@ -824,7 +906,7 @@ static ID **get_selected_and_linked_obs(short *count, short scavisflag) while(ob) { /* 1st case: select sensor when controller selected */ - if((scavisflag & BUTS_SENS_LINK) && (ob->scavisflag & OB_VIS_SENS)==0) { + if((scavisflag & (BUTS_SENS_LINK|BUTS_SENS_STATE)) && (ob->scavisflag & OB_VIS_SENS)==0) { sens= ob->sensors.first; while(sens) { for(a=0; a<sens->totlinks; a++) { @@ -879,7 +961,7 @@ static ID **get_selected_and_linked_obs(short *count, short scavisflag) } /* 4th case: select actuator when controller selected */ - if( (scavisflag & BUTS_ACT_LINK) && (ob->scavisflag & OB_VIS_CONT)) { + if( (scavisflag & (BUTS_ACT_LINK|BUTS_ACT_STATE)) && (ob->scavisflag & OB_VIS_CONT)) { cont= ob->controllers.first; while(cont) { for(a=0; a<cont->totlinks; a++) { @@ -1458,6 +1540,7 @@ static int get_col_actuator(int type) case ACT_GAME: return TH_BUT_SETTING2; case ACT_VISIBILITY: return TH_BUT_NUM; case ACT_CONSTRAINT: return TH_BUT_ACTION; + case ACT_STATE: return TH_BUT_SETTING2; default: return TH_BUT_NEUTRAL; } } @@ -1468,7 +1551,23 @@ static void set_col_actuator(int item, int medium) } -static short draw_actuatorbuttons(bActuator *act, uiBlock *block, short xco, short yco, short width) +char *get_state_name(Object *ob, short bit) +{ + bController *cont; + unsigned int mask; + + mask = (1<<bit); + cont = ob->controllers.first; + while (cont) { + if (cont->state_mask & mask) { + return cont->name; + } + cont = cont->next; + } + return (char*)""; +} + +static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, short xco, short yco, short width) { bSoundActuator *sa = NULL; bCDActuator *cda = NULL; @@ -1487,11 +1586,12 @@ static short draw_actuatorbuttons(bActuator *act, uiBlock *block, short xco, sho bVisibilityActuator *visAct = NULL; bTwoDFilterActuator *tdfa = NULL; bParentActuator *parAct = NULL; + bStateActuator *staAct = NULL; float *fp; short ysize = 0, wval; - char *str; - int myline; + char *str, name[32]; + int myline, stbit; /* yco is at the top of the rect, draw downwards */ uiBlockSetEmboss(block, UI_EMBOSSM); @@ -2022,6 +2122,37 @@ static short draw_actuatorbuttons(bActuator *act, uiBlock *block, short xco, sho break; + case ACT_STATE: + ysize = 34; + + glRects(xco, yco-ysize, xco+width, yco); + uiEmboss((float)xco, + (float)yco-ysize, (float)xco+width, (float)yco, 1); + + staAct = act->data; + + str= "Operation %t|Cpy %x0|Add %x1|Sub %x2|Inv %x3"; + + uiDefButI(block, MENU, B_REDR, str, + xco + 10, yco - 24, 65, 19, &staAct->type, + 0.0, 0.0, 0, 0, + "Select the bit operation on object state mask"); + + for (wval=0; wval<15; wval+=5) { + uiBlockBeginAlign(block); + for (stbit=0; stbit<5; stbit++) { + uiDefButBitI(block, TOG, (1<<(stbit+wval)), 0, "", (short)(xco+85+12*stbit+13*wval), yco-17, 12, 12, (int *)&(staAct->mask), 0, 0, 0, 0, get_state_name(ob, (short)(wval+stbit))); + } + for (stbit=0; stbit<5; stbit++) { + uiDefButBitI(block, TOG, (1<<(stbit+wval+15)), 0, "", (short)(xco+85+12*stbit+13*wval), yco-29, 12, 12, (int *)&(staAct->mask), 0, 0, 0, 0, get_state_name(ob, (short)(wval+stbit+15))); + } + } + uiBlockEndAlign(block); + + yco-= ysize; + + break; + case ACT_RANDOM: ysize = 69; @@ -2596,6 +2727,120 @@ void buttons_bullet(uiBlock *block, Object *ob) uiBlockEndAlign(block); } +static void check_object_state(void *arg1_but, void *arg2_mask) +{ + unsigned int *cont_mask = arg2_mask; + uiBut *but = arg1_but; + + if (*cont_mask == 0 || !(G.qual & LR_SHIFTKEY)) + *cont_mask = (1<<but->retval); + but->retval = B_REDR; +} + +static void check_controller_state_mask(void *arg1_but, void *arg2_mask) +{ + unsigned int *cont_mask = arg2_mask; + uiBut *but = arg1_but; + + /* a controller is always in a single state */ + *cont_mask = (1<<but->retval); + but->retval = B_REDR; +} + +static int first_bit(unsigned int mask) +{ + int bit; + + for (bit=0; bit<32; bit++) { + if (mask & (1<<bit)) + return bit; + } + return -1; +} + +static uiBlock *controller_state_mask_menu(void *arg_cont) +{ + uiBlock *block; + uiBut *but; + bController *cont = arg_cont; + int mask; + + short yco = 12, xco = 0, stbit, offset; + + block= uiNewBlock(&curarea->uiblocks, "Controller state mask", UI_EMBOSS, UI_HELV, curarea->win); + + /* use this for a fake extra empy space around the buttons */ + uiDefBut(block, LABEL, 0, "", -5, -5, 200, 34, NULL, 0, 0, 0, 0, ""); + + for (offset=0; offset<15; offset+=5) { + uiBlockBeginAlign(block); + for (stbit=0; stbit<5; stbit++) { + but = uiDefButBitI(block, TOG, (1<<(stbit+offset)), (stbit+offset), "", (short)(xco+12*stbit+13*offset), yco, 12, 12, (int *)&(cont->state_mask), 0, 0, 0, 0, ""); + uiButSetFunc(but, check_controller_state_mask, but, &(cont->state_mask)); + } + for (stbit=0; stbit<5; stbit++) { + but = uiDefButBitI(block, TOG, (1<<(stbit+offset+15)), (stbit+offset+15), "", (short)(xco+12*stbit+13*offset), yco-12, 12, 12, (int *)&(cont->state_mask), 0, 0, 0, 0, ""); + uiButSetFunc(but, check_controller_state_mask, but, &(cont->state_mask)); + } + } + uiBlockEndAlign(block); + + uiBlockSetDirection(block, UI_TOP); + + return block; +} + +static void do_object_state_menu(void *arg, int event) +{ + Object *ob = arg; + + switch (event) { + case 0: + ob->state = 0x3FFFFFFF; + break; + case 1: + ob->state = ob->init_state; + if (!ob->state) + ob->state = 1; + break; + case 2: + ob->init_state = ob->state; + break; + } + allqueue(REDRAWBUTSLOGIC, 0); +} + +static uiBlock *object_state_mask_menu(void *arg_obj) +{ + uiBlock *block; + uiBut *but; + short xco = 0; + + block= uiNewBlock(&curarea->uiblocks, "obstatemenu", UI_EMBOSSP, UI_HELV, curarea->win); + uiBlockSetButmFunc(block, do_object_state_menu, arg_obj); + + uiDefBut(block, BUTM, 1, "Set all bits", 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, ""); + uiDefBut(block, BUTM, 1, "Recall init state", 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, ""); + uiDefBut(block, SEPR, 0, "", 0, (short)(xco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, ""); + uiDefBut(block, BUTM, 1, "Store init state", 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 2, ""); + + uiBlockSetDirection(block, UI_TOP); + return block; +} + +static int is_sensor_linked(uiBlock *block, bSensor *sens) +{ + bController *cont; + int i, count; + + for (count=0, i=0; i<sens->totlinks; i++) { + cont = sens->links[i]; + if (uiFindInlink(block, cont) != NULL) + return 1; + } + return 0; +} + /* never used, see CVS 1.134 for the code */ /* static FreeCamera *new_freecamera(void) */ @@ -2614,7 +2859,7 @@ void logic_buts(void) uiBlock *block; uiBut *but; World *wrld; - int a; + int a, iact, stbit, offset; short xco, yco, count, width, ycoo; char *pupstr, name[32]; @@ -2686,158 +2931,241 @@ void logic_buts(void) uiClearButLock(); idar= get_selected_and_linked_obs(&count, G.buts->scaflag); - + + /* clean ACT_LINKED and ACT_VISIBLE of all potentially visible actuators so that + we can determine which is actually linked/visible */ + for(a=0; a<count; a++) { + ob= (Object *)idar[a]; + act= ob->actuators.first; + while(act) { + act->flag &= ~(ACT_LINKED|ACT_VISIBLE); + act = act->next; + } + /* same for sensors */ + sens= ob->sensors.first; + while(sens) { + sens->flag &= ~(SENS_VISIBLE); + sens = sens->next; + } + } + + /* start with the controller because we need to know which one is visible */ /* ******************************* */ - xco= 375; yco= 170; width= 230; + xco= 695; yco= 170; width= 275; uiBlockSetEmboss(block, UI_EMBOSSP); - uiDefBlockBut(block, sensor_menu, NULL, "Sensors", xco-10, yco+35, 80, 19, ""); + uiDefBlockBut(block, controller_menu, NULL, "Controllers", xco-10, yco+35, 100, 19, ""); uiBlockSetEmboss(block, UI_EMBOSS); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, BUTS_SENS_SEL, B_REDR, "Sel", xco+110, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects"); - uiDefButBitS(block, TOG, BUTS_SENS_ACT, B_REDR, "Act", xco+110+(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object"); - uiDefButBitS(block, TOG, BUTS_SENS_LINK, B_REDR, "Link", xco+110+2*(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Controller"); + uiDefButBitS(block, TOG, BUTS_CONT_SEL, B_REDR, "Sel", xco+110, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects"); + uiDefButBitS(block, TOG, BUTS_CONT_ACT, B_REDR, "Act", xco+110+(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object"); + uiDefButBitS(block, TOG, BUTS_CONT_LINK, B_REDR, "Link", xco+110+2*(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Sensor/Actuator"); uiBlockEndAlign(block); + ob= OBACT; + for(a=0; a<count; a++) { ob= (Object *)idar[a]; uiClearButLock(); uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE); - - if( (ob->scavisflag & OB_VIS_SENS) == 0) continue; - + if( (ob->scavisflag & OB_VIS_CONT) == 0) continue; + /* presume it is only objects for now */ uiBlockSetEmboss(block, UI_EMBOSS); uiBlockBeginAlign(block); - if(ob->sensors.first) uiSetCurFont(block, UI_HELVB); - uiDefButBitS(block, TOG, OB_SHOWSENS, B_REDR, ob->id.name+2,(short)(xco-10), yco, (short)(width-30), 19, &ob->scaflag, 0, 31, 0, 0, "Object name, click to show/hide sensors"); - if(ob->sensors.first) uiSetCurFont(block, UI_HELV); - uiDefButBitS(block, TOG, OB_ADDSENS, B_ADD_SENS, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Sensor"); + if(ob->controllers.first) uiSetCurFont(block, UI_HELVB); + uiDefButBitS(block, TOG, OB_SHOWCONT, B_REDR, ob->id.name+2,(short)(xco-10), yco, (short)(width-30), 19, &ob->scaflag, 0, 0, 0, 0, "Active Object name"); + if(ob->controllers.first) uiSetCurFont(block, UI_HELV); + uiDefButBitS(block, TOG, OB_ADDCONT, B_ADD_CONT, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Controller"); uiBlockEndAlign(block); - yco-=20; + yco-=17; - if(ob->scaflag & OB_SHOWSENS) { - - sens= ob->sensors.first; - while(sens) { - uiBlockSetEmboss(block, UI_EMBOSSM); - uiDefIconButBitS(block, TOG, SENS_DEL, B_DEL_SENS, ICON_X, xco, yco, 22, 19, &sens->flag, 0, 0, 0, 0, "Delete Sensor"); - uiDefIconButBitS(block, ICONTOG, SENS_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &sens->flag, 0, 0, 0, 0, "Sensor settings"); + /* mark all actuators linked to these controllers */ + /* note that some of these actuators could be from objects that are not in the display list. + It's ok because those actuators will not be displayed here */ + cont= ob->controllers.first; + while(cont) { + for (iact=0; iact<cont->totlinks; iact++) { + act = cont->links[iact]; + act->flag |= ACT_LINKED; + } + cont = cont->next; + } - ycoo= yco; - if(sens->flag & SENS_SHOW) - { - uiDefButS(block, MENU, B_CHANGE_SENS, sensor_pup(), (short)(xco+22), yco, 100, 19, &sens->type, 0, 0, 0, 0, "Sensor type"); - but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, sens->name, 0, 31, 0, 0, "Sensor name"); - uiButSetFunc(but, make_unique_prop_names_cb, sens->name, (void*) 0); + if(ob->scaflag & OB_SHOWCONT) { - sens->otype= sens->type; - yco= draw_sensorbuttons(sens, block, xco, yco, width,ob->id.name); - if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2; + /* first show the state */ + uiBlockSetEmboss(block, UI_EMBOSSP); + uiDefBlockBut(block, object_state_mask_menu, ob, "State", (short)(xco-10), (short)(yco-10), 40, 19, "Object state menu: store and retrieve initial state"); + uiBlockSetEmboss(block, UI_EMBOSS); + if (!ob->state) + ob->state = 1; + for (offset=0; offset<15; offset+=5) { + uiBlockBeginAlign(block); + for (stbit=0; stbit<5; stbit++) { + but = uiDefButBitI(block, TOG, 1<<(stbit+offset), stbit+offset, "", (short)(xco+35+12*stbit+13*offset), yco, 12, 12, (int *)&(ob->state), 0, 0, 0, 0, get_state_name(ob, (short)(stbit+offset))); + uiButSetFunc(but, check_object_state, but, &(ob->state)); } - else { - set_col_sensor(sens->type, 1); - glRecti(xco+22, yco, xco+width-22,yco+19); - but= uiDefBut(block, LABEL, 0, sensor_name(sens->type), (short)(xco+22), yco, 100, 19, sens, 0, 0, 0, 0, ""); - uiButSetFunc(but, sca_move_sensor, sens, NULL); - but= uiDefBut(block, LABEL, 0, sens->name, (short)(xco+122), yco, (short)(width-144), 19, sens, 0, 31, 0, 0, ""); - uiButSetFunc(but, sca_move_sensor, sens, NULL); + for (stbit=0; stbit<5; stbit++) { + but = uiDefButBitI(block, TOG, 1<<(stbit+offset+15), stbit+offset+15, "", (short)(xco+35+12*stbit+13*offset), yco-12, 12, 12, (int *)&(ob->state), 0, 0, 0, 0, get_state_name(ob, (short)(stbit+offset+15))); + uiButSetFunc(but, check_object_state, but, &(ob->state)); } + } + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, OB_SETSTBIT, B_SET_STATE_BIT, "All",(short)(xco+235), yco-10, 25, 19, &ob->scaflag, 0, 0, 0, 0, "Set all state bits"); + uiDefButBitS(block, TOG, OB_INITSTBIT, B_INIT_STATE_BIT, "Ini",(short)(xco+260), yco-10, 25, 19, &ob->scaflag, 0, 0, 0, 0, "Set the initial state"); + uiBlockEndAlign(block); - but= uiDefIconBut(block, LINK, 0, ICON_LINK, (short)(xco+width), ycoo, 19, 19, NULL, 0, 0, 0, 0, ""); - uiSetButLink(but, NULL, (void ***)&(sens->links), &sens->totlinks, LINK_SENSOR, LINK_CONTROLLER); - - yco-=20; + yco-=35; + + /* display only the controllers that match the current state */ + offset = 0; + for (stbit=0; stbit<32; stbit++) { + if (!(ob->state & (1<<stbit))) + continue; + /* add a separation between controllers of different states */ + if (offset) { + offset = 0; + yco -= 6; + } + cont= ob->controllers.first; + while(cont) { + if (cont->state_mask & (1<<stbit)) { + /* this controller is visible, mark all its actuator */ + for (iact=0; iact<cont->totlinks; iact++) { + act = cont->links[iact]; + act->flag |= ACT_VISIBLE; + } + uiBlockSetEmboss(block, UI_EMBOSSM); + uiDefIconButBitS(block, TOG, CONT_DEL, B_DEL_CONT, ICON_X, xco, yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Delete Controller"); + uiDefIconButBitS(block, ICONTOG, CONT_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Controller settings"); + uiBlockSetEmboss(block, UI_EMBOSSP); + sprintf(name, "%d", first_bit(cont->state_mask)+1); + uiDefBlockBut(block, controller_state_mask_menu, cont, name, (short)(xco+width-44), yco, 22, 19, "Set controller state mask"); + uiBlockSetEmboss(block, UI_EMBOSSM); + + if(cont->flag & CONT_SHOW) { + cont->otype= cont->type; + uiDefButS(block, MENU, B_CHANGE_CONT, controller_pup(),(short)(xco+22), yco, 100, 19, &cont->type, 0, 0, 0, 0, "Controller type"); + but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-166), 19, cont->name, 0, 31, 0, 0, "Controller name"); + uiButSetFunc(but, make_unique_prop_names_cb, cont->name, (void*) 0); + + ycoo= yco; + yco= draw_controllerbuttons(cont, block, xco, yco, width); + if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2; + } + else { + cpack(0x999999); + glRecti(xco+22, yco, xco+width-22,yco+19); + but= uiDefBut(block, LABEL, 0, controller_name(cont->type), (short)(xco+22), yco, 100, 19, cont, 0, 0, 0, 0, "Controller type"); + uiButSetFunc(but, sca_move_controller, cont, NULL); + but= uiDefBut(block, LABEL, 0, cont->name,(short)(xco+122), yco,(short)(width-166), 19, cont, 0, 0, 0, 0, "Controller name"); + uiButSetFunc(but, sca_move_controller, cont, NULL); + ycoo= yco; + } + + but= uiDefIconBut(block, LINK, 0, ICON_LINK, (short)(xco+width), ycoo, 19, 19, NULL, 0, 0, 0, 0, ""); + uiSetButLink(but, NULL, (void ***)&(cont->links), &cont->totlinks, LINK_CONTROLLER, LINK_ACTUATOR); + + uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, cont, LINK_CONTROLLER, 0, 0, 0, ""); + /* offset is >0 if at least one controller was displayed */ + offset++; + yco-=20; + } + cont= cont->next; + } - sens= sens->next; } yco-= 6; } } - + /* ******************************* */ - xco= 675; yco= 170; width= 230; + xco= 375; yco= 170; width= 250; uiBlockSetEmboss(block, UI_EMBOSSP); - uiDefBlockBut(block, controller_menu, NULL, "Controllers", xco-10, yco+35, 100, 19, ""); + uiDefBlockBut(block, sensor_menu, NULL, "Sensors", xco-10, yco+35, 70, 19, ""); uiBlockSetEmboss(block, UI_EMBOSS); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, BUTS_CONT_SEL, B_REDR, "Sel", xco+110, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects"); - uiDefButBitS(block, TOG, BUTS_CONT_ACT, B_REDR, "Act", xco+110+(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object"); - uiDefButBitS(block, TOG, BUTS_CONT_LINK, B_REDR, "Link", xco+110+2*(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Sensor/Actuator"); + uiDefButBitS(block, TOG, BUTS_SENS_SEL, B_REDR, "Sel", xco+80, yco+35, (width-70)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects"); + uiDefButBitS(block, TOG, BUTS_SENS_ACT, B_REDR, "Act", xco+80+(width-70)/4, yco+35, (width-70)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object"); + uiDefButBitS(block, TOG, BUTS_SENS_LINK, B_REDR, "Link", xco+80+2*(width-70)/4, yco+35, (width-70)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Controller"); + uiDefButBitS(block, TOG, BUTS_SENS_STATE, B_REDR, "Sta", xco+80+3*(width-70)/4, yco+35, (width-70)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show only sensors connected to active states"); uiBlockEndAlign(block); - ob= OBACT; - for(a=0; a<count; a++) { ob= (Object *)idar[a]; uiClearButLock(); uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE); - if( (ob->scavisflag & OB_VIS_CONT) == 0) continue; - + + if( (ob->scavisflag & OB_VIS_SENS) == 0) continue; + /* presume it is only objects for now */ uiBlockSetEmboss(block, UI_EMBOSS); uiBlockBeginAlign(block); - if(ob->controllers.first) uiSetCurFont(block, UI_HELVB); - uiDefButBitS(block, TOG, OB_SHOWCONT, B_REDR, ob->id.name+2,(short)(xco-10), yco, (short)(width-30), 19, &ob->scaflag, 0, 0, 0, 0, "Active Object name"); - if(ob->controllers.first) uiSetCurFont(block, UI_HELV); - uiDefButBitS(block, TOG, OB_ADDCONT, B_ADD_CONT, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Controller"); + if(ob->sensors.first) uiSetCurFont(block, UI_HELVB); + uiDefButBitS(block, TOG, OB_SHOWSENS, B_REDR, ob->id.name+2,(short)(xco-10), yco, (short)(width-30), 19, &ob->scaflag, 0, 31, 0, 0, "Object name, click to show/hide sensors"); + if(ob->sensors.first) uiSetCurFont(block, UI_HELV); + uiDefButBitS(block, TOG, OB_ADDSENS, B_ADD_SENS, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Sensor"); uiBlockEndAlign(block); yco-=20; - if(ob->scaflag & OB_SHOWCONT) { - - cont= ob->controllers.first; - while(cont) { - uiBlockSetEmboss(block, UI_EMBOSSM); - uiDefIconButBitS(block, TOG, CONT_DEL, B_DEL_CONT, ICON_X, xco, yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Delete Controller"); - uiDefIconButBitS(block, ICONTOG, CONT_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Controller settings"); - - if(cont->flag & CONT_SHOW) { - cont->otype= cont->type; - uiDefButS(block, MENU, B_CHANGE_CONT, controller_pup(),(short)(xco+22), yco, 100, 19, &cont->type, 0, 0, 0, 0, "Controller type"); - but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, cont->name, 0, 31, 0, 0, "Controller name"); - uiButSetFunc(but, make_unique_prop_names_cb, cont->name, (void*) 0); - - ycoo= yco; - yco= draw_controllerbuttons(cont, block, xco, yco, width); - if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2; - } - else { - cpack(0x999999); - glRecti(xco+22, yco, xco+width-22,yco+19); - but= uiDefBut(block, LABEL, 0, controller_name(cont->type), (short)(xco+22), yco, 100, 19, cont, 0, 0, 0, 0, "Controller type"); - uiButSetFunc(but, sca_move_controller, cont, NULL); - but= uiDefBut(block, LABEL, 0, cont->name,(short)(xco+122), yco,(short)(width-144), 19, cont, 0, 0, 0, 0, "Controller name"); - uiButSetFunc(but, sca_move_controller, cont, NULL); + if(ob->scaflag & OB_SHOWSENS) { + + sens= ob->sensors.first; + while(sens) { + if (!(G.buts->scaflag & BUTS_SENS_STATE) || + sens->totlinks == 0 || /* always display sensor without links so that is can be edited */ + is_sensor_linked(block, sens)) { + sens->flag |= SENS_VISIBLE; + uiBlockSetEmboss(block, UI_EMBOSSM); + uiDefIconButBitS(block, TOG, SENS_DEL, B_DEL_SENS, ICON_X, xco, yco, 22, 19, &sens->flag, 0, 0, 0, 0, "Delete Sensor"); + uiDefIconButBitS(block, ICONTOG, SENS_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &sens->flag, 0, 0, 0, 0, "Sensor settings"); + ycoo= yco; + if(sens->flag & SENS_SHOW) + { + uiDefButS(block, MENU, B_CHANGE_SENS, sensor_pup(), (short)(xco+22), yco, 100, 19, &sens->type, 0, 0, 0, 0, "Sensor type"); + but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, sens->name, 0, 31, 0, 0, "Sensor name"); + uiButSetFunc(but, make_unique_prop_names_cb, sens->name, (void*) 0); + + sens->otype= sens->type; + yco= draw_sensorbuttons(sens, block, xco, yco, width,ob->id.name); + if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2; + } + else { + set_col_sensor(sens->type, 1); + glRecti(xco+22, yco, xco+width-22,yco+19); + but= uiDefBut(block, LABEL, 0, sensor_name(sens->type), (short)(xco+22), yco, 100, 19, sens, 0, 0, 0, 0, ""); + uiButSetFunc(but, sca_move_sensor, sens, NULL); + but= uiDefBut(block, LABEL, 0, sens->name, (short)(xco+122), yco, (short)(width-144), 19, sens, 0, 31, 0, 0, ""); + uiButSetFunc(but, sca_move_sensor, sens, NULL); + } + + but= uiDefIconBut(block, LINK, 0, ICON_LINK, (short)(xco+width), ycoo, 19, 19, NULL, 0, 0, 0, 0, ""); + uiSetButLink(but, NULL, (void ***)&(sens->links), &sens->totlinks, LINK_SENSOR, LINK_CONTROLLER); + + yco-=20; } - - but= uiDefIconBut(block, LINK, 0, ICON_LINK, (short)(xco+width), ycoo, 19, 19, NULL, 0, 0, 0, 0, ""); - uiSetButLink(but, NULL, (void ***)&(cont->links), &cont->totlinks, LINK_CONTROLLER, LINK_ACTUATOR); - - uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, cont, LINK_CONTROLLER, 0, 0, 0, ""); - - yco-=20; - - cont= cont->next; + sens= sens->next; } yco-= 6; } } - + /* ******************************* */ - xco= 985; yco= 170; width= 280; + xco= 1040; yco= 170; width= 280; uiBlockSetEmboss(block, UI_EMBOSSP); - uiDefBlockBut(block, actuator_menu, NULL, "Actuators", xco-10, yco+35, 100, 19, ""); + uiDefBlockBut(block, actuator_menu, NULL, "Actuators", xco-10, yco+35, 90, 19, ""); uiBlockSetEmboss(block, UI_EMBOSS); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, BUTS_ACT_SEL, B_REDR, "Sel", xco+110, yco+35, (width-110)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects"); - uiDefButBitS(block, TOG, BUTS_ACT_ACT, B_REDR, "Act", xco+110+(width-110)/3, yco+35, (width-110)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object"); - uiDefButBitS(block, TOG, BUTS_ACT_LINK, B_REDR, "Link", xco+110+2*(width-110)/3, yco+35, (width-110)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Controller"); + uiDefButBitS(block, TOG, BUTS_ACT_SEL, B_REDR, "Sel", xco+110, yco+35, (width-100)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects"); + uiDefButBitS(block, TOG, BUTS_ACT_ACT, B_REDR, "Act", xco+110+(width-100)/4, yco+35, (width-100)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object"); + uiDefButBitS(block, TOG, BUTS_ACT_LINK, B_REDR, "Link", xco+110+2*(width-100)/4, yco+35, (width-100)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Controller"); + uiDefButBitS(block, TOG, BUTS_ACT_STATE, B_REDR, "Sta", xco+110+3*(width-100)/4, yco+35, (width-100)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show only actuators connected to active states"); uiBlockEndAlign(block); for(a=0; a<count; a++) { ob= (Object *)idar[a]; @@ -2859,34 +3187,38 @@ void logic_buts(void) act= ob->actuators.first; while(act) { - uiBlockSetEmboss(block, UI_EMBOSSM); - uiDefIconButBitS(block, TOG, ACT_DEL, B_DEL_ACT, ICON_X, xco, yco, 22, 19, &act->flag, 0, 0, 0, 0, "Delete Actuator"); - uiDefIconButBitS(block, ICONTOG, ACT_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &act->flag, 0, 0, 0, 0, "Actuator settings"); + if (!(G.buts->scaflag & BUTS_ACT_STATE) || + !(act->flag & ACT_LINKED) || /* always display actuators without links so that is can be edited */ + (act->flag & ACT_VISIBLE)) { /* this actuator has visible connection, display it */ + act->flag |= ACT_VISIBLE; /* mark the actuator as visible to help implementing the up/down action */ + uiBlockSetEmboss(block, UI_EMBOSSM); + uiDefIconButBitS(block, TOG, ACT_DEL, B_DEL_ACT, ICON_X, xco, yco, 22, 19, &act->flag, 0, 0, 0, 0, "Delete Actuator"); + uiDefIconButBitS(block, ICONTOG, ACT_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &act->flag, 0, 0, 0, 0, "Actuator settings"); + + if(act->flag & ACT_SHOW) { + act->otype= act->type; + uiDefButS(block, MENU, B_CHANGE_ACT, actuator_pup(ob), (short)(xco+22), yco, 100, 19, &act->type, 0, 0, 0, 0, "Actuator type"); + but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, act->name, 0, 31, 0, 0, "Actuator name"); + uiButSetFunc(but, make_unique_prop_names_cb, act->name, (void*) 0); + + ycoo= yco; + yco= draw_actuatorbuttons(ob, act, block, xco, yco, width); + if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2; + } + else { + set_col_actuator(act->type, 1); + glRecti((short)(xco+22), yco, (short)(xco+width-22),(short)(yco+19)); + but= uiDefBut(block, LABEL, 0, actuator_name(act->type), (short)(xco+22), yco, 100, 19, act, 0, 0, 0, 0, "Actuator type"); + uiButSetFunc(but, sca_move_actuator, act, NULL); + but= uiDefBut(block, LABEL, 0, act->name, (short)(xco+122), yco, (short)(width-144), 19, act, 0, 0, 0, 0, "Actuator name"); + uiButSetFunc(but, sca_move_actuator, act, NULL); + ycoo= yco; + } - if(act->flag & ACT_SHOW) { - act->otype= act->type; - uiDefButS(block, MENU, B_CHANGE_ACT, actuator_pup(ob), (short)(xco+22), yco, 100, 19, &act->type, 0, 0, 0, 0, "Actuator type"); - but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, act->name, 0, 31, 0, 0, "Actuator name"); - uiButSetFunc(but, make_unique_prop_names_cb, act->name, (void*) 0); + uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, act, LINK_ACTUATOR, 0, 0, 0, ""); - ycoo= yco; - yco= draw_actuatorbuttons(act, block, xco, yco, width); - if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2; - } - else { - set_col_actuator(act->type, 1); - glRecti((short)(xco+22), yco, (short)(xco+width-22),(short)(yco+19)); - but= uiDefBut(block, LABEL, 0, actuator_name(act->type), (short)(xco+22), yco, 100, 19, act, 0, 0, 0, 0, "Actuator type"); - uiButSetFunc(but, sca_move_actuator, act, NULL); - but= uiDefBut(block, LABEL, 0, act->name, (short)(xco+122), yco, (short)(width-144), 19, act, 0, 0, 0, 0, "Actuator name"); - uiButSetFunc(but, sca_move_actuator, act, NULL); - ycoo= yco; + yco-=20; } - - uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, act, LINK_ACTUATOR, 0, 0, 0, ""); - - yco-=20; - act= act->next; } yco-= 6; diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c index 6582866d9a1..4fbf92d646e 100644 --- a/source/blender/src/interface.c +++ b/source/blender/src/interface.c @@ -2797,6 +2797,10 @@ static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt) line->to= bt; } +uiBut *uiFindInlink(uiBlock *block, void *poin) +{ + return ui_find_inlink(block, poin); +} void uiComposeLinks(uiBlock *block) { diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 32946267202..21c18634e21 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -2324,6 +2324,14 @@ void BL_ConvertBlenderObjects(struct Main* maggie, bool isInActiveLayer = (blenderobj->lay & activeLayerBitInfo)!=0; BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,keydev,executePriority,activeLayerBitInfo,isInActiveLayer,canvas,converter); } + // apply the initial state to controllers + for ( i=0;i<logicbrick_conversionlist->GetCount();i++) + { + KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i)); + struct Object* blenderobj = converter->FindBlenderObject(gameobj); + gameobj->SetState(blenderobj->state); + } + #endif //CONVERT_LOGIC logicbrick_conversionlist->Release(); diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index f219c3a1472..c02c2a29595 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -56,6 +56,7 @@ #include "KX_ConstraintActuator.h" #include "KX_CameraActuator.h" #include "KX_GameActuator.h" +#include "KX_StateActuator.h" #include "KX_VisibilityActuator.h" #include "KX_SCA_AddObjectActuator.h" #include "KX_SCA_EndObjectActuator.h" @@ -857,7 +858,19 @@ void BL_ConvertActuators(char* maggiename, baseact = tmp_vis_act; } break; - + + case ACT_STATE: + { + bStateActuator *sta_act = (bStateActuator *) bact->data; + KX_StateActuator * tmp_sta_act = NULL; + + tmp_sta_act = + new KX_StateActuator(gameobj, sta_act->type, sta_act->mask); + + baseact = tmp_sta_act; + } + break; + case ACT_2DFILTER: { bTwoDFilterActuator *_2dfilter = (bTwoDFilterActuator*) bact->data; diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/KX_ConvertControllers.cpp index a26cfa95b6d..179dd9f8478 100644 --- a/source/gameengine/Converter/KX_ConvertControllers.cpp +++ b/source/gameengine/Converter/KX_ConvertControllers.cpp @@ -161,6 +161,7 @@ void BL_ConvertControllers( if (gamecontroller) { gamecontroller->SetExecutePriority(executePriority++); + gamecontroller->SetState(bcontr->state_mask); STR_String uniquename = bcontr->name; uniquename += "#CONTR#"; uniqueint++; diff --git a/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp b/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp index 67df5d091ab..f9fbf2387c4 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp +++ b/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp @@ -53,10 +53,13 @@ SCA_AlwaysSensor::SCA_AlwaysSensor(class SCA_EventManager* eventmgr, : SCA_ISensor(gameobj,eventmgr, T) { //SetDrawColor(255,0,0); - m_alwaysresult = true; + Init(); } - +void SCA_AlwaysSensor::Init() +{ + m_alwaysresult = true; +} SCA_AlwaysSensor::~SCA_AlwaysSensor() { diff --git a/source/gameengine/GameLogic/SCA_AlwaysSensor.h b/source/gameengine/GameLogic/SCA_AlwaysSensor.h index 474ed025432..8bf2a8aa98e 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysSensor.h +++ b/source/gameengine/GameLogic/SCA_AlwaysSensor.h @@ -45,6 +45,8 @@ public: virtual CValue* GetReplica(); virtual bool Evaluate(CValue* event); virtual bool IsPositiveTrigger(); + virtual void Init(); + /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ diff --git a/source/gameengine/GameLogic/SCA_IActuator.cpp b/source/gameengine/GameLogic/SCA_IActuator.cpp index 568d0eb4a89..eeca2d7b44c 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.cpp +++ b/source/gameengine/GameLogic/SCA_IActuator.cpp @@ -36,6 +36,7 @@ using namespace std; SCA_IActuator::SCA_IActuator(SCA_IObject* gameobj, PyTypeObject* T) : + m_links(0), SCA_ILogicBrick(gameobj,T) { // nothing to do @@ -109,3 +110,12 @@ SCA_IActuator::~SCA_IActuator() RemoveAllEvents(); } +void SCA_IActuator::DecLink() +{ + m_links--; + if (m_links < 0) + { + printf("Warning: actuator %s has negative m_links: %d\n", m_name.Ptr(), m_links); + m_links = 0; + } +} diff --git a/source/gameengine/GameLogic/SCA_IActuator.h b/source/gameengine/GameLogic/SCA_IActuator.h index b802aa4b298..774b27c5ad4 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.h +++ b/source/gameengine/GameLogic/SCA_IActuator.h @@ -34,8 +34,11 @@ class SCA_IActuator : public SCA_ILogicBrick { + friend class SCA_LogicManager; protected: std::vector<CValue*> m_events; + int m_links; // number of active links to controllers + // when 0, the actuator is automatically stopped void RemoveAllEvents(); public: @@ -83,6 +86,10 @@ public: */ bool IsNegativeEvent() const; virtual ~SCA_IActuator(); + + void IncLink() { m_links++; } + void DecLink(); + bool IsNoLink() const { return !m_links; } }; #endif //__KX_IACTUATOR diff --git a/source/gameengine/GameLogic/SCA_IController.cpp b/source/gameengine/GameLogic/SCA_IController.cpp index 5cb62678c6b..bbe5a51db3c 100644 --- a/source/gameengine/GameLogic/SCA_IController.cpp +++ b/source/gameengine/GameLogic/SCA_IController.cpp @@ -29,6 +29,7 @@ #include "SCA_IController.h" #include "SCA_LogicManager.h" #include "SCA_IActuator.h" +#include "SCA_ISensor.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -37,6 +38,7 @@ SCA_IController::SCA_IController(SCA_IObject* gameobj, PyTypeObject* T) : + m_statemask(0), SCA_ILogicBrick(gameobj,T) { } @@ -45,6 +47,7 @@ SCA_IController::SCA_IController(SCA_IObject* gameobj, SCA_IController::~SCA_IController() { + UnlinkAllActuators(); } @@ -65,6 +68,14 @@ const std::vector<class SCA_IActuator*>& SCA_IController::GetLinkedActuators() void SCA_IController::UnlinkAllSensors() { + if (IsActive()) + { + std::vector<class SCA_ISensor*>::iterator sensit; + for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) + { + (*sensit)->DecLink(); + } + } m_linkedsensors.clear(); } @@ -72,6 +83,14 @@ void SCA_IController::UnlinkAllSensors() void SCA_IController::UnlinkAllActuators() { + if (IsActive()) + { + std::vector<class SCA_IActuator*>::iterator actit; + for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit) + { + (*actit)->DecLink(); + } + } m_linkedactuators.clear(); } @@ -95,26 +114,94 @@ void SCA_IController::Trigger(SCA_LogicManager* logicmgr) void SCA_IController::LinkToActuator(SCA_IActuator* actua) { m_linkedactuators.push_back(actua); + if (IsActive()) + { + actua->IncLink(); + } } void SCA_IController::UnlinkActuator(class SCA_IActuator* actua) { std::vector<class SCA_IActuator*>::iterator actit; - std::vector<class SCA_IActuator*>::iterator actfound = m_linkedactuators.end(); for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit) { if ((*actit) == actua) - actfound = actit; + { + break; + } } - if (!(actfound==m_linkedactuators.end())) + if (!(actit==m_linkedactuators.end())) { - m_linkedactuators.erase(actfound); + m_linkedactuators.erase(actit); + if (IsActive()) + { + (*actit)->DecLink(); + } } - } void SCA_IController::LinkToSensor(SCA_ISensor* sensor) { m_linkedsensors.push_back(sensor); + if (IsActive()) + { + sensor->IncLink(); + } +} + +void SCA_IController::UnlinkSensor(class SCA_ISensor* sensor) +{ + std::vector<class SCA_ISensor*>::iterator sensit; + for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) + { + if ((*sensit) == sensor) + { + break; + } + + } + if (!(sensit==m_linkedsensors.end())) + { + m_linkedsensors.erase(sensit); + if (IsActive()) + { + (*sensit)->DecLink(); + } + } } + +void SCA_IController::ApplyState(unsigned int state) +{ + std::vector<class SCA_IActuator*>::iterator actit; + std::vector<class SCA_ISensor*>::iterator sensit; + + if (m_statemask & state) + { + if (!IsActive()) + { + // reactive the controller, all the links to actuator are valid again + for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit) + { + (*actit)->IncLink(); + } + for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) + { + (*sensit)->IncLink(); + } + SetActive(true); + } + } else if (IsActive()) + { + for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit) + { + (*actit)->DecLink(); + } + for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) + { + (*sensit)->DecLink(); + } + SetActive(false); + } +} + diff --git a/source/gameengine/GameLogic/SCA_IController.h b/source/gameengine/GameLogic/SCA_IController.h index 79e956dec4e..f67c0942eb4 100644 --- a/source/gameengine/GameLogic/SCA_IController.h +++ b/source/gameengine/GameLogic/SCA_IController.h @@ -36,6 +36,7 @@ class SCA_IController : public SCA_ILogicBrick protected: std::vector<class SCA_ISensor*> m_linkedsensors; std::vector<class SCA_IActuator*> m_linkedactuators; + unsigned int m_statemask; public: SCA_IController(SCA_IObject* gameobj,PyTypeObject* T); virtual ~SCA_IController(); @@ -47,6 +48,9 @@ public: void UnlinkAllSensors(); void UnlinkAllActuators(); void UnlinkActuator(class SCA_IActuator* actua); + void UnlinkSensor(class SCA_ISensor* sensor); + void SetState(unsigned int state) { m_statemask = state; } + void ApplyState(unsigned int state); }; diff --git a/source/gameengine/GameLogic/SCA_IObject.cpp b/source/gameengine/GameLogic/SCA_IObject.cpp index 6df9e23f3fa..826e7bbdf0e 100644 --- a/source/gameengine/GameLogic/SCA_IObject.cpp +++ b/source/gameengine/GameLogic/SCA_IObject.cpp @@ -40,7 +40,7 @@ MT_Point3 SCA_IObject::m_sDummy=MT_Point3(0,0,0); -SCA_IObject::SCA_IObject(PyTypeObject* T): CValue(T) +SCA_IObject::SCA_IObject(PyTypeObject* T): m_state(0), CValue(T) { m_suspended = false; } @@ -329,6 +329,17 @@ void SCA_IObject::Resume(void) } } +void SCA_IObject::SetState(unsigned int state) +{ + m_state = state; + // update the status of the controllers + SCA_ControllerList::iterator contit; + for (contit = m_controllers.begin(); contit != m_controllers.end(); contit++) + { + (*contit)->ApplyState(m_state); + } +} + /* ------------------------------------------------------------------------- */ diff --git a/source/gameengine/GameLogic/SCA_IObject.h b/source/gameengine/GameLogic/SCA_IObject.h index e8251e0ceaa..07b4310a91e 100644 --- a/source/gameengine/GameLogic/SCA_IObject.h +++ b/source/gameengine/GameLogic/SCA_IObject.h @@ -67,7 +67,12 @@ protected: * Ignore updates? */ bool m_suspended; - + + /** + * current state = bit mask of state that are active + */ + unsigned int m_state; + public: SCA_IObject(PyTypeObject* T=&Type); @@ -111,7 +116,17 @@ public: * Resume progress */ void Resume(void); - + + /** + * Set the object state + */ + void SetState(unsigned int state); + + /** + * Get the object state + */ + unsigned int GetState(void) { return m_state; } + // const class MT_Point3& ConvertPythonPylist(PyObject* pylist); // here come the python forwarded methods diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp index 9fdee0c19da..1c29eb27be5 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.cpp +++ b/source/gameengine/GameLogic/SCA_ISensor.cpp @@ -52,6 +52,7 @@ SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj, SCA_ILogicBrick(gameobj,T), m_triggered(false) { + m_links = 0; m_suspended = false; m_invert = false; m_pos_ticks = 0; @@ -111,6 +112,25 @@ void SCA_ISensor::Resume() { m_suspended = false; } +void SCA_ISensor::Init() { + printf("Sensor %s has no init function, please report this bug to Blender.org\n", m_name); +} + +void SCA_ISensor::DecLink() { + m_links--; + if (m_links < 0) + { + printf("Warning: sensor %s has negative m_links: %d\n", m_name.Ptr(), m_links); + m_links = 0; + } + if (!m_links) + { + // sensor is detached from all controllers, initialize it so that it + // is fresh as at startup when it is reattached again. + Init(); + } +} + /* python integration */ PyTypeObject SCA_ISensor::Type = { @@ -177,7 +197,8 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr, CValue* event) { // calculate if a __triggering__ is wanted - if (!m_suspended) { + // don't evaluate a sensor that is not connected to any controller + if (m_links && !m_suspended) { bool result = this->Evaluate(event); if (result) { logicmgr->AddActivatedSensor(this); diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h index e14fb34241a..292b2d160ae 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.h +++ b/source/gameengine/GameLogic/SCA_ISensor.h @@ -64,6 +64,9 @@ class SCA_ISensor : public SCA_ILogicBrick /** Sensor must ignore updates? */ bool m_suspended; + /** number of connections to controller */ + int m_links; + /** Pass the activation on to the logic manager.*/ void SignalActivation(class SCA_LogicManager* logicmgr); @@ -81,6 +84,7 @@ public: void Activate(class SCA_LogicManager* logicmgr,CValue* event); virtual bool Evaluate(CValue* event) = 0; virtual bool IsPositiveTrigger(); + virtual void Init(); virtual PyObject* _getattr(const STR_String& attr); virtual CValue* GetReplica()=0; @@ -114,6 +118,12 @@ public: /** Resume sensing. */ void Resume(); + void IncLink() + { m_links++; } + void DecLink(); + bool IsNoLink() const + { return !m_links; } + /* Python functions: */ KX_PYMETHOD_DOC(SCA_ISensor,IsPositive); KX_PYMETHOD_DOC(SCA_ISensor,GetUsePosPulseMode); diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp index b0e7fee130d..81938f05af1 100644 --- a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp @@ -64,9 +64,13 @@ std::cout << " button flag "<< m_buttonf << std::endl; std::cout << " hat " << m_hat << std::endl; std::cout << " hat flag " << m_hatf << std::endl; */ - m_istrig=0; + Init(); } +void SCA_JoystickSensor::Init() +{ + m_istrig=0; +} SCA_JoystickSensor::~SCA_JoystickSensor() { diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.h b/source/gameengine/GameLogic/SCA_JoystickSensor.h index 2fbe1edf1e7..69068da6494 100644 --- a/source/gameengine/GameLogic/SCA_JoystickSensor.h +++ b/source/gameengine/GameLogic/SCA_JoystickSensor.h @@ -95,6 +95,7 @@ public: virtual bool Evaluate(CValue* event); virtual bool IsPositiveTrigger(); + virtual void Init(); /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp index f13b1bcf4c9..c6c06846e3b 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp @@ -62,7 +62,7 @@ SCA_KeyboardSensor::SCA_KeyboardSensor(SCA_KeyboardManager* keybdmgr, if (hotkey == SCA_IInputDevice::KX_ESCKEY) keybdmgr->GetInputDevice()->HookEscape(); // SetDrawColor(0xff0000ff); - m_val=0; + Init(); } @@ -71,7 +71,14 @@ SCA_KeyboardSensor::~SCA_KeyboardSensor() { } - +void SCA_KeyboardSensor::Init() +{ + // this function is used when the sensor is disconnected from all controllers + // by the state engine. It reinitializes the sensor as if it was just created. + // However, if the target key is pressed when the sensor is reactivated, it + // will not generated an event (see remark in Evaluate()). + m_val = 0; +} CValue* SCA_KeyboardSensor::GetReplica() { diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.h b/source/gameengine/GameLogic/SCA_KeyboardSensor.h index e87eddecd32..b86f6931d27 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.h +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.h @@ -114,6 +114,8 @@ public: PyTypeObject* T=&Type ); virtual ~SCA_KeyboardSensor(); virtual CValue* GetReplica(); + virtual void Init(); + short int GetHotkey(); virtual bool Evaluate(CValue* event); diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp index 49f01d643e5..fb1a2c29eb6 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.cpp +++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp @@ -165,6 +165,11 @@ void* SCA_LogicManager::FindBlendObjByGameMeshName(const STR_String& gamemeshnam void SCA_LogicManager::RemoveSensor(SCA_ISensor* sensor) { + controllerlist contlist = m_sensorcontrollermapje[sensor]; + for (controllerlist::const_iterator c= contlist.begin();!(c==contlist.end());c++) + { + (*c)->UnlinkSensor(sensor); + } m_sensorcontrollermapje.erase(sensor); for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin(); @@ -176,6 +181,8 @@ void SCA_LogicManager::RemoveSensor(SCA_ISensor* sensor) void SCA_LogicManager::RemoveController(SCA_IController* controller) { + controller->UnlinkAllSensors(); + controller->UnlinkAllActuators(); std::map<SCA_ISensor*,controllerlist>::iterator sit; for (sit = m_sensorcontrollermapje.begin();!(sit==m_sensorcontrollermapje.end());++sit) { @@ -236,7 +243,8 @@ void SCA_LogicManager::BeginFrame(double curtime, double fixedtime) !(c==contlist.end());c++) { SCA_IController* contr = *c;//controllerarray->at(c); - triggeredControllerSet.insert(SmartControllerPtr(contr,0)); + if (contr->IsActive()) + triggeredControllerSet.insert(SmartControllerPtr(contr,0)); } //sensor->SetActive(false); } @@ -273,6 +281,16 @@ void SCA_LogicManager::UpdateFrame(double curtime, bool frame) (*ia)->SetActive(false); //m_activeactuators.pop_back(); + } else if ((*ia)->IsNoLink()) + { + // This actuator has no more links but it still active + // make sure it will get a negative event on next frame to stop it + // Do this check after Update() rather than before to make sure + // that all the actuators that are activated at same time than a state + // actuator have a chance to execute. + CValue* event = new CBoolValue(false); + (*ia)->RemoveAllEvents(); + (*ia)->AddEvent(event); } } diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.cpp b/source/gameengine/GameLogic/SCA_MouseSensor.cpp index 8810b7470ed..11e67eda014 100644 --- a/source/gameengine/GameLogic/SCA_MouseSensor.cpp +++ b/source/gameengine/GameLogic/SCA_MouseSensor.cpp @@ -58,7 +58,6 @@ SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager* eventmgr, { m_mousemode = mousemode; m_triggermode = true; - m_val = 0; /* stores the latest attribute */ switch (m_mousemode) { case KX_MOUSESENSORMODE_LEFTBUTTON: @@ -79,7 +78,12 @@ SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager* eventmgr, default: ; /* ignore, no hotkey */ } + Init(); +} +void SCA_MouseSensor::Init() +{ + m_val = 0; /* stores the latest attribute */ } SCA_MouseSensor::~SCA_MouseSensor() diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.h b/source/gameengine/GameLogic/SCA_MouseSensor.h index 86c9d96a800..26a1c5e3fd2 100644 --- a/source/gameengine/GameLogic/SCA_MouseSensor.h +++ b/source/gameengine/GameLogic/SCA_MouseSensor.h @@ -96,7 +96,7 @@ class SCA_MouseSensor : public SCA_ISensor virtual ~SCA_MouseSensor(); virtual CValue* GetReplica(); virtual bool Evaluate(CValue* event); - + virtual void Init(); virtual bool IsPositiveTrigger(); short int GetModeKey(); SCA_IInputDevice::KX_EnumInputs GetHotKey(); diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp index f1fcb18d32e..d6eb246ffd2 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp +++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp @@ -57,7 +57,6 @@ SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr, m_lastresult(false), m_range_expr(NULL) { - m_recentresult=false; //CParser pars; //pars.SetContext(this->AddRef()); //CValue* resultval = m_rightexpr->Calculate(); @@ -73,7 +72,12 @@ SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr, { PrecalculateRangeExpression(); } + Init(); +} +void SCA_PropertySensor::Init() +{ + m_recentresult = false; } void SCA_PropertySensor::PrecalculateRangeExpression() diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.h b/source/gameengine/GameLogic/SCA_PropertySensor.h index 81c9b958f25..6871cb3afdc 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.h +++ b/source/gameengine/GameLogic/SCA_PropertySensor.h @@ -77,6 +77,7 @@ public: virtual void Delete(); virtual ~SCA_PropertySensor(); virtual CValue* GetReplica(); + virtual void Init(); void PrecalculateRangeExpression(); bool CheckPropertyCondition(); diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.cpp b/source/gameengine/GameLogic/SCA_RandomSensor.cpp index 0e856e0d6bb..3626522e49a 100644 --- a/source/gameengine/GameLogic/SCA_RandomSensor.cpp +++ b/source/gameengine/GameLogic/SCA_RandomSensor.cpp @@ -50,16 +50,9 @@ SCA_RandomSensor::SCA_RandomSensor(SCA_EventManager* eventmgr, PyTypeObject* T) : SCA_ISensor(gameobj,eventmgr, T) { - m_iteration = 0; - m_interval = 0; - m_lastdraw = false; - // m_basegenerator is never deleted => memory leak m_basegenerator = new SCA_RandomNumberGenerator(startseed); - m_currentDraw = m_basegenerator->Draw(); - //registration is done globally, don't do it here - //Note: it was probably done to work around a bug in Evaluate(). It is now fixed - //RegisterToManager(); + Init(); } @@ -69,6 +62,13 @@ SCA_RandomSensor::~SCA_RandomSensor() /* Nothing to be done here. */ } +void SCA_RandomSensor::Init() +{ + m_iteration = 0; + m_interval = 0; + m_lastdraw = false; + m_currentDraw = m_basegenerator->Draw(); +} CValue* SCA_RandomSensor::GetReplica() diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.h b/source/gameengine/GameLogic/SCA_RandomSensor.h index cc54179aa4e..d29bfb6837a 100644 --- a/source/gameengine/GameLogic/SCA_RandomSensor.h +++ b/source/gameengine/GameLogic/SCA_RandomSensor.h @@ -54,6 +54,7 @@ public: virtual CValue* GetReplica(); virtual bool Evaluate(CValue* event); virtual bool IsPositiveTrigger(); + virtual void Init(); /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp index e320453b7aa..027cb2a0ffa 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp @@ -58,10 +58,15 @@ KX_NetworkMessageSensor::KX_NetworkMessageSensor( m_NetworkScene(NetworkScene), m_subject(subject), m_frame_message_count (0), - m_IsUp(false), m_BodyList(NULL), m_SubjectList(NULL) { + Init(); +} + +void KX_NetworkMessageSensor::Init() +{ + m_IsUp = false; } KX_NetworkMessageSensor::~KX_NetworkMessageSensor() diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h index d051b715aab..6fd92d17be3 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h @@ -65,6 +65,7 @@ public: virtual CValue* GetReplica(); virtual bool Evaluate(CValue* event); virtual bool IsPositiveTrigger(); + virtual void Init(); void EndFrame(); /* ------------------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index 60b90138abe..f306f0dbfbb 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -69,11 +69,14 @@ KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr, m_gp_canvas(canvas), m_kxscene(kxscene) { + Init(); +} +void KX_MouseFocusSensor::Init() +{ m_mouse_over_in_previous_frame = false; m_positive_event = false; m_hitObject = 0; - } bool KX_MouseFocusSensor::Evaluate(CValue* event) diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index 86f32fbf4be..b011ebe1288 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -68,6 +68,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor * @attention Overrides default evaluate. */ virtual bool Evaluate(CValue* event); + virtual void Init(); virtual bool IsPositiveTrigger() { bool result = m_positive_event; diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp index 31fffffa3c1..987e0b946b2 100644 --- a/source/gameengine/Ketsji/KX_RadarSensor.cpp +++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp @@ -71,7 +71,6 @@ KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr, //sumoObj->setClientObject(&m_client_info); } - KX_RadarSensor::~KX_RadarSensor() { diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp index a85dc61cac8..02b814105b4 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.cpp +++ b/source/gameengine/Ketsji/KX_RaySensor.cpp @@ -60,17 +60,19 @@ KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr, m_bFindMaterial(bFindMaterial), m_distance(distance), m_scene(ketsjiScene), - m_bTriggered(false), - m_axis(axis), - m_rayHit(false), - m_hitObject(NULL) + m_axis(axis) { - + Init(); } - +void KX_RaySensor::Init() +{ + m_bTriggered = false; + m_rayHit = false; + m_hitObject = NULL; +} KX_RaySensor::~KX_RaySensor() { diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h index 8a317ffaa07..f4305b053d1 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.h +++ b/source/gameengine/Ketsji/KX_RaySensor.h @@ -66,6 +66,7 @@ public: virtual bool Evaluate(CValue* event); virtual bool IsPositiveTrigger(); + virtual void Init(); bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index fff33ca82fd..1526709f425 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -754,8 +754,6 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) for (SCA_ControllerList::iterator itc = controllers.begin(); !(itc==controllers.end());itc++) { - (*itc)->UnlinkAllSensors(); - (*itc)->UnlinkAllActuators(); m_logicmgr->RemoveController(*itc); } diff --git a/source/gameengine/Ketsji/KX_StateActuator.cpp b/source/gameengine/Ketsji/KX_StateActuator.cpp new file mode 100644 index 00000000000..95a79f0c480 --- /dev/null +++ b/source/gameengine/Ketsji/KX_StateActuator.cpp @@ -0,0 +1,207 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * Actuator to toggle visibility/invisibility of objects + */ + +#include "KX_StateActuator.h" +#include "KX_GameObject.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +KX_StateActuator::KX_StateActuator( + SCA_IObject* gameobj, + int operation, + unsigned int mask, + PyTypeObject* T + ) + : SCA_IActuator(gameobj,T), + m_operation(operation), + m_mask(mask) +{ + // intentionally empty +} + +KX_StateActuator::~KX_StateActuator( + void + ) +{ + // intentionally empty +} + +CValue* +KX_StateActuator::GetReplica( + void + ) +{ + KX_StateActuator* replica = new KX_StateActuator(*this); + replica->ProcessReplica(); + // this will copy properties and so on... + CValue::AddDataToReplica(replica); + return replica; +} + +bool +KX_StateActuator::Update() +{ + bool bNegativeEvent = IsNegativeEvent(); + unsigned int objMask; + + RemoveAllEvents(); + if (bNegativeEvent) return false; + + KX_GameObject *obj = (KX_GameObject*) GetParent(); + + objMask = obj->GetState(); + switch (m_operation) + { + case OP_CPY: + objMask = m_mask; + break; + case OP_SET: + objMask |= m_mask; + break; + case OP_CLR: + objMask &= ~m_mask; + break; + case OP_NEG: + objMask ^= m_mask; + break; + default: + // unsupported operation, no nothing + return false; + } + obj->SetState(objMask); + return false; +} + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + + + +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject +KX_StateActuator::Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "KX_StateActuator", + sizeof(KX_StateActuator), + 0, + PyDestructor, + 0, + __getattr, + __setattr, + 0, //&MyPyCompare, + __repr, + 0, //&cvalue_as_number, + 0, + 0, + 0, + 0 +}; + +PyParentObject +KX_StateActuator::Parents[] = { + &KX_StateActuator::Type, + &SCA_IActuator::Type, + &SCA_ILogicBrick::Type, + &CValue::Type, + NULL +}; + +PyMethodDef +KX_StateActuator::Methods[] = { + {"setOperation", (PyCFunction) KX_StateActuator::sPySetOperation, + METH_VARARGS, SetOperation_doc}, + {"setMask", (PyCFunction) KX_StateActuator::sPySetMask, + METH_VARARGS, SetMask_doc}, + {NULL,NULL} //Sentinel +}; + +PyObject* +KX_StateActuator::_getattr( + const STR_String& attr + ) +{ + _getattr_up(SCA_IActuator); +}; + + + +/* set operation ---------------------------------------------------------- */ +char +KX_StateActuator::SetOperation_doc[] = +"setOperation(op)\n" +"\t - op : bit operation (0=Copy, 1=Set, 2=Clear, 3=Negate)" +"\tSet the type of bit operation to be applied on object state mask.\n" +"\tUse setMask() to specify the bits that will be modified.\n"; +PyObject* + +KX_StateActuator::PySetOperation(PyObject* self, + PyObject* args, + PyObject* kwds) { + int oper; + + if(!PyArg_ParseTuple(args, "i", &oper)) { + return NULL; + } + + m_operation = oper; + + Py_Return; +} + +/* set mask ---------------------------------------------------------- */ +char +KX_StateActuator::SetMask_doc[] = +"setMask(mask)\n" +"\t - mask : bits that will be modified" +"\tSet the value that defines the bits that will be modified by the operation.\n" +"\tThe bits that are 1 in the value will be updated in the object state,\n" +"\tthe bits that are 0 are will be left unmodified expect for the Copy operation\n" +"\twhich copies the value to the object state.\n"; +PyObject* + +KX_StateActuator::PySetMask(PyObject* self, + PyObject* args, + PyObject* kwds) { + int mask; + + if(!PyArg_ParseTuple(args, "i", &mask)) { + return NULL; + } + + m_mask = mask; + + Py_Return; +} + + diff --git a/source/gameengine/Ketsji/KX_StateActuator.h b/source/gameengine/Ketsji/KX_StateActuator.h new file mode 100644 index 00000000000..8698e51b2c1 --- /dev/null +++ b/source/gameengine/Ketsji/KX_StateActuator.h @@ -0,0 +1,83 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * Actuator to toggle visibility/invisibility of objects + */ + +#ifndef __KX_STATEACTUATOR +#define __KX_STATEACTUATOR + +#include "SCA_IActuator.h" + +class KX_StateActuator : public SCA_IActuator +{ + Py_Header; + + /** Make visible? */ + enum { + OP_CPY = 0, + OP_SET, + OP_CLR, + OP_NEG + }; + int m_operation; + unsigned int m_mask; + + public: + + KX_StateActuator( + SCA_IObject* gameobj, + int operation, + unsigned int mask, + PyTypeObject* T=&Type + ); + + virtual + ~KX_StateActuator( + void + ); + + virtual CValue* + GetReplica( + void + ); + + virtual bool + Update(); + + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + virtual PyObject* _getattr(const STR_String& attr); + //KX_PYMETHOD_DOC + KX_PYMETHOD_DOC(KX_StateActuator,SetOperation); + KX_PYMETHOD_DOC(KX_StateActuator,SetMask); +}; + +#endif + diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp index 3f185359de0..56c2780871b 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.cpp +++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp @@ -77,18 +77,14 @@ KX_TouchSensor::KX_TouchSensor(SCA_EventManager* eventmgr,KX_GameObject* gameobj :SCA_ISensor(gameobj,eventmgr,T), m_touchedpropname(touchedpropname), m_bFindMaterial(bFindMaterial), -m_eventmgr(eventmgr), +m_eventmgr(eventmgr) /*m_sumoObj(sumoObj),*/ -m_bCollision(false), -m_bTriggered(false), -m_bLastTriggered(false) { // KX_TouchEventManager* touchmgr = (KX_TouchEventManager*) eventmgr; // m_resptable = touchmgr->GetResponseTable(); // m_solidHandle = m_sumoObj->getObjectHandle(); - m_hitObject = NULL; m_colliders = new CListValue(); KX_ClientObjectInfo *client_info = gameobj->getClientInfo(); @@ -98,8 +94,16 @@ m_bLastTriggered(false) m_physCtrl = dynamic_cast<PHY_IPhysicsController*>(gameobj->GetPhysicsController()); MT_assert( !gameobj->GetPhysicsController() || m_physCtrl ); + Init(); } +void KX_TouchSensor::Init() +{ + m_bCollision = false; + m_bTriggered = false; + m_bLastTriggered = false; + m_hitObject = NULL; +} KX_TouchSensor::~KX_TouchSensor() { diff --git a/source/gameengine/Ketsji/KX_TouchSensor.h b/source/gameengine/Ketsji/KX_TouchSensor.h index f594196628a..056440ccd6c 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.h +++ b/source/gameengine/Ketsji/KX_TouchSensor.h @@ -72,6 +72,7 @@ public: virtual CValue* GetReplica(); virtual void SynchronizeTransform(); virtual bool Evaluate(CValue* event); + virtual void Init(); virtual void ReParent(SCA_IObject* parent); virtual void RegisterSumo(KX_TouchEventManager* touchman); |