Exemplo n.º 1
0
/* node_dynamic_exec_cb: the execution callback called per pixel
 * during rendering. */
static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) {
#ifndef WITH_PYTHON
	return;
#else
	BPy_Node *mynode = NULL;
	NodeScriptDict *nsd = NULL;
	PyObject *pyresult = NULL;
	PyObject *args = NULL;
	ShadeInput *shi;
	PyGILState_STATE gilstate;

	if (!node->id)
		return;

	/*if (G.scene->r.threads > 1)
		return;*/

	if (BTST2(node->custom1, NODE_DYNAMIC_NEW, NODE_DYNAMIC_REPARSE)) {
		node_dynamic_setup(node);
		return;
	}

	if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
		if (node->storage) node_dynamic_setup(node);
		return;
	}

	if (BTST(node->custom1, NODE_DYNAMIC_READY)) {
		nsd = (NodeScriptDict *)node->storage;
		mynode = (BPy_Node *)(nsd->node);


		if (mynode && PyCallable_Check((PyObject *)mynode)) {

			gilstate = PyGILState_Ensure();

			mynode->node = node;
			shi = ((ShaderCallData *)data)->shi;

			Node_SetStack(mynode, in, NODE_INPUTSTACK);
			Node_SetStack(mynode, out, NODE_OUTPUTSTACK);
			Node_SetShi(mynode, shi);

			args=Py_BuildValue("()");
			pyresult= PyObject_Call((PyObject *)mynode, args, NULL);
			Py_DECREF(args);

			if (!pyresult) {
				PyGILState_Release(gilstate);
				node_dynamic_disable_all_by_id(node->id);
				node_dynamic_pyerror_print(node);
				node_dynamic_setup(node);
				return;
			}
			Py_DECREF(pyresult);
			PyGILState_Release(gilstate);
		}
	}
#endif
}
Exemplo n.º 2
0
//                   d0              d2              a0            a1
void DrawTiles(int vramOffs, int patternBase, uint* tileAddr, int* block)
{
	VDP_SetAddr(vramOffs | patternBase, VDP_VRAM_Write);

	if(BTST(*tileAddr, 1 << 4))
	{
		if(BTST(*tileAddr, 1 << 3))
		{
			// flipped horiz and vert
			VDP_Data(SWAP16(block[1] ^ 0x18001800));
			VDP_SetAddr((vramOffs | patternBase) + 0x80, VDP_VRAM_Write);
			VDP_Data(SWAP16(block[0] ^ 0x18001800));
		}
		else
		{
			// flipped vert
			VDP_Data(block[1] ^ 0x10001000);
			VDP_SetAddr((vramOffs | patternBase) + 0x80, VDP_VRAM_Write);
			VDP_Data(block[0] ^ 0x10001000);
		}
	}
	else if(BTST(*tileAddr, 1 << 3))
	{
		// flipped horiz
		VDP_Data(SWAP16(block[0] ^ 0x08000800))
		VDP_SetAddr((vramOffs | patternBase) + 0x80, VDP_VRAM_Write);
		VDP_Data(SWAP16(block[1] ^ 0x08000800))
	}
Exemplo n.º 3
0
void print_sinfo(void)
{
  struct sinfo *p;int i,j;
  if(DEBUG&2)
    printf("print_sinfo\n");
  else
    return;
  for(j=0;j<si_count;j++){
    p=&silist[j];
    printf("inst: %s",p->txt);
    printf("flags=%u, label=%u latency=%u\n",p->flags,p->label,p->latency);
    printf("available pipelines: ");
    for(i=0;i<PIPES;i++)
      if(BTST(p->pipes,i))
        printf("%d ",i);
    printf("\nuses registers (%d=mem): ",MEM);
    for(i=0;i<=MEM;i++)
      if(BTST(p->uses,i))
        printf("%d ",i);
    printf("\nmodifies registers (%d=MEM): ",MEM);
    for(i=0;i<=MEM;i++)
      if(BTST(p->modifies,i))
        printf("%d ",i);
    printf("\n\n");
  }
}
Exemplo n.º 4
0
ALIST_API Boolean ALIsRowHidden( long inAnyRowNum, ALHandle hAL )
{	ALCell		tempCell;
	unsigned long	superRowOffset;

	// Sanity check.
	if ( hAL == nil || *hAL == nil || inAnyRowNum < (**hAL).dataBounds.top || inAnyRowNum >= (**hAL).dataBounds.bottom )
		return false;

	// Make sure the list is heirarchical.
	if ( !BTST( (*hAL)->features, alFHeirarchical ) )
		return false;

	// The left-most cell contains the heirarchical data.
	tempCell.h = (**hAL).dataBounds.left;
	tempCell.v = inAnyRowNum;

	while ( ( tempCell.v = ALSuperRow( tempCell.v, hAL ) ) != -1 ) {
		// tempCell now contains the cell that is the superrow of the previous tempCell.
		superRowOffset = _ALCalcOffsetFromCell( &tempCell, &(*hAL)->dataBounds );

		if ( BTST( (*(*hAL)->hSelected)[ superRowOffset ], alSsuperrow ) &&
					!BTST( (*(*hAL)->hSelected)[ superRowOffset ], alSexpanded ) )
			// The superrow is not expanded, so we're hidden.
			return true;
	} // end of "found a superrow" loop

	// We're not hidden.
	return false;
}
Exemplo n.º 5
0
void print_av(bvtype *bitvector)
/*  druckt Variablen in einem Bitvektor */
{
    int i;
    if(!bitvector) {printf("active variables not available\n");return;}
    for(i=0;i<vcount-rcount;i++)
        if(BTST(bitvector,i)) printf("%3d: %s,%ld\n",i,vilist[i]->identifier,zm2l(vilist[i]->offset));
    for(i=vcount-rcount;i<vcount;i++)
        if(BTST(bitvector,i)) printf("%3d: (%s),%ld\n",i,vilist[i]->identifier,zm2l(vilist[i]->offset));
}
Exemplo n.º 6
0
ALIST_API ControlPartCode ALSetFocus(ControlPartCode focusPart, ALHandle hAL)
{	ControlPartCode	result;
	Boolean			oldFocus;
	CGrafPtr			savePort;
	WindowPtr		winRef;

	if (hAL == nil || *hAL == nil)
		return kControlFocusNoPart;

	// Keep track of the old state of things.
	oldFocus = (BTST((*hAL)->flags, alFFocused) != 0);

	switch (focusPart) {
	case kControlFocusNoPart:		// Turn off all focusing.
		BCLR((*hAL)->flags, alFFocused);
		result = kControlFocusNoPart;
		break;
	case kControlFocusNextPart:		// Switch the state from off/on to on/off.
	case kControlFocusPrevPart:
		if (BTST((*hAL)->flags, alFFocused)) {
			// Turn off the focus.
			BCLR((*hAL)->flags, alFFocused);
			result = kControlFocusNoPart;
		} else {
			// Turn on the focus.
			BSET((*hAL)->flags, alFFocused);
			result = kControlListBoxPart;
		}
		break;
	case kControlListBoxPart:			// Turn on focusing.
		BSET((*hAL)->flags, alFFocused);
		result = kControlListBoxPart;
		break;
	default:	// simply return the state of focus
			result = (BTST((*hAL)->flags, alFFocused)) ? kControlListBoxPart : kControlFocusNoPart;
			break;
	}

	// If the focus changed, redraw if the alFDrawFocus feature is turned on.
	if ( BTST((*hAL)->features, alFDrawFocus) && oldFocus != (BTST((*hAL)->flags, alFFocused) != 0)) {
	  GDHandle        saveDevice;
	  
	  GetGWorld(&savePort, &saveDevice);
	  ALGetInfo(alWindow, &winRef, hAL);
	  SetPortWindowPort(winRef);
	  _ALDrawListBorder(hAL);
	  SetGWorld(savePort, saveDevice);
	}

	return result;
} // ALSetFocus
Exemplo n.º 7
0
void HUD_Update()
{
	if(f_debugmode)
		HudDb_XY();
	else if(f_scorecount)
	{
		f_scorecount = false;
		Hud_Score(0xDC80, v_score);
	}

	if(f_ringcount)
	{
		if(BTST(f_ringcount, 0x80))
			Hud_DrawZeroRings();

		f_ringcount = false;
		Hud_Rings(0xDF40, v_rings);
	}

	if(!f_debugmode && f_timecount && !f_pause)
	{
		if(v_timemin == 9 && v_timesec == 59 && v_timecent == 59)
		{
			// Time over
			f_timecount = false;
			Player_Kill(v_player, v_player);
			f_timeover = true;
			return;
		}

		if(IncTo(v_timecent, 60))
		{
			v_timecent = 0;

			if(IncTo(v_timesec, 60))
			{
				v_timesec = 60;
				IncTo(v_timemin, 9);
			}

			Hud_Mins(0xDE40, v_timemin);
			Hud_Secs(0xDEC0, v_timesec);
		}
	}

	// Dupe
	if(f_lifecount)
	{
		f_lifecount = false;
		Hud_Lives();
	}

	if(f_endactbonus)
	{
		f_endactbonus = false;
		VDP_SetAddr(0xAE00, VDP_VRAM_Write);
		Hud_TimeRingBonus(v_timebonus);
		Hud_TimeRingBonus(v_ringbonus);
	}
}
Exemplo n.º 8
0
ALIST_API short ALFeatureFlag(unsigned long feature, short action, ALHandle hAL)
{	ALPtr	pAL;
	short	status;

	if (hAL == nil || *hAL == nil)
		return alBitClear;

	pAL = *hAL;

	// get current status of the specified feature
	status = BTST(pAL->features, feature) ? alBitSet : alBitClear;

	// if action is alBitToggle, invert flag
	if (action == alBitToggle)
		action = 1 - status;

	// reset flag according to action
	if (action == alBitClear) {
		BCLR(pAL->features, feature);
		if ( feature == alFInhibitRedraw )
			// If we're enabling drawing, recalculate what's visible.
			_ALCalcVisibleCells( hAL );
	} else if ( action == alBitSet )
		BSET(pAL->features, feature);

	// return old status
	return status;
} // ALFeatureFlag
Exemplo n.º 9
0
ALIST_API long ALSuperRow( long subRow, ALHandle hAL )
{	ALCell		tempCell;
	unsigned long	subRowOffset, offset;

	if ( hAL == nil || *hAL == nil || subRow < (*hAL)->dataBounds.top || subRow >= (*hAL)->dataBounds.bottom )
		return -1;

	// Make sure the list is heirarchical.
	if ( !BTST( (*hAL)->features, alFHeirarchical ) )
		return -1;

	tempCell.h = (*hAL)->dataBounds.left;
	tempCell.v = subRow;
	subRowOffset = _ALCalcOffsetFromCell( &tempCell, &(*hAL)->dataBounds );

	if ( (*(*hAL)->hLevels)[ subRowOffset ] == 0 )
		// We're at the top level already.
		return -1;

	// Go up the list looking for the nearest level change.
	for ( tempCell.v--; tempCell.v >= (*hAL)->dataBounds.top; tempCell.v-- ) {
		offset = _ALCalcOffsetFromCell( &tempCell, &(*hAL)->dataBounds );
		if ( (*(*hAL)->hLevels)[ offset ] < (*(*hAL)->hLevels)[ subRowOffset ] )
			return tempCell.v;
	}

	// Didn't find the super row?  Shouldn't ever happen.
	return -1;
}
Exemplo n.º 10
0
ALIST_API OSErr ALCollapseRow(long rowNum, Boolean collapseChildren, ALHandle hAL)
{	ALCell		tempCell;
	unsigned long	superRowOffset, offset;

	// Sanity check.
	if ( hAL == nil || *hAL == nil || rowNum < (**hAL).dataBounds.top || rowNum >= (**hAL).dataBounds.bottom )
		return paramErr;

	// Make sure the list is heirarchical.
	if ( !BTST( (*hAL)->features, alFHeirarchical ) )
		return false;

	// The left-most cell contains the heirarchical data.
	tempCell.h = (**hAL).dataBounds.left;
	tempCell.v = rowNum;

	superRowOffset = _ALCalcOffsetFromCell(&tempCell, &(*hAL)->dataBounds);

	// Mark the row as collapsed.
	BCLR((*(*hAL)->hSelected)[superRowOffset], alSexpanded);

	// See if it's a heirarchical row.
	if ( BTST((*(*hAL)->hSelected)[superRowOffset], alSsuperrow) ) {
		for ( tempCell.v++; tempCell.v < (*hAL)->dataBounds.bottom; tempCell.v++ ) {
			// Go through looking for children.
			offset = _ALCalcOffsetFromCell( &tempCell, &(*hAL)->dataBounds );
			if ( (*(*hAL)->hLevels)[ offset ] > (*(*hAL)->hLevels)[ superRowOffset ] ) {
				if ( collapseChildren )
					// Mark all children as collapsed.
					BCLR( (*(*hAL)->hSelected)[ offset ], alSexpanded );
				// Also, clear all selection bits.
				BCLR( (*(*hAL)->hSelected)[ offset ], alSselected );
			} else
				break;
		}

		// Recalculate the visible cells.
		_ALCalcVisibleCells( hAL );

		// Redraw the entire list.
		if ( !BTST((*hAL)->features, alFInhibitRedraw) )
			ALUpdate( nil, hAL );
	}

	return noErr;
}
Exemplo n.º 11
0
ALIST_API long ALAddRowUnder( long count, long superRow, ALHandle hAL )
{	long			result;
	ALCell		tempCell;
	unsigned long	superRowOffset, offset;
	short		saveRedrawState;

	if ( count < 0 || hAL == nil || *hAL == nil || superRow < (*hAL)->dataBounds.top || superRow >= (*hAL)->dataBounds.bottom )
		return 0;

	// Make sure the list is heirarchical.
	if ( !BTST( (*hAL)->features, alFHeirarchical ) )
		return 0;

	saveRedrawState = ALFeatureFlag( alFInhibitRedraw, alBitSet, hAL );

	result = ALAddRow( count, superRow + 1, hAL );

	ALFeatureFlag( alFInhibitRedraw, saveRedrawState, hAL );

	if ( result > 0 ) {
		tempCell.h = (**hAL).dataBounds.left;
		tempCell.v = superRow;
		superRowOffset = _ALCalcOffsetFromCell( &tempCell, &(*hAL)->dataBounds );

		// Mark the superRow as an alSsuperrow, if it wasn't already.
		if ( !BTST( (*(*hAL)->hSelected)[ superRowOffset ], alSsuperrow ) ) {
			BSET( (*(*hAL)->hSelected)[ superRowOffset ], alSsuperrow );

			// The row defaults to being expanded.
			BSET( (*(*hAL)->hSelected)[ superRowOffset ], alSexpanded );
		}

		// Set the level of all the added rows to one greater than the superRows level.
		for ( tempCell.v = superRow + 1; tempCell.v <= superRow + count; tempCell.v++ ) {
			offset = _ALCalcOffsetFromCell(&tempCell, &(*hAL)->dataBounds);
			(*(*hAL)->hLevels)[ offset ] = (*(*hAL)->hLevels)[ superRowOffset ] + 1;
		}

		// Redraw the entire list.
		if ( !BTST((*hAL)->features, alFInhibitRedraw) )
			ALUpdate( nil, hAL );
	}

	return result;
}
Exemplo n.º 12
0
ALIST_API Boolean ALIsRowExpanded( long inSuperRowNum, ALHandle hAL )
{	ALCell		tempCell;
	unsigned long	offset;

	// Sanity check.
	if (hAL == nil || *hAL == nil || inSuperRowNum < (**hAL).dataBounds.top || inSuperRowNum >= (**hAL).dataBounds.bottom)
		return false;

	// Make sure the list is heirarchical.
	if ( !BTST( (*hAL)->features, alFHeirarchical ) )
		return false;

	// The left-most cell contains the heirarchical data.
	tempCell.h = (**hAL).dataBounds.left;
	tempCell.v = inSuperRowNum;

	offset = _ALCalcOffsetFromCell(&tempCell, &(*hAL)->dataBounds);

	return (BTST((*(*hAL)->hSelected)[offset], alSexpanded) != 0);
}
Exemplo n.º 13
0
ALIST_API ControlPartCode ALPartFocused(ALHandle hAL)
{	// Sanity check!
	if  (hAL == nil || *hAL == nil)
		return kControlFocusNoPart;

	// Get current status of the focus flag
	if (BTST((*hAL)->flags, alFFocused))
		return kControlListBoxPart;
	else
		return kControlFocusNoPart;
} // ALPartFocused
Exemplo n.º 14
0
void av_change(struct IC *p,bvtype *use,bvtype *def)
/*  Berechnet die Aenderungen, die sich durch IC p an use und def ergeben.  */
{
    int i,j,n=-1;
    int g1,g2;

    /*  Wenn eine Quelle==Ziel, dann wird dadurch kein neuer use erzeugt,   */
    /*  um z.B. unbenutzte Induktionsvariablen in Schleifen zu eliminieren. */
    g1=compare_objs(&p->q1,&p->z,p->typf);
    g2=compare_objs(&p->q2,&p->z,p->typf);
    if(!g1&&(p->q1.flags&(VAR|DREFOBJ))==VAR) n=p->q1.v->index;
    if(!g2&&(p->q2.flags&(VAR|DREFOBJ))==VAR) n=p->q2.v->index;

    for(j=0;j<p->use_cnt;j++){
        i=p->use_list[j].v->index;
        if(p->use_list[j].flags&DREFOBJ) i+=vcount-rcount;
        if(i>=vcount) continue;
        if(i!=n&&!BTST(def,i)) BSET(use,i);
    }

    /*  Ein Wert wird nicht zerstoert, wenn es kein elementarer Typ ist und */
    /*  die Groesse kleiner als die Variable (steht in alle solchen ICs in  */
    /*  q2.val.max.                                                         */
    if((p->z.flags&(VAR|DREFOBJ))==VAR&&(ISSCALAR(p->z.v->vtyp->flags)||p->z.v->vtyp->flags==0||zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp)))){
        i=p->z.v->index;
        if(i>=vcount) ierror(0);
        if(g1&&g2&&!BTST(use,i)) BSET(def,i);
        /*  Wenn p geaendert wird, wird auch *p geaendert   */
        if(i<rcount&&!BTST(def,i+vcount-rcount)) BSET(use,i+vcount-rcount);
    }
    if((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&g1&&g2&&!(p->z.v->flags&DNOTTYPESAFE)){
        i=p->z.v->index+vcount-rcount;
        if(i>=vcount) ierror(0);
        if(!BTST(use,i)) BSET(def,i);
    }
}
Exemplo n.º 15
0
void output_scheduled(FILE *f)
{
  int pipes[PIPES],i,j,k,l,remaining;
  int latency[MEM+1]={0},cycle=0;
  unsigned char used[REGS_SIZE],modified[REGS_SIZE],tmp[REGS_SIZE],empty[REGS_SIZE]={0};
  remaining=si_count;
  if(DEBUG&2) print_sinfo();
  while(remaining){
    cycle++;
    if(DEBUG&4){
      printf("cycle %d\n",cycle);
      for(i=0;i<=MEM;i++)
        if(latency[i]>0) printf("latency[%d]=%d\n",i,latency[i]);
    }
    /* Mark all instructions which are ready. */
    memset(modified,0,REGS_SIZE);
    memset(used,0,REGS_SIZE);
    for(i=0;i<si_count;i++){
      if(silist[i].flags&OUT) continue;
      memcpy(tmp,silist[i].uses,REGS_SIZE);
      bvunite(tmp,silist[i].modifies,REGS_SIZE);
      bvintersect(tmp,modified,REGS_SIZE);
      if(bvcmp(tmp,empty,REGS_SIZE)){
        /* uses and modifies nothing that has to be modified before */
        memcpy(tmp,used,REGS_SIZE);
        bvintersect(tmp,silist[i].modifies,REGS_SIZE);
        if(bvcmp(tmp,empty,REGS_SIZE)){
          /* modifies nothing that has to be used before */
          for(k=0,j=0;j<=MEM;j++){
            if(BTST(silist[i].uses,j)&&latency[j]>0) k=1;
          }
          if(!k) silist[i].flags|=READY;
        }
      }
      bvunite(modified,silist[i].modifies,REGS_SIZE);
      bvunite(used,silist[i].uses,REGS_SIZE);
    }

    /* Fill pipeline slots with ready instructions. */
    for(i=0;i<PIPES;i++) pipes[i]=-1;
    for(i=0;i<si_count;i++){
      if(silist[i].flags&OUT) continue;
      if(!(silist[i].flags&READY)) continue;
      if(DEBUG&4) printf("inst ready: %s",silist[i].txt);
      k=0;
      /* Is there a free slot? */
      for(j=0;!k&&j<PIPES;j++){
        if(pipes[j]<0&&BTST(silist[i].pipes,j)){
          pipes[j]=i;
          k=1;
        }
      }
      /* Replace a scheduled instruction with smaller latency. */
      for(j=0;!k&&j<PIPES;j++){
        if(BTST(silist[i].pipes,j)&&silist[i].latency>silist[pipes[j]].latency){
          pipes[j]=i;
          k=1;
        }
      }
    }
    if(DEBUG&4) printf("instructions for cycle %d:\n",cycle);
    for(i=0;i<PIPES;i++){
      if(pipes[i]>=0){
        if(DEBUG&4) printf("%3d: %s",i,silist[pipes[i]].txt);
        fprintf(f,"%s",silist[pipes[i]].txt);
        silist[pipes[i]].flags|=OUT;
        remaining--;
        for(j=0;j<=MEM;j++){
          if(BTST(silist[pipes[i]].modifies,j)) latency[j]=silist[pipes[i]].latency;
        }
      }
    }
    for(i=0;i<=MEM;i++)
      if(latency[i]>0) latency[i]--;
  }
}
Exemplo n.º 16
0
ALIST_API void ALActivate(Boolean isActive, ALHandle hAL)
{	short	status;
	short	hilite;
	ALPtr	pAL;

	// Sanity check!
	if  (hAL == nil || *hAL == nil)
		return;

	// Get current status of the active flag
	status = BTST((*hAL)->flags, alFActive) ? alBitSet : alBitClear;

	if ((isActive && status == alBitSet) || (!isActive && status == alBitClear))
		return; // Do nothing, we're already the way the user wants us to be.
	else {
		// Hide the selection hiliting.
		_ALHiliteSelected(hAL);

		pAL = *hAL;

		if ( isActive ) {
			BSET(pAL->flags, alFComingActive);
			BSET(pAL->flags, alFActive);
			hilite = kControlNoPart;
 		 } else {
			BCLR(pAL->flags, alFActive);
			hilite = kControlInactivePart;
			// Dispose of the offscreen port if we're inactive.
			if (pAL->offscreenPort != nil) {
				DisposeGWorld(pAL->offscreenPort);
				(*hAL)->offscreenPort = nil;
			}
		}

		// Show the selection hiliting.
		_ALHiliteSelected(hAL);

#if ALIST_USEAPPEARANCEMGR
		if (BTST((*hAL)->flags, alFHasAppearanceMgr) != 0) {
			if ((*hAL)->vScroll != nil) {
				if (hilite == kControlInactivePart)
					DeactivateControl((*hAL)->vScroll);
				else
					ActivateControl((*hAL)->vScroll);
			}
			if ((*hAL)->hScroll != nil) {
				if (hilite == kControlInactivePart)
					DeactivateControl((*hAL)->hScroll);
				else
					ActivateControl((*hAL)->hScroll);
			}
		} else
#endif
			{
			if ((*hAL)->vScroll != nil)
				HiliteControl((*hAL)->vScroll, hilite);
			if ((*hAL)->hScroll != nil)
				HiliteControl((*hAL)->hScroll, hilite);
		}

		ALUpdate( nil, hAL );
	}
} // ALActivate
Exemplo n.º 17
0
int dead_assignments(struct flowgraph *fg)
/*  Findet Zuweisungen, die unnoetig sind, da die Variable nie mehr     */
/*  benutzt werden kann.                                                */
{
    int changed=0;struct IC *p;bvtype *isused;
    int i,j;
    if(DEBUG&1024) printf("searching for dead assignments\n");
    isused=mymalloc(vsize);
    while(fg){
      memcpy(isused,fg->av_out,vsize);
      p=fg->end;
      while(p){
	if(p->z.flags&VAR){
	  i=p->z.v->index;
	  if(p->z.flags&DREFOBJ) i+=vcount-rcount;
	  if(!BTST(isused,i)&&!is_volatile_ic(p)&&!(disable&1)){
	    if(DEBUG&1024){printf("dead assignment deleted:\n");pric2(stdout,p);}
	    if(*p->z.v->identifier&&p->code!=ASSIGN){ err_ic=p;error(170,i>=vcount-rcount?"*":"",p->z.v->identifier);err_ic=0;}
	    if(p->code!=GETRETURN) changed=1;
	    if(p==fg->start){remove_IC_fg(fg,p);break;}
	    p=p->prev;remove_IC_fg(fg,p->next);
	    continue;
	  }
	}
	if(p->code!=SETRETURN&&p->code!=TEST&&p->code!=COMPARE&&(p->q1.flags&VAR)&&!BTST(isused,p->q1.v->index)&&(!(p->z.flags&VAR)||!p->z.v->reg||p->z.v->identifier)){
          struct IC *m,*a;int f=p->q1.flags,dt=p->q1.dtyp;
	  p->q1.flags&=~DREFOBJ;
	  a=p->prev;if(a) m=a->prev; else m=0;
	  if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->q1,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
	    if(DEBUG&1024){
	      printf("reorder post-op(q1):\n");
	      pric2(stdout,m);pric2(stdout,a);pric(stdout,p);
	    }
	    p->q1=a->q1;
	    m->next=p;p->prev=m;
	    if(p->next) p->next->prev=a;
	    a->next=p->next;
	    a->prev=p;p->next=a;
	    if(fg->end==p) fg->end=a;
	    if(p==last_ic) last_ic=a;
	    remove_IC_fg(fg,m);
	    av_update(a,isused);
	    p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
	    memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
	    p->use_cnt+=a->use_cnt;
	    changed=1;
	    if((f&DREFOBJ)&&p->q1.v->index>=rcount)
	      ierror(0);
	  }
	  p->q1.flags=f;
	  p->q1.dtyp=dt;
	}
	if(p->code!=TEST&&p->code!=COMPARE&&(p->q2.flags&VAR)&&!BTST(isused,p->q2.v->index)&&(!(p->z.flags&VAR)||!p->z.v->reg||p->z.v->identifier)){
          struct IC *m,*a;int f=p->q2.flags,dt=p->q2.dtyp;
	  p->q2.flags&=~DREFOBJ;
	  a=p->prev;if(a) m=a->prev; else m=0;
	  if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->q2,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
	    if(DEBUG&1024){
	      printf("reorder post-op(q2):\n");
	      pric2(stdout,m);pric2(stdout,a);pric(stdout,p);
	    }
	    p->q2=a->q1;
	    m->next=p;p->prev=m;
	    if(p->next) p->next->prev=a;
	    a->next=p->next;
	    a->prev=p;p->next=a;
	    if(fg->end==p) fg->end=a;
	    if(p==last_ic) last_ic=a;
	    remove_IC_fg(fg,m);
	    av_update(a,isused);
	    p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
	    memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
	    p->use_cnt+=a->use_cnt;
	    changed=1;
	    if((f&DREFOBJ)&&p->q2.v->index>=rcount)
	      ierror(0);
	  }
	  p->q2.flags=f;
	  p->q2.dtyp=dt;
	}
	if(p->code!=TEST&&p->code!=COMPARE&&(p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&!BTST(isused,p->z.v->index)){
          struct IC *m,*a;int f=p->z.flags,dt=p->z.dtyp;
	  p->z.flags&=~DREFOBJ;
	  a=p->prev;if(a) m=a->prev; else m=0;
	  if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->z,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
	    if(DEBUG&1024){
	      printf("reorder post-op(z):\n");
	      pric2(stdout,m);pric2(stdout,a);pric2(stdout,p);
	      printf("--");
	    }
	    p->z=a->q1;
	    m->next=p;p->prev=m;
	    if(p->next) p->next->prev=a;
	    a->next=p->next;
	    a->prev=p;p->next=a;
	    if(fg->end==p) fg->end=a;
	    if(p==last_ic) last_ic=a;
	    remove_IC_fg(fg,m);
	    av_update(a,isused);
	    p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
	    memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
	    p->use_cnt+=a->use_cnt;
	    changed=1;
	    if((f&DREFOBJ)&&p->z.v->index>=rcount)
	      ierror(0);
	  }
	  p->z.flags=f;
	  p->z.dtyp=dt;
	}
	av_update(p,isused);
	if(p==fg->start) break;
	p=p->prev;
      }
      fg=fg->normalout;
    }
    free(isused);
    return(changed);
}
Exemplo n.º 18
0
ALIST_API int ALIsActive(ALHandle hAL)
{
  return BTST((*hAL)->flags, alFActive) ? 1 : 0;
}
bool ShouldSpawnNumberBubble(Object* self)
{
	return BTST(VAR_W(self, bubbleFlagsW), BubbleFlags_SpawnNumber) &&
		(RandomNumber(4) == 0 || VAR_B(self, spawnTimerB) == 0) &&
		!BTST(VAR_W(self, bubbleFlagsW), BubbleFlags_NumberSpawned);
}
Exemplo n.º 20
0
static int node_dynamic_parse(struct bNode *node)
{
#ifndef WITH_PYTHON
	return -1;
#else
	PyObject *dict= NULL;
	PyObject *pynode_data= NULL;
	PyObject *pynode= NULL;
	PyObject *args= NULL;
	NodeScriptDict *nsd = NULL;
	PyObject *pyresult = NULL;
	char *buf = NULL;
	int is_valid_script = 0;
	PyGILState_STATE gilstate;

	if (!node->id || !node->storage)
		return 0;

	/* READY, no need to be here */
	if (BTST(node->custom1, NODE_DYNAMIC_READY))
		return 0;

	/* for threading */
	gilstate = PyGILState_Ensure();

	nsd = (NodeScriptDict *)node->storage;

	dict = (PyObject *)(nsd->dict);
	buf = txt_to_buf((Text *)node->id);

	pyresult = PyRun_String(buf, Py_file_input, dict, dict);

	MEM_freeN(buf);

	if (!pyresult) {
		if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) {
			node_dynamic_disable(node);
		} else {
		node_dynamic_disable_all_by_id(node->id);
		}
		node_dynamic_pyerror_print(node);
		PyGILState_Release(gilstate);
		return -1;
	}

	Py_DECREF(pyresult);

	pynode_data = node_dynamic_get_pynode(dict);

	if (pynode_data) {
		BPy_NodeSocketLists *socklists = Node_CreateSocketLists(node);

		args = Py_BuildValue("(O)", socklists);

		/* init it to get the input and output sockets */
		pynode = PyObject_Call(pynode_data, args, NULL);

		Py_DECREF(pynode_data);
		Py_DECREF(socklists);
		Py_DECREF(args);

		if (!PyErr_Occurred() && pynode && pytype_is_pynode(pynode)) {
			InitNode((BPy_Node *)(pynode), node);
			nsd->node = pynode;
			node->typeinfo->execfunc = node_dynamic_exec_cb;
			is_valid_script = 1;

			/* for NEW, LOADED, REPARSE */
			if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) {
				node->typeinfo->pydict = dict;
				node->typeinfo->pynode = pynode;
				node->typeinfo->id = node->id;
				if (BNTST(node->custom1, NODE_DYNAMIC_LOADED))
					nodeAddSockets(node, node->typeinfo);
				if (BNTST(node->custom1, NODE_DYNAMIC_REPARSE))
					node_dynamic_register_type(node);
			}

			node->custom1 = 0;
			node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);
		}
	}

	PyGILState_Release(gilstate);

	if (!is_valid_script) { /* not a valid pynode script */
		node_dynamic_disable_all_by_id(node->id);
		node_dynamic_pyerror_print(node);
		return -1;
	}

	return 0;
#endif
}
Exemplo n.º 21
0
/* node_dynamic_setup: prepare for execution (state: NODE_DYNAMIC_READY)
 * pynodes already linked to a script (node->id != NULL). */
static void node_dynamic_setup(bNode *node)
{
#ifdef WITH_PYTHON
	NodeScriptDict *nsd = NULL;
	bNodeTree *nodetree = NULL;
	bNodeType *ntype = NULL;
	PyGILState_STATE gilstate;

	/* Possible cases:
	 * NEW
	 * ADDEXIST
	 * LOADED
	 * REPARSE
	 * ERROR
	 * READY
	 */

	/* NEW, but not linked to a script: link default (empty) typeinfo */
	if (!node->id) {
		node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders,
				NULL);
		return;
	}

	/* READY, no need to be here */
	if (BTST(node->custom1, NODE_DYNAMIC_READY))
		return;

	gilstate = PyGILState_Ensure();

	/* ERROR, reset to (empty) defaults */
	if (BCLR(node->custom1, NODE_DYNAMIC_ERROR) == 0) {
		node_dynamic_reset(node, 0);
		PyGILState_Release(gilstate);
		return;
	}

	/* User asked to update this pynode, prepare it for reparsing */
	if (BTST(node->custom1, NODE_DYNAMIC_REPARSE)) {
		int needs_parsing = 1;

		node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW);

		if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
			node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_REPARSE);
			ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id);

			if (ntype) {
				node->typeinfo = ntype;
				node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
				node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ERROR);
				needs_parsing = 0;
			}
			else { nodeMakeDynamicType(node); }

		} else {
			node_dynamic_rem_all_links(node->typeinfo);
			node_dynamic_free_typeinfo_sockets(node->typeinfo);
			node_dynamic_update_socket_links(node, NULL);
			node_dynamic_free_storage_cb(node);
		}

		if (needs_parsing) {
			nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
			nsd->dict = init_dynamicdict();
			node->storage = nsd;
			/* prepared, now reparse: */
			node_dynamic_parse(node);
			PyGILState_Release(gilstate);
			return;
		}
	}
	else if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) {
		/* when loading from a .blend we don't have G.main yet, so we
		 * quickly abuse node->storage in ntreeInitTypes (node.c) to have
		 * our nodetree ptr (needed if a pynode script that worked before
		 * saving the .blend for some reason fails upon loading): */
		nodetree = (bNodeTree *)node->storage;
		node->storage = NULL;
	}

	if (node->storage)
		fprintf(stderr, "\nDEBUG: PYNODES ERROR: non NULL node->storage in node_dynamic_setup()\n");

	nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
	node->storage = nsd;
	
	/* NEW, LOADED or REPARSE */
	if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) {
		/* check if there's already a bNodeType linked to this script */
		/* (XXX hardcoded for shader nodes for now) */
		ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id);

		if (ntype) { /* if so, reuse it */
			node->typeinfo = ntype;
			/* so this is actually an ADDEXIST type */
			node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
		}
		else { /* create bNodeType for this pynode */
			nodeMakeDynamicType(node);
			nsd->dict = init_dynamicdict();
			if ((node_dynamic_parse(node) == -1) && nodetree) {
				node_dynamic_reset_loaded(node);
			}
			PyGILState_Release(gilstate);
			return;
		}
	}

	/* ADDEXIST: new pynode linked to an already registered dynamic type,
	 * we just reuse existing py dict and pynode */
	nsd->dict = node->typeinfo->pydict;
	nsd->node = node->typeinfo->pynode;

	Py_INCREF((PyObject *)(nsd->dict));
	Py_INCREF((PyObject *)(nsd->node));

	if (BTST(node->custom1, NODE_DYNAMIC_NEW)) {
		nodeAddSockets(node, node->typeinfo);
		node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_NEW);
	}

	node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ADDEXIST);
	node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);

	PyGILState_Release(gilstate);
#endif /* WITH_PYTHON */
	return;
}
Exemplo n.º 22
0
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//		¥ WEIsAnchorAtEnd
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
bool WEIsAnchorAtEnd(
	WEHandle		hWE)
{
	return BTST((*hWE)->flags, weFAnchorIsEnd)!=0;
}
Exemplo n.º 23
0
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//		¥ WEFastSetStyle
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// Sets the style without making an undo entry and can effect any text range, not just the selection
OSErr WEFastSetStyle(
	WEStyleMode		mode,
	const TextStyle *ts,
	SInt32			inStart,
	SInt32			inEnd,
	WEHandle		hWE)
{
	WEPtr pWE;
	WEActionHandle hAction;
	ScriptCode fontScript;
	Boolean saveWELock;
	OSErr err;

	// lock the WE record
	saveWELock = _WESetHandleLock((Handle) hWE, true);
	pWE = *hWE;

	// return an error code if this instance is read-only
	err = weReadOnlyErr;
	if (BTST(pWE->features, weFReadOnly))
	{
		goto cleanup;
	}

	// stop any ongoing inline input session
	WEStopInlineSession(hWE);

	if (BTST(pWE->features, weFMonoStyled))
	{
		// MONOSTYLED TEXT
		// apply the change to the whole text, not just to the selection range
		if ((err = _WESetStyleRange(0, pWE->textLength, mode, (WETextStyle *) ts, hWE)) != noErr)
		{
			goto cleanup;
		}

		// invalidate the null style record
		BCLR(pWE->flags, weFUseNullStyle);

		// redraw the text
		if ((err = _WERedraw(0, pWE->textLength, hWE)) != noErr)
		{
			goto cleanup;
		}
	}
	else if (inStart == inEnd)
	{
		// MULTISTYLED TEXT; NULL SELECTION
		// first make sure the nullStyle field contains valid information
		_WESynchNullStyle(hWE);

		// apply style changes to the nullStyle record
		_WECopyStyle((WETextStyle *) ts, &pWE->nullStyle.runStyle, pWE->nullStyle.runStyle.tsFace, mode);

		// special case: if this instance is empty, propagate the
		// change to the style table (this avoids some subtle problems)
		if (pWE->textLength == 0)
		{
			if ((err = _WESetStyleRange(0, 0, weDoAll + weDoReplaceFace, &pWE->nullStyle.runStyle, hWE)) != noErr)
			{
				goto cleanup;
			}
		}

#if !WASTE_NO_SYNCH
		// if the font was altered, synchronize the keyboard script
		if (BTST(pWE->flags, weFNonRoman) && (mode & weDoFont))
		{
			fontScript = FontToScript(pWE->nullStyle.runStyle.tsFont);
			if (fontScript != GetScriptManagerVariable(smKeyScript))
			{
				KeyScript(fontScript);
			}
		}
#endif
	}
	else
	{
		// MULTISTYLED TEXT; NON-EMPTY SELECTION

		// increment modification count
		pWE->modCount++;

		// check for "smart" font modes
		if (BTST(pWE->flags, weFNonRoman) && ((mode & weDoSmartFont) == weDoSmartFont))
		{
			if ((err = _WESmartSetFont(mode, ts, hWE)) != noErr)
			{
				goto cleanup;
			}
			mode &= ~weDoFont;
		}

		// set the style of the selection range
		if ((err = _WESetStyleRange(inStart,inEnd, mode, (WETextStyle *) ts, hWE)) != noErr)
		{
			goto cleanup;
		}

		// and redraw the text
		if ((err = _WERedraw(inStart,inEnd, hWE)) != noErr)
		{
			goto cleanup;
		}
	}

	// clear the result code
	err = noErr;

cleanup:
	// unlock the WE record
	_WESetHandleLock((Handle) hWE, saveWELock);

	// return result code
	return err;
}
Exemplo n.º 24
0
void EntryPoint()
{
    if(z80_port_1_control == 0 && z80_expansion_control == 0)
    {
        if(z80_version & 0xF) // hw version
            tmss_register = FOURCC("SEGA");

        VDP_Control(); // dummy read?
        SET_USP(0); // set user stack pointer to top of memory (since stack grows down)

        VDP_RegWrite(0x00, 4);            // 8-colour mode
        VDP_RegWrite(0x01, 0x14);         // Megadrive mode, DMA enable
        VDP_RegWrite(0x02, (0xC000>>10)); // foreground nametable address
        VDP_RegWrite(0x03, (0xF000>>10)); // window nametable address
        VDP_RegWrite(0x04, (0xE000>>13)); // background nametable address
        VDP_RegWrite(0x05, (0xD800>>9));  // sprite table address
        VDP_RegWrite(0x06, 0);            // unused
        VDP_RegWrite(0x07, 0);            // background colour
        VDP_RegWrite(0x08, 0);            // unused
        VDP_RegWrite(0x09, 0);            // unused
        VDP_RegWrite(0x0A, 255);          // HBlank register
        VDP_RegWrite(0x0B, 0);            // full screen scroll
        VDP_RegWrite(0x0C, 0x81);         // 40 cell display
        VDP_RegWrite(0x0D, (0xDC00>>10)); // hscroll table address
        VDP_RegWrite(0x0E, 0);            // unused
        VDP_RegWrite(0x0F, 1);            // VDP increment
        VDP_RegWrite(0x10, 1);            // 64 cell hscroll size
        VDP_RegWrite(0x11, 0);            // window h position
        VDP_RegWrite(0x12, 0);            // window v position
        VDP_ClearVRAM();
        STOP_Z80();
        RESET_Z80();
        WAIT_Z80();
        memcpy(z80_ram, Z80_Program, sizeof(Z80_Program));
        RESET_Z80a();
        WAIT_Z80();
        RESET_Z80();
        memset(0xFFFF0000, 0, 0x10000); // clear RAM
        VDP_RegWrite(0x01, 4);
        VDP_RegWrite(0x0F, 2);
        VDP_ClearCRAM();
        VDP_ClearVSRAM();
        VDP_PSG_Write(0x9F);
        VDP_PSG_Write(0xBF);
        VDP_PSG_Write(0xDF);
        VDP_PSG_Write(0xFF);
        RESET_Z80a();
        DISABLE_INTERRUPTS();
    }

    VDP_Control(); // dummy read?

    if(!BTST(z80_expansion_control, 1 << 6) || v_init != FOURCC("init"))
    {
        // checksum would go here, which is not important or implementable in HLL
        memset(0xFFFFFE00, 0, 0x200);
        v_megadrive = z80_version & 0xC0;
        v_init = FOURCC("init");
    }

    memset(0xFFFF0000, 0, 0xFE00);

    VDP_SetupGame();
    SoundDriverLoad();
    JoypadInit();
    v_gamemode = GameMode_Sega;

    while(true)
    {
        switch(v_gamemode & 0x1C)
        {
        case GameMode_Sega:
            GM_Sega();
            break;
        case GameMode_Title:
            GM_Title();
            break;
        case GameMode_Demo:
        case GameMode_Level:
            GM_Level();
            break;
        case GameMode_Special:
            GM_Special();
            break;
        case GameMode_Continue:
            GM_Continue();
            break;
        case GameMode_Ending:
            GM_Ending();
            break;
        case GameMode_Credits:
            GM_Credits();
            break;
        }
    }
}
void DrownCount(Object* self)
{
	switch(self->routine)
	{
		case Routine_Init:
			self->routine = Routine_BubbleExpanding;
			self->map = Map_Bub;
			self->gfx = GFX_Bubble;
			Obj_SetVisible(self);
			Obj_SetBehind(self);
			self->actWid = 16;
			self->priority = 1;

			if(BTST(self->subtype, Subtype_Master))
			{
				self->routine = Routine_Master;
				self->map = Map_Drown;
				self->gfx = GFX_Master;
				VAR_B(self, alwaysOneB) = self->subtype & ~Subtype_Master;
				goto _masterRoutine;
			}

			// Bubble
			self->anim = self->subtype;
			VAR_W(self, origXW) = self->x;
			self->velY = -Bubble_Velocity;
			// fall through
		case Routine_BubbleExpanding:
			AnimateSprite(self, Ani_Drown);
			// fall through
		case Routine_BubbleRising:
			// Still underwater?
			if(self->y >= vWaterpos1)
			{
				// Move bubbles with tunnel current
				if(fWtunnelmode)
					VAR_W(self, origXW) += 4;

				// Wobble
				self->x = VAR_W(self, origXW) + Bubble_Wobble[self->angle & 0x7F];
				self->angle++;

				// Update appearance
				CheckNumberBubbleConversion(self);
				SpeedToPos(self);

				if(Object_IsVisible(self))
					DisplaySprite(self);
				else
					DeleteObject(self);
				break;
			}
			else
			{
				// Reached surface? For small bubbles, this sets their anim to blank and will go routine 6 > 8 and die
				// Big bubbles actually glitch out when they reach the surface cause there aren't enough enim mappings!
				self->routine = Routine_BubbleDying;
				self->anim += 7;
			}
			// fall through
		case Routine_BubbleDying:
		case Routine_NumberUpdate:
		_display:
			// Update appearance
			CheckNumberBubbleConversion(self);
			AnimateSprite(self, Ani_Drown);
			DisplaySprite(self);
			break;

		case Routine_BubbleDead:
		case Routine_NumberDead:
			DeleteObject(self);
			break;

		// Once a number-bubble gets plastered to the screen, it enters this state which handles switching to the
		// "flashing number" animation.
		case Routine_NumberTransition:
			if(v_air > Drown_Air)
			{
				DeleteObject(self);
				break;
			}

			if(TimerZero(VAR_W(self, frameTimerW)))
			{
				self->routine = Routine_NumberUpdate;
				self->anim += 7;
				goto _display;
			}

			AnimateSprite(self, Ani_Drown);

			if(Object_IsVisible(self))
				DisplaySprite(self);
			else
				DeleteObject(self);
			break;

		// The "master" object, spawned when Sonic goes underwater for the first time, goes into this routine forever.
		// It manages counting down the air meter, spawning bubbles/numbers, and drowning/killing Sonic.
		case Routine_Master:
		_masterRoutine:
			// If we're not currently drowning...
			if(VAR_W(self, drowningTimeW) == 0)
			{
				// Manage counting down the timer and stuff
				if(Player_IsDead() || !Player_IsUnderwater())
					return;

				// Count down frames until the next second
				if(TimerNeg(VAR_W(self, frameTimerW), 59))
				{
					VAR_W(self, bubbleFlagsW) = BubbleFlags_Enable;
					VAR_B(self, spawnTimerB) = RandomNumber(2);

					if(ShouldDing())
						PlaySound_Special(SFX_Warning); // ding-ding
					else if(v_air <= Drown_Air)
					{
						if(v_air == Drown_Air)
							PlaySound(BGM_Drowning); // uh oh

						if(TimerNeg(VAR_B(self, sillyTimerB), VAR_B(self, alwaysOneB)))
							BSET(VAR_W(self, bubbleFlagsW), BubbleFlags_SpawnNumber);
					}

					if(TimerNeg(v_air))
					{
						// Drowning time.
						ResumeMusic();
						f_lockmulti = 0x81;
						PlaySound_Special(SFX_Drown);
						VAR_B(self, spawnTimerB) = 10;
						VAR_W(self, bubbleFlagsW) = BubbleFlags_Enable;
						VAR_W(self, drowningTimeW) = Drown_Length;
						Player_ResetOnFloor(v_player);
						Player_SetAnimDrowning();
						Player_SetInAir();
						v_player->gfx |= 0x80;
						v_player->velY = 0;
						v_player->velX = 0;
						v_player->inertia = 0;
						f_nobgscroll = true;
						return;
					}

					goto _makeBubble;
				}
			}
			else
			{
				// Manage the drowning animation (Sonic falling offscreen)
				if(TimerZero(VAR_W(self, drowningTimeW)))
				{
					Player_SetDead();
					return;
				}

				SpeedToPos(v_player);
				v_player->velY += Drown_Velocity;
			}

			// Bubble spawning enabled?
			if(VAR_W(self, bubbleFlagsW))
			{
				if(TimerNeg(VAR_W(self, bubbleTimerW)))
				{
				_makeBubble:
					VAR_W(self, bubbleTimerW) = RandomNumber(16);

					if(auto bubble = FindFreeObj())
					{
						auto bubble = &v_objspace[slot];
						bubble->id = ID_DrownCount;
						bubble->x v_player->x + (Player_IsFlipped() ? -Bubble_OffsX : Bubble_OffsX);
						bubble->y = v_player->y;
						bubble->angle = Player_IsFlipped() ? Bubble_AngleFlipped : 0;
						bubble->subtype = Subtype_SmallBubble;

						// If we're doing drowning-bubbles..
						if(VAR_W(self, drowningTimeW) != 0)
						{
							VAR_W(self, bubbleTimerW) &= 7;
							bubble->y = v_player->y - Bubble_DrownOffsY;
							bubble->angle = RandomNumber(256);

							// 1/4 bubbles are made bigger
							if((v_framecount & 3) == 0)
								bubble->subtype = Subtype_MediumBubble;
						}
						else if(ShouldSpawnNumberBubble(self))
						{
							BSET(VAR_W(self, bubbleFlagsW), BubbleFlags_NumberSpawned);
							bubble->subtype = GetCountdownDigit();
							VAR_W(bubble, frameTimerW) = NumberBubble_Timer1;
						}

						if(TimerNeg(VAR_B(self, spawnTimerB)))
							VAR_W(self, bubbleFlagsW) = 0;
					}
				}
			}

			break;
	}
}