static void forloop_execute(void *data, int thread, struct bNode *node, void *nodedata, struct bNodeStack **in, struct bNodeStack **out)
{
	bNodeTreeExec *exec= (bNodeTreeExec*)nodedata;
	int totiterations= (int)in[0]->vec[0];
	bNodeSocket *sock;
	bNodeStack *ns;
	int iteration;
	
	/* XXX same behavior as trunk: all nodes inside group are executed.
	 * it's stupid, but just makes it work. compo redesign will do this better.
	 */
	{
		bNode *inode;
		for (inode=exec->nodetree->nodes.first; inode; inode=inode->next)
			inode->need_exec = 1;
	}
	
	/* "Iteration" socket */
	sock = exec->nodetree->inputs.first;
	ns = node_get_socket_stack(exec->stack, sock);
	
	group_copy_inputs(node, in, exec->stack);
	for (iteration=0; iteration < totiterations; ++iteration) {
		/* first input contains current iteration counter */
		ns->vec[0] = (float)iteration;
		
		if (iteration > 0)
			loop_iteration_reset(exec->nodetree, exec->stack);
		ntreeExecNodes(exec, data, thread);
		group_free_internal(exec);
	}
	group_move_outputs(node, out, exec->stack);
}
static void group_execute(void *data, int thread, struct bNode *node, void *nodedata, struct bNodeStack **in, struct bNodeStack **out)
{
	bNodeTreeExec *exec= (bNodeTreeExec*)nodedata;
	bNodeThreadStack *nts;
	
	if (!exec)
		return;
	
	/* XXX same behavior as trunk: all nodes inside group are executed.
	 * it's stupid, but just makes it work. compo redesign will do this better.
	 */
	{
		bNode *inode;
		for (inode=exec->nodetree->nodes.first; inode; inode=inode->next)
			inode->need_exec = 1;
	}
	
	nts = ntreeGetThreadStack(exec, thread);
	
	group_copy_inputs(node, in, nts->stack);
	ntreeExecThreadNodes(exec, nts, data, thread);
	group_move_outputs(node, out, nts->stack);
	
	ntreeReleaseThreadStack(nts);
}
static void group_execute(void *data, int thread, struct bNode *node, void *nodedata, struct bNodeStack **in, struct bNodeStack **out)
{
	bNodeTreeExec *exec= (bNodeTreeExec*)nodedata;
	
	/* XXX same behavior as trunk: all nodes inside group are executed.
	 * it's stupid, but just makes it work. compo redesign will do this better.
	 */
	{
		bNode *inode;
		for (inode=exec->nodetree->nodes.first; inode; inode=inode->next)
			inode->need_exec = 1;
	}
	
	group_copy_inputs(node, in, exec->stack);
	ntreeExecNodes(exec, data, thread);
	group_free_internal(exec);
	group_move_outputs(node, out, exec->stack);
}
/**** WHILE LOOP ****/

#if 0 /* XXX loop nodes don't work nicely with current trees */
static void whileloop_execute(void *data, int thread, struct bNode *node, void *nodedata, struct bNodeStack **in, struct bNodeStack **out)
{
	bNodeTreeExec *exec= (bNodeTreeExec*)nodedata;
	int condition= (in[0]->vec[0] > 0.0f);
	bNodeSocket *sock;
	bNodeStack *ns;
	int iteration;
	
	/* XXX same behavior as trunk: all nodes inside group are executed.
	 * it's stupid, but just makes it work. compo redesign will do this better.
	 */
	{
		bNode *inode;
		for (inode=exec->nodetree->nodes.first; inode; inode=inode->next)
			inode->need_exec = 1;
	}
	
	/* "Condition" socket */
	sock = exec->nodetree->outputs.first;
	ns = node_get_socket_stack(exec->stack, sock);
	
	iteration = 0;
	group_copy_inputs(node, in, exec->stack);
	while (condition && iteration < node->custom1) {
		if (iteration > 0)
			loop_iteration_reset(exec->nodetree, exec->stack);
		ntreeExecNodes(exec, data, thread);
		group_free_internal(exec);
		
//		PRINT_BUFFERS(exec);
		
		condition = (ns->vec[0] > 0.0f);
		++iteration;
	}
	group_move_outputs(node, out, exec->stack);
}