Beispiel #1
0
static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float *UNUSED(progress))
{
	ThumbnailJob *tj= tjv;
	FileImage* limg = tj->loadimages.first;

	tj->stop= stop;
	tj->do_update= do_update;

	while ( (*stop==0) && (limg) ) {
		if ( limg->flags & IMAGEFILE ) {
			limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE);
		}
		else if ( limg->flags & BLENDERFILE ) {
			limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_BLEND);
		}
		else if ( limg->flags & MOVIEFILE ) {
			limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_MOVIE);
			if (!limg->img) {
					/* remember that file can't be loaded via IMB_open_anim */
					limg->flags &= ~MOVIEFILE;
					limg->flags |= MOVIEFILE_ICON;
				}
		}
		*do_update = 1;
		PIL_sleep_ms(10);
		limg = limg->next;
	}
}
Beispiel #2
0
static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float *UNUSED(progress))
{
	ThumbnailJob *tj = tjv;
	FileImage *limg = tj->loadimages.first;

	tj->stop = stop;
	tj->do_update = do_update;

	while ((*stop == 0) && (limg)) {
		ThumbSource source = 0;

		BLI_assert(limg->flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
		                          FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP));
		if (limg->flags & FILE_TYPE_IMAGE) {
			source = THB_SOURCE_IMAGE;
		}
		else if (limg->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
			source = THB_SOURCE_BLEND;
		}
		else if (limg->flags & FILE_TYPE_MOVIE) {
			source = THB_SOURCE_MOVIE;
		}
		else if (limg->flags & FILE_TYPE_FTFONT) {
			source = THB_SOURCE_FONT;
		}
		limg->img = IMB_thumb_manage(limg->path, THB_LARGE, source);
		*do_update = true;
		PIL_sleep_ms(10);
		limg = limg->next;
	}
}
Beispiel #3
0
void BLI_insert_work(ThreadedWorker *worker, void *param)
{
	WorkParam *p = MEM_callocN(sizeof(WorkParam), "workparam");
	int index;
	
	if (BLI_available_threads(&worker->threadbase) == 0)
	{
		index = worker->total;
		while(index == worker->total)
		{
			PIL_sleep_ms(worker->sleep_time);
			
			for (index = 0; index < worker->total; index++)
			{
				if (worker->busy[index] == 0)
				{
					BLI_remove_thread_index(&worker->threadbase, index);
					break;
				}
			}
		}
	}
	else
	{
		index = BLI_available_thread_index(&worker->threadbase);
	}
	
	worker->busy[index] = 1;
	
	p->param = param;
	p->index = index;
	p->worker = worker;
	
	BLI_insert_thread(&worker->threadbase, p);
}
Beispiel #4
0
void wm_window_process_events(const bContext *C) 
{
	int hasevent = GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
	
	if (hasevent)
		GHOST_DispatchEvents(g_system);
	
	hasevent |= wm_window_timer(C);

	/* no event, we sleep 5 milliseconds */
	if (hasevent == 0)
		PIL_sleep_ms(5);
}
/* optimized tree execute test for compositing */
static void ntreeCompositExecTreeOld(bNodeTree *ntree, RenderData *rd, int do_preview)
{
	bNodeExec *nodeexec;
	bNode *node;
	ListBase threads;
	ThreadData thdata;
	int totnode, curnode, rendering = TRUE, n;
	bNodeTreeExec *exec = ntree->execdata;

	if (do_preview)
		ntreeInitPreview(ntree, 0, 0);
	
	if (!ntree->execdata) {
		/* XXX this is the top-level tree, so we use the ntree->execdata pointer. */
		exec = ntreeCompositBeginExecTree(ntree, 1);
	}
	ntree_composite_texnode(ntree, 1);
	
	/* prevent unlucky accidents */
	if (G.background)
		rd->scemode &= ~R_COMP_CROP;
	
	/* setup callerdata for thread callback */
	thdata.rd= rd;
	thdata.stack= exec->stack;
	
	/* fixed seed, for example noise texture */
	BLI_srandom(rd->cfra);

	/* sets need_exec tags in nodes */
	curnode = totnode= setExecutableNodes(exec, &thdata);

	BLI_init_threads(&threads, exec_composite_node, rd->threads);
	
	while (rendering) {
		
		if (BLI_available_threads(&threads)) {
			nodeexec= getExecutableNode(exec);
			if (nodeexec) {
				node = nodeexec->node;
				if (ntree->progress && totnode)
					ntree->progress(ntree->prh, (1.0f - curnode/(float)totnode));
				if (ntree->stats_draw) {
					char str[128];
					BLI_snprintf(str, sizeof(str), "Compositing %d %s", curnode, node->name);
					ntree->stats_draw(ntree->sdh, str);
				}
				curnode--;
				
				node->threaddata = &thdata;
				node->exec= NODE_PROCESSING;
				BLI_insert_thread(&threads, nodeexec);
			}
			else
				PIL_sleep_ms(50);
		}
		else
			PIL_sleep_ms(50);
		
		rendering= 0;
		/* test for ESC */
		if (ntree->test_break && ntree->test_break(ntree->tbh)) {
			for (node= ntree->nodes.first; node; node= node->next)
				node->exec |= NODE_READY;
		}
		
		/* check for ready ones, and if we need to continue */
		for (n=0, nodeexec=exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
			node = nodeexec->node;
			if (node->exec & NODE_READY) {
				if ((node->exec & NODE_FINISHED)==0) {
					BLI_remove_thread(&threads, nodeexec); /* this waits for running thread to finish btw */
					node->exec |= NODE_FINISHED;
					
					/* freeing unused buffers */
					if (rd->scemode & R_COMP_FREE)
						freeExecutableNode(exec);
				}
			}
			else rendering= 1;
		}
	}
	
	BLI_end_threads(&threads);
	
	/* XXX top-level tree uses the ntree->execdata pointer */
	ntreeCompositEndExecTree(exec, 1);
}
Beispiel #6
0
/* return path for restart */
static char *wm_main_playanim_intern(int argc, const char **argv)
{
	struct ImBuf *ibuf = NULL;
	static char filepath[FILE_MAX];	/* abused to return dropped file path */
	GHOST_TUns32 maxwinx, maxwiny;
	int i;
	/* This was done to disambiguate the name for use under c++. */
	struct anim *anim = NULL;
	int start_x = 0, start_y = 0;
	int sfra = -1;
	int efra = -1;
	int totblock;
	
	PlayState ps = {0};

	/* ps.doubleb   = TRUE;*/ /* UNUSED */
	ps.go        = TRUE;
	ps.direction = TRUE;
	ps.next_frame = 1;
	ps.once      = FALSE;
	ps.turbo     = FALSE;
	ps.pingpong  = FALSE;
	ps.noskip    = FALSE;
	ps.sstep     = FALSE;
	ps.wait2     = FALSE;
	ps.stopped   = FALSE;
	ps.picture   = NULL;
	ps.dropped_file[0] = 0;
	ps.zoom      = 1.0f;
	/* resetmap = FALSE */

	ps.fstep     = 1;

	ps.fontid = -1;

	while (argc > 1) {
		if (argv[1][0] == '-') {
			switch (argv[1][1]) {
				case 'm':
					fromdisk = TRUE;
					break;
				case 'p':
					if (argc > 3) {
						start_x = atoi(argv[2]);
						start_y = atoi(argv[3]);
						argc -= 2;
						argv += 2;
					}
					else {
						printf("too few arguments for -p (need 2): skipping\n");
					}
					break;
				case 'f':
					if (argc > 3) {
						double fps = atof(argv[2]);
						double fps_base = atof(argv[3]);
						if (fps == 0.0) {
							fps = 1;
							printf("invalid fps,"
							       "forcing 1\n");
						}
						swaptime = fps_base / fps;
						argc -= 2;
						argv += 2;
					}
					else {
						printf("too few arguments for -f (need 2): skipping\n");
					}
					break;
				case 's':
					sfra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
					argc--;
					argv++;
					break;
				case 'e':
					efra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
					argc--;
					argv++;
					break;
				case 'j':
					ps.fstep = MIN2(MAXFRAME, MAX2(1, atoi(argv[2])));
					swaptime *= ps.fstep;
					argc--;
					argv++;
					break;
				default:
					printf("unknown option '%c': skipping\n", argv[1][1]);
					break;
			}
			argc--;
			argv++;
		}
		else {
			break;
		}
	}

	if (argc > 1) {
		BLI_strncpy(filepath, argv[1], sizeof(filepath));
	}
	else {
		BLI_current_working_dir(filepath, sizeof(filepath));
		BLI_add_slash(filepath);
	}

	if (IMB_isanim(filepath)) {
		/* OCIO_TODO: support different input color spaces */
		anim = IMB_open_anim(filepath, IB_rect, 0, NULL);
		if (anim) {
			ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
			IMB_close_anim(anim);
			anim = NULL;
		}
	}
	else if (!IMB_ispic(filepath)) {
		printf("%s: '%s' not an image file\n", __func__, filepath);
		exit(1);
	}

	if (ibuf == NULL) {
		/* OCIO_TODO: support different input color space */
		ibuf = IMB_loadiffname(filepath, IB_rect, NULL);
	}

	if (ibuf == NULL) {
		printf("%s: '%s' couldn't open\n", __func__, filepath);
		exit(1);
	}

#if 0 //XXX25
	#if !defined(WIN32) && !defined(__APPLE__)
	if (fork()) exit(0);
	#endif
#endif //XXX25

	{

		GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);

		g_WS.ghost_system = GHOST_CreateSystem();
		GHOST_AddEventConsumer(g_WS.ghost_system, consumer);

		playanim_window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y);

		/* unified matrix, note it affects offset for drawing */
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
		glMatrixMode(GL_MODELVIEW);
	}

	GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &maxwinx, &maxwiny);

	//GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);

	/* initialize the font */
	BLF_init(11, 72);
	ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
	BLF_size(ps.fontid, 11, 72);

	ps.ibufx = ibuf->x;
	ps.ibufy = ibuf->y;
	
	ps.win_x = ps.ibufx;
	ps.win_y = ps.ibufy;

	if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x));
	if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y));

	
	glClearColor(0.1, 0.1, 0.1, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);

	GHOST_SwapWindowBuffers(g_WS.ghost_window);

	if (sfra == -1 || efra == -1) {
		/* one of the frames was invalid, just use all images */
		sfra = 1;
		efra = MAXFRAME;
	}

	build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);

	for (i = 2; i < argc; i++) {
		BLI_strncpy(filepath, argv[i], sizeof(filepath));
		build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
	}

	IMB_freeImBuf(ibuf);
	ibuf = NULL;

	pupdate_time();
	ptottime = 0;

	/* newly added in 2.6x, without this images never get freed */
#define USE_IMB_CACHE

	while (ps.go) {
		if (ps.pingpong)
			ps.direction = -ps.direction;

		if (ps.direction == 1) {
			ps.picture = picsbase.first;
		}
		else {
			ps.picture = picsbase.last;
		}

		if (ps.picture == NULL) {
			printf("couldn't find pictures\n");
			ps.go = FALSE;
		}
		if (ps.pingpong) {
			if (ps.direction == 1) {
				ps.picture = ps.picture->next;
			}
			else {
				ps.picture = ps.picture->prev;
			}
		}
		if (ptottime > 0.0) ptottime = 0.0;

		while (ps.picture) {
			int hasevent;
#ifndef USE_IMB_CACHE
			if (ibuf != NULL && ibuf->ftype == 0) IMB_freeImBuf(ibuf);
#endif
			if (ps.picture->ibuf) {
				ibuf = ps.picture->ibuf;
			}
			else if (ps.picture->anim) {
				ibuf = IMB_anim_absolute(ps.picture->anim, ps.picture->frame, IMB_TC_NONE, IMB_PROXY_NONE);
			}
			else if (ps.picture->mem) {
				/* use correct colorspace here */
				ibuf = IMB_ibImageFromMemory((unsigned char *) ps.picture->mem, ps.picture->size,
				                             ps.picture->IB_flags, NULL, ps.picture->name);
			}
			else {
				/* use correct colorspace here */
				ibuf = IMB_loadiffname(ps.picture->name, ps.picture->IB_flags, NULL);
			}

			if (ibuf) {

#ifdef USE_IMB_CACHE
				ps.picture->ibuf = ibuf;
#endif

				BLI_strncpy(ibuf->name, ps.picture->name, sizeof(ibuf->name));

				/* why only windows? (from 2.4x) - campbell */
#ifdef _WIN32
				GHOST_SetTitle(g_WS.ghost_window, ps.picture->name);
#endif

				while (pupdate_time()) PIL_sleep_ms(1);
				ptottime -= swaptime;
				playanim_toscreen(&ps, ps.picture, ibuf, ps.fontid, ps.fstep);
			} /* else delete */
			else {
				printf("error: can't play this image type\n");
				exit(0);
			}

			if (ps.once) {
				if (ps.picture->next == NULL) {
					ps.wait2 = TRUE;
				}
				else if (ps.picture->prev == NULL) {
					ps.wait2 = TRUE;
				}
			}

			ps.next_frame = ps.direction;


			while ( (hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0)) || ps.wait2 != 0) {
				if (hasevent) {
					GHOST_DispatchEvents(g_WS.ghost_system);
				}
				/* Note, this still draws for mousemoves on pause */
				if (ps.wait2) {
					if (hasevent) {
						if (ibuf) {
							while (pupdate_time()) PIL_sleep_ms(1);
							ptottime -= swaptime;
							playanim_toscreen(&ps, ps.picture, ibuf, ps.fontid, ps.fstep);
						}
					}
				}
				if (!ps.go) {
					break;
				}
			}

			ps.wait2 = ps.sstep;

			if (ps.wait2 == 0 && ps.stopped == 0) {
				ps.stopped = TRUE;
			}

			pupdate_time();

			if (ps.picture && ps.next_frame) {
				/* always at least set one step */
				while (ps.picture) {
					ps.picture = playanim_step(ps.picture, ps.next_frame);

					if (ps.once && ps.picture != NULL) {
						if (ps.picture->next == NULL) {
							ps.wait2 = TRUE;
						}
						else if (ps.picture->prev == NULL) {
							ps.wait2 = TRUE;
						}
					}

					if (ps.wait2 || ptottime < swaptime || ps.turbo || ps.noskip) break;
					ptottime -= swaptime;
				}
				if (ps.picture == NULL && ps.sstep) {
					ps.picture = playanim_step(ps.picture, ps.next_frame);
				}
			}
			if (ps.go == FALSE) {
				break;
			}
		}
	}
	ps.picture = picsbase.first;
	anim = NULL;
	while (ps.picture) {
		if (ps.picture && ps.picture->anim && (anim != ps.picture->anim)) {
			// to prevent divx crashes
			anim = ps.picture->anim;
			IMB_close_anim(anim);
		}

		if (ps.picture->ibuf) {
			IMB_freeImBuf(ps.picture->ibuf);
		}
		if (ps.picture->mem) {
			MEM_freeN(ps.picture->mem);
		}

		ps.picture = ps.picture->next;
	}

	/* cleanup */
#ifndef USE_IMB_CACHE
	if (ibuf) IMB_freeImBuf(ibuf);
#endif

	BLI_freelistN(&picsbase);
#if 0 // XXX25
	free_blender();
#else
	/* we still miss freeing a lot!,
	 * but many areas could skip initialization too for anim play */
	
	BLF_exit();
#endif
	GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window);

	/* early exit, IMB and BKE should be exited only in end */
	if (ps.dropped_file[0]) {
		BLI_strncpy(filepath, ps.dropped_file, sizeof(filepath));
		return filepath;
	}
	
	IMB_exit();
	BKE_images_exit();

	totblock = MEM_get_memory_blocks_in_use();
	if (totblock != 0) {
		/* prints many bAKey, bArgument's which are tricky to fix */
#if 0
		printf("Error Totblock: %d\n", totblock);
		MEM_printmemlist();
#endif
	}
	
	return NULL;
}
Beispiel #7
0
/* Precache a volume into a 3D voxel grid.
 * The voxel grid is stored in the ObjectInstanceRen, 
 * in camera space, aligned with the ObjectRen's bounding box.
 * Resolution is defined by the user.
 */
void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma)
{
	VolumePrecache *vp;
	VolPrecachePart *nextpa, *pa;
	RayObject *tree;
	ShadeInput shi;
	ListBase threads;
	float *bbmin=obi->obr->boundbox[0], *bbmax=obi->obr->boundbox[1];
	int parts[3] = {1, 1, 1}, totparts;
	
	int caching=1, counter=0;
	int totthread = re->r.threads;
	
	double time, lasttime= PIL_check_seconds_timer();
	
	R = *re;

	/* create a raytree with just the faces of the instanced ObjectRen, 
	 * used for checking if the cached point is inside or outside. */
	//tree = create_raytree_obi(obi, bbmin, bbmax);
	tree = makeraytree_object(&R, obi);
	if (!tree) return;
	INIT_MINMAX(bbmin, bbmax);
	RE_rayobject_merge_bb( tree, bbmin, bbmax);

	vp = MEM_callocN(sizeof(VolumePrecache), "volume light cache");
	
	if (!precache_resolution(vp, bbmin, bbmax, ma->vol.precache_resolution)) {
		MEM_freeN(vp);
		vp = NULL;
		return;
	}

	vp->data_r = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data red channel");
	vp->data_g = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data green channel");
	vp->data_b = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data blue channel");
	obi->volume_precache = vp;

	/* Need a shadeinput to calculate scattering */
	precache_setup_shadeinput(re, obi, ma, &shi);
	
	precache_init_parts(re, tree, &shi, obi, totthread, parts);
	totparts = parts[0] * parts[1] * parts[2];
	
	BLI_init_threads(&threads, vol_precache_part, totthread);
	
	while(caching) {

		if(BLI_available_threads(&threads) && !(re->test_break(re->tbh))) {
			nextpa = precache_get_new_part(re);
			if (nextpa) {
				nextpa->working = 1;
				BLI_insert_thread(&threads, nextpa);
			}
		}
		else PIL_sleep_ms(50);

		caching=0;
		counter=0;
		for(pa= re->volume_precache_parts.first; pa; pa= pa->next) {
			
			if(pa->done) {
				counter++;
				BLI_remove_thread(&threads, pa);
			} else
				caching = 1;
		}
		
		if (re->test_break(re->tbh) && BLI_available_threads(&threads)==totthread)
			caching=0;
		
		time= PIL_check_seconds_timer();
		if(time-lasttime>1.0f) {
			char str[64];
			sprintf(str, "Precaching volume: %d%%", (int)(100.0f * ((float)counter / (float)totparts)));
			re->i.infostr= str;
			re->stats_draw(re->sdh, &re->i);
			re->i.infostr= NULL;
			lasttime= time;
		}
	}
	
	BLI_end_threads(&threads);
	BLI_freelistN(&re->volume_precache_parts);
	
	if(tree) {
		//TODO: makeraytree_object creates a tree and saves it on OBI, if we free this tree we should also clear other pointers to it
		//RE_rayobject_free(tree);
		//tree= NULL;
	}
	
	lightcache_filter(obi->volume_precache);
	
	if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE))
	{
		multiple_scattering_diffusion(re, vp, ma);
	}
}
Beispiel #8
0
/*
 * This thread is used to load video frame asynchronously.
 * It provides a frame caching service.
 * The main thread is responsible for positioning the frame pointer in the
 * file correctly before calling startCache() which starts this thread.
 * The cache is organized in two layers: 1) a cache of 20-30 undecoded packets to keep
 * memory and CPU low 2) a cache of 5 decoded frames.
 * If the main thread does not find the frame in the cache (because the video has restarted
 * or because the GE is lagging), it stops the cache with StopCache() (this is a synchronous
 * function: it sends a signal to stop the cache thread and wait for confirmation), then
 * change the position in the stream and restarts the cache thread.
 */
void *VideoFFmpeg::cacheThread(void *data)
{
	VideoFFmpeg* video = (VideoFFmpeg*)data;
	// holds the frame that is being decoded
	CacheFrame *currentFrame = NULL;
	CachePacket *cachePacket;
	bool endOfFile = false;
	int frameFinished = 0;
	double timeBase = av_q2d(video->m_formatCtx->streams[video->m_videoStream]->time_base);
	int64_t startTs = video->m_formatCtx->streams[video->m_videoStream]->start_time;

	if (startTs == AV_NOPTS_VALUE)
		startTs = 0;

	while (!video->m_stopThread)
	{
		// packet cache is used solely by this thread, no need to lock
		// In case the stream/file contains other stream than the one we are looking for,
		// allow a bit of cycling to get rid quickly of those frames
		frameFinished = 0;
		while (	   !endOfFile
				&& (cachePacket = (CachePacket *)video->m_packetCacheFree.first) != NULL
				&& frameFinished < 25)
		{
			// free packet => packet cache is not full yet, just read more
			if (av_read_frame(video->m_formatCtx, &cachePacket->packet)>=0)
			{
				if (cachePacket->packet.stream_index == video->m_videoStream)
				{
					// make sure fresh memory is allocated for the packet and move it to queue
					av_dup_packet(&cachePacket->packet);
					BLI_remlink(&video->m_packetCacheFree, cachePacket);
					BLI_addtail(&video->m_packetCacheBase, cachePacket);
					break;
				} else {
					// this is not a good packet for us, just leave it on free queue
					// Note: here we could handle sound packet
					av_free_packet(&cachePacket->packet);
					frameFinished++;
				}

			} else {
				if (video->m_isFile)
					// this mark the end of the file
					endOfFile = true;
				// if we cannot read a packet, no need to continue
				break;
			}
		}
		// frame cache is also used by main thread, lock
		if (currentFrame == NULL)
		{
			// no current frame being decoded, take free one
			pthread_mutex_lock(&video->m_cacheMutex);
			if ((currentFrame = (CacheFrame *)video->m_frameCacheFree.first) != NULL)
				BLI_remlink(&video->m_frameCacheFree, currentFrame);
			pthread_mutex_unlock(&video->m_cacheMutex);
		}
		if (currentFrame != NULL)
		{
			// this frame is out of free and busy queue, we can manipulate it without locking
			frameFinished = 0;
			while (!frameFinished && (cachePacket = (CachePacket *)video->m_packetCacheBase.first) != NULL)
			{
				BLI_remlink(&video->m_packetCacheBase, cachePacket);
				// use m_frame because when caching, it is not used in main thread
				// we can't use currentFrame directly because we need to convert to RGB first
				avcodec_decode_video2(video->m_codecCtx,
					video->m_frame, &frameFinished,
					&cachePacket->packet);
				if (frameFinished)
				{
					AVFrame * input = video->m_frame;

					/* This means the data wasnt read properly, this check stops crashing */
					if (   input->data[0]!=0 || input->data[1]!=0
						|| input->data[2]!=0 || input->data[3]!=0)
					{
						if (video->m_deinterlace)
						{
							if (avpicture_deinterlace(
								(AVPicture*) video->m_frameDeinterlaced,
								(const AVPicture*) video->m_frame,
								video->m_codecCtx->pix_fmt,
								video->m_codecCtx->width,
								video->m_codecCtx->height) >= 0)
							{
								input = video->m_frameDeinterlaced;
							}
						}
						// convert to RGB24
						sws_scale(video->m_imgConvertCtx,
							input->data,
							input->linesize,
							0,
							video->m_codecCtx->height,
							currentFrame->frame->data,
							currentFrame->frame->linesize);
						// move frame to queue, this frame is necessarily the next one
						video->m_curPosition = (long)((cachePacket->packet.dts-startTs) * (video->m_baseFrameRate*timeBase) + 0.5);
						currentFrame->framePosition = video->m_curPosition;
						pthread_mutex_lock(&video->m_cacheMutex);
						BLI_addtail(&video->m_frameCacheBase, currentFrame);
						pthread_mutex_unlock(&video->m_cacheMutex);
						currentFrame = NULL;
					}
				}
				av_free_packet(&cachePacket->packet);
				BLI_addtail(&video->m_packetCacheFree, cachePacket);
			}
			if (currentFrame && endOfFile)
			{
				// no more packet and end of file => put a special frame that indicates that
				currentFrame->framePosition = -1;
				pthread_mutex_lock(&video->m_cacheMutex);
				BLI_addtail(&video->m_frameCacheBase, currentFrame);
				pthread_mutex_unlock(&video->m_cacheMutex);
				currentFrame = NULL;
				// no need to stay any longer in this thread
				break;
			}
		}
		// small sleep to avoid unnecessary looping
		PIL_sleep_ms(10);
	}
	// before quitting, put back the current frame to queue to allow freeing
	if (currentFrame)
	{
		pthread_mutex_lock(&video->m_cacheMutex);
		BLI_addtail(&video->m_frameCacheFree, currentFrame);
		pthread_mutex_unlock(&video->m_cacheMutex);
	}
	return 0;
}
Beispiel #9
0
/* only this runs inside thread */
static void screenshot_startjob(void *sjv, short *stop, short *do_update, float *UNUSED(progress))
{
    ScreenshotJob *sj = sjv;
    RenderData rd = sj->scene->r;
    bMovieHandle *mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype);

    /* we need this as local variables for renderdata */
    rd.frs_sec = U.scrcastfps;
    rd.frs_sec_base = 1.0f;

    if (BKE_imtype_is_movie(rd.im_format.imtype)) {
        if (!mh->start_movie(sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports)) {
            printf("screencast job stopped\n");
            return;
        }
    }
    else
        mh = NULL;

    sj->stop = stop;
    sj->do_update = do_update;

    *do_update = true; /* wait for opengl rect */

    while (*stop == 0) {

        if (sj->dumprect) {

            if (mh) {
                if (mh->append_movie(&rd, rd.sfra, rd.cfra, (int *)sj->dumprect,
                                     sj->dumpsx, sj->dumpsy, &sj->reports))
                {
                    BKE_reportf(&sj->reports, RPT_INFO, "Appended frame: %d", rd.cfra);
                    printf("Appended frame %d\n", rd.cfra);
                }
                else {
                    break;
                }
            }
            else {
                ImBuf *ibuf = IMB_allocImBuf(sj->dumpsx, sj->dumpsy, rd.im_format.planes, 0);
                char name[FILE_MAX];
                int ok;

                BKE_makepicstring(name, rd.pic, sj->bmain->name, rd.cfra,
                                  &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true);

                ibuf->rect = sj->dumprect;
                ok = BKE_imbuf_write(ibuf, name, &rd.im_format);

                if (ok == 0) {
                    printf("Write error: cannot save %s\n", name);
                    BKE_reportf(&sj->reports, RPT_INFO, "Write error: cannot save %s", name);
                    break;
                }
                else {
                    printf("Saved file: %s\n", name);
                    BKE_reportf(&sj->reports, RPT_INFO, "Saved file: %s", name);
                }

                /* imbuf knows which rects are not part of ibuf */
                IMB_freeImBuf(ibuf);
            }

            MEM_freeN(sj->dumprect);
            sj->dumprect = NULL;

            *do_update = true;

            rd.cfra++;

        }
        else
            PIL_sleep_ms(U.scrcastwait);
    }

    if (mh)
        mh->end_movie();

    BKE_report(&sj->reports, RPT_INFO, "Screencast job stopped");
}
Beispiel #10
0
/* returns 0 if nothing was handled */
int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress)
{
	BakeShade *handles;
	ListBase threads;
	Image *ima;
	int a, vdone = false, result = BAKE_RESULT_OK;
	bool use_mask = false;
	bool use_displacement_buffer = false;
	
	re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene);
	
	/* initialize render global */
	R = *re;
	R.bakebuf = NULL;

	/* initialize static vars */
	get_next_bake_face(NULL);
	
	/* do we need a mask? */
	if (re->r.bake_filter)
		use_mask = true;

	/* do we need buffer to store displacements  */
	if (ELEM(type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
		if (((R.r.bake_flag & R_BAKE_NORMALIZE) && R.r.bake_maxdist == 0.0f) ||
		    (type == RE_BAKE_DERIVATIVE))
		{
			use_displacement_buffer = true;
			use_mask = true;
		}
	}

	/* baker uses this flag to detect if image was initialized */
	if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
		for (ima = G.main->image.first; ima; ima = ima->id.next) {
			ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL, IMA_IBUF_IMA);
			ima->id.flag |= LIB_DOIT;
			ima->flag &= ~IMA_USED_FOR_RENDER;
			if (ibuf) {
				ibuf->userdata = NULL; /* use for masking if needed */
			}
			BKE_image_release_ibuf(ima, ibuf, NULL);
		}
	}

	if (R.r.bake_flag & R_BAKE_VCOL) {
		/* untag all meshes */
		tag_main_lb(&G.main->mesh, false);
	}

	BLI_init_threads(&threads, do_bake_thread, re->r.threads);

	handles = MEM_callocN(sizeof(BakeShade) * re->r.threads, "BakeShade");

	/* get the threads running */
	for (a = 0; a < re->r.threads; a++) {
		/* set defaults in handles */
		handles[a].ssamp.shi[0].lay = re->lay;

		if (type == RE_BAKE_SHADOW) {
			handles[a].ssamp.shi[0].passflag = SCE_PASS_SHADOW;
		}
		else {
			handles[a].ssamp.shi[0].passflag = SCE_PASS_COMBINED;
		}
		handles[a].ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC);
		handles[a].ssamp.shi[0].thread = a;
		handles[a].ssamp.tot = 1;

		handles[a].type = type;
		handles[a].actob = actob;
		if (R.r.bake_flag & R_BAKE_VCOL)
			handles[a].zspan = NULL;
		else
			handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake");
		
		handles[a].use_mask = use_mask;
		handles[a].use_displacement_buffer = use_displacement_buffer;

		handles[a].do_update = do_update; /* use to tell the view to update */
		
		handles[a].displacement_min = FLT_MAX;
		handles[a].displacement_max = -FLT_MAX;

		BLI_insert_thread(&threads, &handles[a]);
	}
	
	/* wait for everything to be done */
	a = 0;
	while (a != re->r.threads) {
		PIL_sleep_ms(50);

		/* calculate progress */
		for (vdone = false, a = 0; a < re->r.threads; a++)
			vdone += handles[a].vdone;
		if (progress)
			*progress = (float)(vdone / (float)re->totvlak);

		for (a = 0; a < re->r.threads; a++) {
			if (handles[a].ready == false) {
				break;
			}
		}
	}

	/* filter and refresh images */
	if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
		float displacement_min = FLT_MAX, displacement_max = -FLT_MAX;

		if (use_displacement_buffer) {
			for (a = 0; a < re->r.threads; a++) {
				displacement_min = min_ff(displacement_min, handles[a].displacement_min);
				displacement_max = max_ff(displacement_max, handles[a].displacement_max);
			}
		}

		for (ima = G.main->image.first; ima; ima = ima->id.next) {
			if ((ima->id.flag & LIB_DOIT) == 0) {
				ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL, IMA_IBUF_IMA);
				BakeImBufuserData *userdata;

				if (ima->flag & IMA_USED_FOR_RENDER)
					result = BAKE_RESULT_FEEDBACK_LOOP;

				if (!ibuf)
					continue;

				userdata = (BakeImBufuserData *)ibuf->userdata;
				if (userdata) {
					if (use_displacement_buffer) {
						if (type == RE_BAKE_DERIVATIVE) {
							float user_scale = (R.r.bake_flag & R_BAKE_USERSCALE) ? R.r.bake_user_scale : -1.0f;
							RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
							                        displacement_min, displacement_max, user_scale);
						}
						else {
							RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
							                                    displacement_min, displacement_max);
						}
					}

					RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter);
				}

				ibuf->userflags |= IB_BITMAPDIRTY;
				BKE_image_release_ibuf(ima, ibuf, NULL);
			}
		}

		/* calculate return value */
		for (a = 0; a < re->r.threads; a++) {
			zbuf_free_span(handles[a].zspan);
			MEM_freeN(handles[a].zspan);
		}
	}

	MEM_freeN(handles);
	
	BLI_end_threads(&threads);

	if (vdone == 0) {
		result = BAKE_RESULT_NO_OBJECTS;
	}

	return result;
}
Beispiel #11
0
int fluidsimBake(bContext *C, ReportList *reports, Object *ob)
{
	Scene *scene= CTX_data_scene(C);
	FILE *fileCfg;
	int i;
	Object *fsDomain = NULL;
	FluidsimSettings *domainSettings;
	Object *obit = NULL; /* object iterator */
	Base *base;
	int origFrame = scene->r.cfra;
	char debugStrBuffer[256];
	int dirExist = 0;
	int gridlevels = 0;
	int simAborted = 0; // was the simulation aborted by user?
	int  doExportOnly = 0;
	char *exportEnvStr = "BLENDER_ELBEEMEXPORTONLY";
	const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
	//char *channelNames[3] = { "translation","rotation","scale" };

	char *suffixConfig = "fluidsim.cfg";
	char *suffixSurface = "fluidsurface";
	char newSurfdataPath[FILE_MAXDIR+FILE_MAXFILE]; // modified output settings
	char targetDir[FILE_MAXDIR+FILE_MAXFILE];  // store & modify output settings
	char targetFile[FILE_MAXDIR+FILE_MAXFILE]; // temp. store filename from targetDir for access
	int  outStringsChanged = 0;             // modified? copy back before baking
	int  haveSomeFluid = 0;                 // check if any fluid objects are set

	// config vars, inited before either export or run...
	double calcViscosity = 0.0;
	int noFrames;
	double aniFrameTime;
	float aniFrlen;
	int   channelObjCount;
	float *bbStart = NULL;
	float *bbSize = NULL;
	float domainMat[4][4];
	float invDomMat[4][4];
	// channel data
	int   allchannelSize; // fixed by no. of frames
	int   startFrame = 1;  // dont use scene->r.sfra here, always start with frame 1
	// easy frame -> sim time calc
	float *timeAtFrame=NULL, *timeAtIndex=NULL;
	// domain
	float *channelDomainTime = NULL;
	float *channelDomainViscosity = NULL; 
	float *channelDomainGravity = NULL;
	// objects (currently max. 256 objs)
	float *channelObjMove[256][3]; // object movments , 0=trans, 1=rot, 2=scale
	float *channelObjInivel[256];    // initial velocities
	float *channelObjActive[256];    // obj active channel
	
	/* fluid control channels */
	float *channelAttractforceStrength[256];
	float *channelAttractforceRadius[256];
	float *channelVelocityforceStrength[256];
	float *channelVelocityforceRadius[256];
	FluidsimModifierData *fluidmd = NULL;
	Mesh *mesh = NULL;
	
	if(getenv(strEnvName)) {
		int dlevel = atoi(getenv(strEnvName));
		elbeemSetDebugLevel(dlevel);
		snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",strEnvName); 
		elbeemDebugOut(debugStrBuffer);
	}
	if(getenv(exportEnvStr)) {
		doExportOnly = atoi(getenv(exportEnvStr));
		snprintf(debugStrBuffer,256,"fluidsimBake::msg: Exporting mode set to '%d' due to envvar '%s'\n",doExportOnly, exportEnvStr); 
		elbeemDebugOut(debugStrBuffer);
	}

	// make sure it corresponds to startFrame setting
	// old: noFrames = scene->r.efra - scene->r.sfra +1;
	noFrames = scene->r.efra - 0;
	if(noFrames<=0) {
		BKE_report(reports, RPT_ERROR, "No frames to export - check your animation range settings.");
		return 0;
	}

	/* no object pointer, find in selected ones.. */
	if(!ob) {
		for(base=scene->base.first; base; base= base->next) {
			if ((base)->flag & SELECT) 
			{
				FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim);
				
				if(fluidmdtmp && (base->object->type==OB_MESH)) 
				{
					if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) 
					{
						ob = base->object;
						break;
					}
				}
			}
		}
		// no domains found?
		if(!ob) return 0;
	}
	
	channelObjCount = 0;
	for(base=scene->base.first; base; base= base->next) 
	{
		FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim);
		obit = base->object;
		if( fluidmdtmp && 
			(obit->type==OB_MESH) &&
			(fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) &&  // if has to match 3 places! // CHECKMATCH
			(fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE) ) 
		{
			channelObjCount++;
		}
	}
	
	if (channelObjCount>=255) {
		BKE_report(reports, RPT_ERROR, "Cannot bake with more then 256 objects.");
		return 0;
	}

	/* check if there's another domain... */
	for(base=scene->base.first; base; base= base->next) 
	{
		FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim);
		obit = base->object;
		if( fluidmdtmp &&(obit->type==OB_MESH)) 
		{
			if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) 
			{
				if(obit != ob) 
				{
					BKE_report(reports, RPT_ERROR, "There should be only one domain object.");
					return 0;
				}
			}
		}
	}
	
	// check if theres any fluid
	// abort baking if not...
	for(base=scene->base.first; base; base= base->next) 
	{
		FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim);
		obit = base->object;
		if( fluidmdtmp && 
			(obit->type==OB_MESH) && 
			((fluidmdtmp->fss->type == OB_FLUIDSIM_FLUID) ||
			(fluidmdtmp->fss->type == OB_FLUIDSIM_INFLOW) ))
		{
			haveSomeFluid = 1;
			break;
		}
	}
	if(!haveSomeFluid) {
		BKE_report(reports, RPT_ERROR, "No fluid objects in scene.");
		return 0;
	}
	
	/* these both have to be valid, otherwise we wouldnt be here */
	/* dont use ob here after...*/
	fsDomain = ob;
	fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
	domainSettings = fluidmd->fss;
	ob = NULL;
	mesh = fsDomain->data;
	
	// calculate bounding box
	fluid_get_bb(mesh->mvert, mesh->totvert, fsDomain->obmat, domainSettings->bbStart, domainSettings->bbSize);
	
	// reset last valid frame
	domainSettings->lastgoodframe = -1;
	
	/* rough check of settings... */
	if(domainSettings->previewresxyz > domainSettings->resolutionxyz) {
		snprintf(debugStrBuffer,256,"fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz ,  domainSettings->resolutionxyz); 
		elbeemDebugOut(debugStrBuffer);
		domainSettings->previewresxyz = domainSettings->resolutionxyz;
	}
	// set adaptive coarsening according to resolutionxyz
	// this should do as an approximation, with in/outflow
	// doing this more accurate would be overkill
	// perhaps add manual setting?
	if(domainSettings->maxRefine <0) {
		if(domainSettings->resolutionxyz>128) {
			gridlevels = 2;
		} else
		if(domainSettings->resolutionxyz>64) {
			gridlevels = 1;
		} else {
			gridlevels = 0;
		}
	} else {
		gridlevels = domainSettings->maxRefine;
	}
	snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels ); 
	elbeemDebugOut(debugStrBuffer);

	// prepare names...
	strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
	strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR);
	BLI_convertstringcode(targetDir, G.sce); // fixed #frame-no 

	strcpy(targetFile, targetDir);
	strcat(targetFile, suffixConfig);
	if(!doExportOnly) { strcat(targetFile,".tmp"); }  // dont overwrite/delete original file
	// make sure all directories exist
	// as the bobjs use the same dir, this only needs to be checked
	// for the cfg output
	BLI_make_existing_file(targetFile);

	// check selected directory
	// simply try to open cfg file for writing to test validity of settings
	fileCfg = fopen(targetFile, "w");
	if(fileCfg) { 
		dirExist = 1; fclose(fileCfg); 
		// remove cfg dummy from  directory test
		if(!doExportOnly) { BLI_delete(targetFile, 0,0); }
	}

	if((strlen(targetDir)<1) || (!dirExist)) {
		char blendDir[FILE_MAXDIR+FILE_MAXFILE], blendFile[FILE_MAXDIR+FILE_MAXFILE];
		// invalid dir, reset to current/previous
		strcpy(blendDir, G.sce);
		BLI_splitdirstring(blendDir, blendFile);
		if(strlen(blendFile)>6){
			int len = strlen(blendFile);
			if( (blendFile[len-6]=='.')&& (blendFile[len-5]=='b')&& (blendFile[len-4]=='l')&&
					(blendFile[len-3]=='e')&& (blendFile[len-2]=='n')&& (blendFile[len-1]=='d') ){
				blendFile[len-6] = '\0';
			}
		}
		// todo... strip .blend ?
		snprintf(newSurfdataPath,FILE_MAXFILE+FILE_MAXDIR,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);

		snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
		elbeemDebugOut(debugStrBuffer);
		outStringsChanged=1;
	}

	// check if modified output dir is ok
	if(outStringsChanged) {
		char dispmsg[FILE_MAXDIR+FILE_MAXFILE+256];
		int  selection=0;
		strcpy(dispmsg,"Output settings set to: '");
		strcat(dispmsg, newSurfdataPath);
		strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0");

		// ask user if thats what he/she wants...
		selection = pupmenu(dispmsg);
		if(selection<1) return 0; // 0 from menu, or -1 aborted
		strcpy(targetDir, newSurfdataPath);
		strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR);
		BLI_convertstringcode(targetDir, G.sce); // fixed #frame-no 
	}
	
	// --------------------------------------------------------------------------------------------
	// dump data for start frame 
	// CHECK more reasonable to number frames according to blender?
	// dump data for frame 0
	scene->r.cfra = startFrame;
	ED_update_for_newframe(C, 1);
	
	// init common export vars for both file export and run
	for(i=0; i<256; i++) {
		channelObjMove[i][0] = channelObjMove[i][1] = channelObjMove[i][2] = NULL;
		channelObjInivel[i] = NULL;
		channelObjActive[i] = NULL;
		channelAttractforceStrength[i] = NULL;
		channelAttractforceRadius[i] = NULL;
		channelVelocityforceStrength[i] = NULL;
		channelVelocityforceRadius[i] = NULL;
	}
	allchannelSize = scene->r.efra; // always use till last frame
	aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames;
	// blender specific - scale according to map old/new settings in anim panel:
	aniFrlen = scene->r.framelen;
	if(domainSettings->viscosityMode==1) {
		/* manual mode, visc=value/(10^-vexp) */
		calcViscosity = (1.0/pow(10.0,domainSettings->viscosityExponent)) * domainSettings->viscosityValue;
	} else {
		calcViscosity = fluidsimViscosityPreset[ domainSettings->viscosityMode ];
	}

	bbStart = domainSettings->bbStart;
	bbSize = domainSettings->bbSize;

	// always init
	{ int timeIcu[1] = { FLUIDSIM_TIME };
		float timeDef[1] = { 1. };
		int gravIcu[3] = { FLUIDSIM_GRAV_X, FLUIDSIM_GRAV_Y, FLUIDSIM_GRAV_Z };
		float gravDef[3];
		int viscIcu[1] = { FLUIDSIM_VISC };
		float viscDef[1] = { 1. };

		gravDef[0] = domainSettings->gravx;
		gravDef[1] = domainSettings->gravy;
		gravDef[2] = domainSettings->gravz;

		// time channel is a bit special, init by hand...
		timeAtIndex = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatindex");
		for(i=0; i<=scene->r.efra; i++) {
			timeAtIndex[i] = (float)(i-startFrame);
		}
		fluidsimInitChannel(scene, &channelDomainTime, allchannelSize, timeAtIndex, timeIcu,timeDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB
		// time channel is a multiplicator for aniFrameTime
		if(channelDomainTime) {
			for(i=0; i<allchannelSize; i++) { 
				channelDomainTime[i*2+0] = aniFrameTime * channelDomainTime[i*2+0]; 
				if(channelDomainTime[i*2+0]<0.) channelDomainTime[i*2+0] = 0.;
			}
		}
		timeAtFrame = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatframe");
		timeAtFrame[0] = timeAtFrame[1] = domainSettings->animStart; // start at index 1
		if(channelDomainTime) {
			for(i=2; i<=allchannelSize; i++) {
				timeAtFrame[i] = timeAtFrame[i-1]+channelDomainTime[(i-1)*2+0];
			}
		} else {
			for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+aniFrameTime; }
		}

		fluidsimInitChannel(scene, &channelDomainViscosity, allchannelSize, timeAtFrame, viscIcu,viscDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB
		if(channelDomainViscosity) {
			for(i=0; i<allchannelSize; i++) { channelDomainViscosity[i*2+0] = calcViscosity * channelDomainViscosity[i*2+0]; }
		}
		fluidsimInitChannel(scene, &channelDomainGravity, allchannelSize, timeAtFrame, gravIcu,gravDef, domainSettings->ipo, CHANNEL_VEC );
	} // domain channel init
	
	// init obj movement channels
	channelObjCount=0;
	for(base=scene->base.first; base; base= base->next) 
	{
		FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim);
		obit = base->object;
		
		if( fluidmdtmp && 
			(obit->type==OB_MESH) &&
			(fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) &&  // if has to match 3 places! // CHECKMATCH
			(fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE) ) {

			//  cant use fluidsimInitChannel for obj channels right now, due
			//  to the special DXXX channels, and the rotation specialities
			IpoCurve *icuex[3][3];
			//IpoCurve *par_icuex[3][3];
#if 0
			int icuIds[3][3] = { 
				{OB_LOC_X,  OB_LOC_Y,  OB_LOC_Z},
				{OB_ROT_X,  OB_ROT_Y,  OB_ROT_Z},
				{OB_SIZE_X, OB_SIZE_Y, OB_SIZE_Z} 
			};
			int icudIds[3][3] = { 
				{OB_DLOC_X,  OB_DLOC_Y,  OB_DLOC_Z},
				{OB_DROT_X,  OB_DROT_Y,  OB_DROT_Z},
				{OB_DSIZE_X, OB_DSIZE_Y, OB_DSIZE_Z} 
			};
#endif
			// relative ipos
			IpoCurve *icudex[3][3];
			//IpoCurve *par_icudex[3][3];
			int j,k;
			float vals[3] = {0.0,0.0,0.0}; 
			int o = channelObjCount;
			int   inivelIcu[3] =  { FLUIDSIM_VEL_X, FLUIDSIM_VEL_Y, FLUIDSIM_VEL_Z };
			float inivelDefs[3];
			int   activeIcu[1] =  { FLUIDSIM_ACTIVE };
			float activeDefs[1] = { 1 }; // default to on

			inivelDefs[0] = fluidmdtmp->fss->iniVelx;
			inivelDefs[1] = fluidmdtmp->fss->iniVely;
			inivelDefs[2] = fluidmdtmp->fss->iniVelz;

			// check & init loc,rot,size
			for(j=0; j<3; j++) {
				for(k=0; k<3; k++) {
					// XXX prevent invalid memory access until this works
					icuex[j][k]= NULL;
					icudex[j][k]= NULL;

					// XXX icuex[j][k]  = find_ipocurve(obit->ipo, icuIds[j][k] );
					// XXX icudex[j][k] = find_ipocurve(obit->ipo, icudIds[j][k] );
					// XXX lines below were already disabled!
					//if(obit->parent) {
						//par_icuex[j][k]  = find_ipocurve(obit->parent->ipo, icuIds[j][k] );
						//par_icudex[j][k] = find_ipocurve(obit->parent->ipo, icudIds[j][k] );
					//}
				}
			}

			for(j=0; j<3; j++) {
				channelObjMove[o][j] = MEM_callocN( allchannelSize*4*sizeof(float), "fluidsiminit_objmovchannel");
				for(i=1; i<=allchannelSize; i++) {

					for(k=0; k<3; k++) {
						if(icuex[j][k]) { 
							// IPO exists, use it ...
							// XXX calc_icu(icuex[j][k], aniFrlen*((float)i) );
							vals[k] = icuex[j][k]->curval; 
							if(obit->parent) {
								// add parent transform, multiply scaling, add trafo&rot
								//calc_icu(par_icuex[j][k], aniFrlen*((float)i) );
								//if(j==2) { vals[k] *= par_icuex[j][k]->curval; }
								//else { vals[k] += par_icuex[j][k]->curval; }
							}
						} else {
							// use defaults from static values
							float setval=0.0;
							if(j==0) { 
								setval = obit->loc[k];
								if(obit->parent){ setval += obit->parent->loc[k]; }
							} else if(j==1) { 
								setval = ( 180.0*obit->rot[k] )/( 10.0*M_PI );
								if(obit->parent){ setval = ( 180.0*(obit->rot[k]+obit->parent->rot[k]) )/( 10.0*M_PI ); }
							} else { 
								setval = obit->size[k]; 
								if(obit->parent){ setval *= obit->parent->size[k]; }
							}
							vals[k] = setval;
						}
						if(icudex[j][k]) { 
							// XXX calc_icu(icudex[j][k], aniFrlen*((float)i) );
							//vals[k] += icudex[j][k]->curval; 
							// add transform, multiply scaling, add trafo&rot
							if(j==2) { vals[k] *= icudex[j][k]->curval; }
							else { vals[k] += icudex[j][k]->curval; }
							if(obit->parent) {
								// add parent transform, multiply scaling, add trafo&rot
								//calc_icu(par_icuex[j][k], aniFrlen*((float)i) );
								//if(j==2) { vals[k] *= par_icudex[j][k]->curval; }
								//else { vals[k] += par_icudex[j][k]->curval; }
							}
						} 
					} // k

					for(k=0; k<3; k++) {
						float set = vals[k];
						if(j==1) { // rot is downscaled by 10 for ipo !?
							set = 360.0 - (10.0*set);
						}
						channelObjMove[o][j][(i-1)*4 + k] = set;
					} // k
					channelObjMove[o][j][(i-1)*4 + 3] = timeAtFrame[i];
				}
			}
			
			{
				int   attrFSIcu[1] =  { FLUIDSIM_ATTR_FORCE_STR };
				int   attrFRIcu[1] =  { FLUIDSIM_ATTR_FORCE_RADIUS };
				int   velFSIcu[1] =  { FLUIDSIM_VEL_FORCE_STR };
				int   velFRIcu[1] =  { FLUIDSIM_VEL_FORCE_RADIUS };

				float attrFSDefs[1];
				float attrFRDefs[1];
				float velFSDefs[1];
				float velFRDefs[1];
				
				attrFSDefs[0] = fluidmdtmp->fss->attractforceStrength;
				attrFRDefs[0] = fluidmdtmp->fss->attractforceRadius;
				velFSDefs[0] = fluidmdtmp->fss->velocityforceStrength;
				velFRDefs[0] = fluidmdtmp->fss->velocityforceRadius;
				
				fluidsimInitChannel(scene, &channelAttractforceStrength[o], allchannelSize, timeAtFrame, attrFSIcu,attrFSDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT );
				fluidsimInitChannel(scene, &channelAttractforceRadius[o], allchannelSize, timeAtFrame, attrFRIcu,attrFRDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT );
				fluidsimInitChannel(scene, &channelVelocityforceStrength[o], allchannelSize, timeAtFrame, velFSIcu,velFSDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT );
				fluidsimInitChannel(scene, &channelVelocityforceRadius[o], allchannelSize, timeAtFrame, velFRIcu,velFRDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT );
			}
			
			fluidsimInitChannel(scene, &channelObjInivel[o], allchannelSize, timeAtFrame, inivelIcu,inivelDefs, fluidmdtmp->fss->ipo, CHANNEL_VEC );
			fluidsimInitChannel(scene, &channelObjActive[o], allchannelSize, timeAtFrame, activeIcu,activeDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT );
		

			channelObjCount++;

		}
	}

	// init trafo matrix
	Mat4CpyMat4(domainMat, fsDomain->obmat);
	if(!Mat4Invert(invDomMat, domainMat)) {
		snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); 
		elbeemDebugOut(debugStrBuffer);
		BKE_report(reports, RPT_ERROR, "Invalid object matrix."); 
		// FIXME add fatal msg
		FS_FREE_CHANNELS;
		return 0;
	}

	// --------------------------------------------------------------------------------------------
	// start writing / exporting
	strcpy(targetFile, targetDir);
	strcat(targetFile, suffixConfig);
	if(!doExportOnly) { strcat(targetFile,".tmp"); }  // dont overwrite/delete original file
	// make sure these directories exist as well
	if(outStringsChanged) {
		BLI_make_existing_file(targetFile);
	}

	if(!doExportOnly) {
		ListBase threads;

		// perform simulation with El'Beem api and threads
		elbeemSimulationSettings fsset;
		elbeemResetSettings(&fsset);
		fsset.version = 1;

		// setup global settings
		for(i=0 ; i<3; i++) fsset.geoStart[i] = bbStart[i];
		for(i=0 ; i<3; i++) fsset.geoSize[i] = bbSize[i];
		
		// simulate with 50^3
		fsset.resolutionxyz = (int)domainSettings->resolutionxyz;
		fsset.previewresxyz = (int)domainSettings->previewresxyz;
		// 10cm water domain
		fsset.realsize = domainSettings->realsize;
		fsset.viscosity = calcViscosity;
		// earth gravity
		fsset.gravity[0] = domainSettings->gravx;
		fsset.gravity[1] = domainSettings->gravy;
		fsset.gravity[2] = domainSettings->gravz;
		// simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz
		fsset.animStart = domainSettings->animStart;
		fsset.aniFrameTime = aniFrameTime;
		fsset.noOfFrames = noFrames; // is otherwise subtracted in parser
		strcpy(targetFile, targetDir);
		strcat(targetFile, suffixSurface);
		// defaults for compressibility and adaptive grids
		fsset.gstar = domainSettings->gstar;
		fsset.maxRefine = domainSettings->maxRefine; // check <-> gridlevels
		fsset.generateParticles = domainSettings->generateParticles; 
		fsset.numTracerParticles = domainSettings->generateTracers; 
		fsset.surfaceSmoothing = domainSettings->surfaceSmoothing; 
		fsset.surfaceSubdivs = domainSettings->surfaceSubdivs; 
		fsset.farFieldSize = domainSettings->farFieldSize; 
		strcpy( fsset.outputPath, targetFile);

		// domain channels
		fsset.channelSizeFrameTime = 
		fsset.channelSizeViscosity = 
		fsset.channelSizeGravity =  allchannelSize;
		fsset.channelFrameTime = channelDomainTime;
		fsset.channelViscosity = channelDomainViscosity;
		fsset.channelGravity = channelDomainGravity;

		fsset.runsimCallback = &runSimulationCallback;
		fsset.runsimUserData = &fsset;

		if(     (domainSettings->typeFlags&OB_FSBND_NOSLIP))   fsset.domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
		else if((domainSettings->typeFlags&OB_FSBND_PARTSLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
		else if((domainSettings->typeFlags&OB_FSBND_FREESLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
		fsset.domainobsPartslip = domainSettings->partSlipValue;
		fsset.generateVertexVectors = (domainSettings->domainNovecgen==0);

		// init blender trafo matrix
 		// fprintf(stderr,"elbeemInit - mpTrafo:\n");
		{ int j; 
		for(i=0; i<4; i++) {
			for(j=0; j<4; j++) {
				fsset.surfaceTrafo[i*4+j] = invDomMat[j][i];
 				// fprintf(stderr,"elbeemInit - mpTrafo %d %d = %f (%d) \n", i,j, fsset.surfaceTrafo[i*4+j] , (i*4+j) );
			}
		} }

	  // init solver with settings
		elbeemInit();
		elbeemAddDomain(&fsset);
		
		// init objects
		channelObjCount = 0;
		for(base=scene->base.first; base; base= base->next) {
			FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim);
			obit = base->object;
			//{ snprintf(debugStrBuffer,256,"DEBUG object name=%s, type=%d ...\n", obit->id.name, obit->type); elbeemDebugOut(debugStrBuffer); } // DEBUG
			if( fluidmdtmp &&  // if has to match 3 places! // CHECKMATCH
				(obit->type==OB_MESH) &&
				(fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) &&
				(fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE)) 
			{
				float *verts=NULL;
				int *tris=NULL;
				int numVerts=0, numTris=0;
				int o = channelObjCount;
				int	deform = (fluidmdtmp->fss->domainNovecgen); // misused value
				// todo - use blenderInitElbeemMesh
				int modifierIndex = modifiers_indexInObject(obit, (ModifierData *)fluidmdtmp);
				
				elbeemMesh fsmesh;
				elbeemResetMesh( &fsmesh );
				fsmesh.type = fluidmdtmp->fss->type;
				// get name of object for debugging solver
				fsmesh.name = obit->id.name; 

				initElbeemMesh(scene, obit, &numVerts, &verts, &numTris, &tris, 0, modifierIndex);
				fsmesh.numVertices   = numVerts;
				fsmesh.numTriangles  = numTris;
				fsmesh.vertices      = verts;
				fsmesh.triangles     = tris;

				fsmesh.channelSizeTranslation  = 
				fsmesh.channelSizeRotation     = 
				fsmesh.channelSizeScale        = 
				fsmesh.channelSizeInitialVel   = 
				fsmesh.channelSizeActive       = allchannelSize;

				fsmesh.channelTranslation      = channelObjMove[o][0];
				fsmesh.channelRotation         = channelObjMove[o][1];
				fsmesh.channelScale            = channelObjMove[o][2];
				fsmesh.channelActive           = channelObjActive[o];
				if( (fsmesh.type == OB_FLUIDSIM_FLUID) ||
				(fsmesh.type == OB_FLUIDSIM_INFLOW)) {
					fsmesh.channelInitialVel       = channelObjInivel[o];
					fsmesh.localInivelCoords = ((fluidmdtmp->fss->typeFlags&OB_FSINFLOW_LOCALCOORD)?1:0);
				} 

				if(     (fluidmdtmp->fss->typeFlags&OB_FSBND_NOSLIP))   fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
				else if((fluidmdtmp->fss->typeFlags&OB_FSBND_PARTSLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP;
				else if((fluidmdtmp->fss->typeFlags&OB_FSBND_FREESLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP;
				fsmesh.obstaclePartslip = fluidmdtmp->fss->partSlipValue;
				fsmesh.volumeInitType = fluidmdtmp->fss->volumeInitType;
				fsmesh.obstacleImpactFactor = fluidmdtmp->fss->surfaceSmoothing; // misused value
				
				if(fsmesh.type == OB_FLUIDSIM_CONTROL)
				{
					// control fluids will get exported as whole
					deform = 1;
					
					fsmesh.cpsTimeStart = fluidmdtmp->fss->cpsTimeStart;
					fsmesh.cpsTimeEnd = fluidmdtmp->fss->cpsTimeEnd;
					fsmesh.cpsQuality = fluidmdtmp->fss->cpsQuality;
					fsmesh.obstacleType = (fluidmdtmp->fss->flag & OB_FLUIDSIM_REVERSE);
					
					fsmesh.channelSizeAttractforceRadius = 
					fsmesh.channelSizeVelocityforceStrength = 
					fsmesh.channelSizeVelocityforceRadius = 
					fsmesh.channelSizeAttractforceStrength = allchannelSize;
					
					fsmesh.channelAttractforceStrength = channelAttractforceStrength[o];
					fsmesh.channelAttractforceRadius = channelAttractforceRadius[o];
					fsmesh.channelVelocityforceStrength = channelVelocityforceStrength[o];
					fsmesh.channelVelocityforceRadius = channelVelocityforceRadius[o];
				}
				else 
				{
					// set channels to 0
					fsmesh.channelAttractforceStrength =
					fsmesh.channelAttractforceRadius = 
					fsmesh.channelVelocityforceStrength = 
					fsmesh.channelVelocityforceRadius = NULL; 
				}

				// animated meshes
				if(deform) {
					fsmesh.channelSizeVertices = allchannelSize;
					fluidsimInitMeshChannel(C, &fsmesh.channelVertices, allchannelSize, obit, numVerts, timeAtFrame, modifierIndex);
					scene->r.cfra = startFrame;
					ED_update_for_newframe(C, 1);
					// remove channels
					fsmesh.channelTranslation      = 
					fsmesh.channelRotation         = 
					fsmesh.channelScale            = NULL; 
				} 

				elbeemAddMesh(&fsmesh);

				if(verts) MEM_freeN(verts);
				if(tris) MEM_freeN(tris);
				if(fsmesh.channelVertices) MEM_freeN(fsmesh.channelVertices);
				channelObjCount++;
			} // valid mesh
		} // objects
		//domainSettings->type = OB_FLUIDSIM_DOMAIN; // enable for bake display again
		
		// set to neutral, -1 means user abort, -2 means init error
		globalBakeState = 0;
		globalBakeFrame = 0;
		BLI_init_threads(&threads, fluidsimSimulateThread, 1);
		BLI_insert_thread(&threads, targetFile);
		
		{
			int done = 0;
			float noFramesf = (float)noFrames;
			float percentdone = 0.0;
			int lastRedraw = -1;
			
			g_break= 0;
			G.afbreek= 0;	/* blender_test_break uses this global */
			
			start_progress_bar();

			while(done==0) {
				char busy_mess[80];
				
				waitcursor(1);
				
				// lukep we add progress bar as an interim mesure
				percentdone = globalBakeFrame / noFramesf;
				sprintf(busy_mess, "baking fluids %d / %d       |||", globalBakeFrame, (int) noFramesf);
				progress_bar(percentdone, busy_mess );
				
				// longer delay to prevent frequent redrawing
				PIL_sleep_ms(2000);
				
				BLI_lock_thread(LOCK_CUSTOM1);
				if(globalBakeState != 0) done = 1; // 1=ok, <0=error/abort
				BLI_unlock_thread(LOCK_CUSTOM1);

				if (!G.background) {
					g_break= blender_test_break();
					
					if(g_break)
					{
						// abort...
						BLI_lock_thread(LOCK_CUSTOM1);
						
						if(domainSettings)
							domainSettings->lastgoodframe = startFrame+globalBakeFrame;
						
						done = -1;
						globalBakeFrame = 0;
						globalBakeState = -1;
						simAborted = 1;
						BLI_unlock_thread(LOCK_CUSTOM1);
						break;
					}
				} 

				// redraw the 3D for showing progress once in a while...
				if(lastRedraw!=globalBakeFrame) {
#if 0					
					ScrArea *sa;
					scene->r.cfra = startFrame+globalBakeFrame;
					lastRedraw = globalBakeFrame;
					ED_update_for_newframe(C, 1);
					sa= G.curscreen->areabase.first;
					while(sa) {
						if(sa->spacetype == SPACE_VIEW3D) { scrarea_do_windraw(sa); }
						sa= sa->next;	
					} 
					screen_swapbuffers();
#endif
				} // redraw
			}
			end_progress_bar();
		}
		BLI_end_threads(&threads);
	} // El'Beem API init, thread creation 
	// --------------------------------------------------------------------------------------------
	else
	{ // write config file to be run with command line simulator
		BKE_report(reports, RPT_WARNING, "Config file export not supported.");
	} // config file export done!

	// --------------------------------------------------------------------------------------------
	FS_FREE_CHANNELS;

	// go back to "current" blender time
	waitcursor(0);
	
	if(globalBakeState >= 0)
	{
		if(domainSettings)
			domainSettings->lastgoodframe = startFrame+globalBakeFrame;
	}
	
	scene->r.cfra = origFrame;
	ED_update_for_newframe(C, 1);

	if(!simAborted) {
		char elbeemerr[256];

		// check if some error occurred
		if(globalBakeState==-2) {
			elbeemGetErrorString(elbeemerr);
			BKE_reportf(reports, RPT_ERROR, "Failed to initialize [Msg: %s]", elbeemerr);
			return 0;
		} // init error
	}
	
	// elbeemFree();
	return 1;
}