コード例 #1
0
// position pointer in file, position in second
AVFrame *VideoFFmpeg::grabFrame(long position)
{
	AVPacket packet;
	int frameFinished;
	int posFound = 1;
	bool frameLoaded = false;
	int64_t targetTs = 0;
	CacheFrame *frame;
	int64_t dts = 0;

	if (m_cacheStarted)
	{
		// when cache is active, we must not read the file directly
		do {
			pthread_mutex_lock(&m_cacheMutex);
			frame = (CacheFrame *)m_frameCacheBase.first;
			pthread_mutex_unlock(&m_cacheMutex);
			// no need to remove the frame from the queue: the cache thread does not touch the head, only the tail
			if (frame == NULL)
			{
				// no frame in cache, in case of file it is an abnormal situation
				if (m_isFile)
				{
					// go back to no threaded reading
					stopCache();
					break;
				}
				return NULL;
			}
			if (frame->framePosition == -1) 
			{
				// this frame mark the end of the file (only used for file)
				// leave in cache to make sure we don't miss it
				m_eof = true;
				return NULL;
			}
			// for streaming, always return the next frame, 
			// that's what grabFrame does in non cache mode anyway.
			if (m_isStreaming || frame->framePosition == position)
			{
				return frame->frame;
			}
			// for cam, skip old frames to keep image realtime.
			// There should be no risk of clock drift since it all happens on the same CPU
			if (frame->framePosition > position) 
			{
				// this can happen after rewind if the seek didn't find the first frame
				// the frame in the buffer is ahead of time, just leave it there
				return NULL;
			}
			// this frame is not useful, release it
			pthread_mutex_lock(&m_cacheMutex);
			BLI_remlink(&m_frameCacheBase, frame);
			BLI_addtail(&m_frameCacheFree, frame);
			pthread_mutex_unlock(&m_cacheMutex);
		} while (true);
	}
	double timeBase = av_q2d(m_formatCtx->streams[m_videoStream]->time_base);
	int64_t startTs = m_formatCtx->streams[m_videoStream]->start_time;
	if (startTs == AV_NOPTS_VALUE)
		startTs = 0;

	// come here when there is no cache or cache has been stopped
	// locate the frame, by seeking if necessary (seeking is only possible for files)
	if (m_isFile)
	{
		// first check if the position that we are looking for is in the preseek range
		// if so, just read the frame until we get there
		if (position > m_curPosition + 1 
			&& m_preseek 
			&& position - (m_curPosition + 1) < m_preseek) 
		{
			while (av_read_frame(m_formatCtx, &packet)>=0)
			{
				if (packet.stream_index == m_videoStream) 
				{
					avcodec_decode_video2(
						m_codecCtx, 
						m_frame, &frameFinished, 
						&packet);
					if (frameFinished)
					{
						m_curPosition = (long)((packet.dts-startTs) * (m_baseFrameRate*timeBase) + 0.5);
					}
				}
				av_free_packet(&packet);
				if (position == m_curPosition+1)
					break;
			}
		}
		// if the position is not in preseek, do a direct jump
		if (position != m_curPosition + 1) 
		{ 
			int64_t pos = (int64_t)((position - m_preseek) / (m_baseFrameRate*timeBase));

			if (pos < 0)
				pos = 0;

			pos += startTs;

			if (position <= m_curPosition || !m_eof)
			{
#if 0
				// Tried to make this work but couldn't: seeking on byte is ignored by the
				// format plugin and it will generally continue to read from last timestamp.
				// Too bad because frame seek is not always able to get the first frame
				// of the file.
				if (position <= m_preseek)
				{
					// we can safely go the beginning of the file
					if (av_seek_frame(m_formatCtx, m_videoStream, 0, AVSEEK_FLAG_BYTE) >= 0)
					{
						// binary seek does not reset the timestamp, must do it now
						av_update_cur_dts(m_formatCtx, m_formatCtx->streams[m_videoStream], startTs);
						m_curPosition = 0;
					}
				}
				else
#endif
				{
					// current position is now lost, guess a value. 
					if (av_seek_frame(m_formatCtx, m_videoStream, pos, AVSEEK_FLAG_BACKWARD) >= 0)
					{
						// current position is now lost, guess a value. 
						// It's not important because it will be set at this end of this function
						m_curPosition = position - m_preseek - 1;
					}
				}
			}
			// this is the timestamp of the frame we're looking for
			targetTs = (int64_t)(position / (m_baseFrameRate * timeBase)) + startTs;

			posFound = 0;
			avcodec_flush_buffers(m_codecCtx);
		}
	} else if (m_isThreaded)
	{
		// cache is not started but threading is possible
		// better not read the stream => make take some time, better start caching
		if (startCache())
			return NULL;
		// Abnormal!!! could not start cache, fall back on direct read
		m_isThreaded = false;
	}

	// find the correct frame, in case of streaming and no cache, it means just
	// return the next frame. This is not quite correct, may need more work
	while (av_read_frame(m_formatCtx, &packet) >= 0)
	{
		if (packet.stream_index == m_videoStream) 
		{
			if (m_isImage)
			{
				// If we're an image, we're probably not going to be here often,
				// so we don't want to deal with delayed frames from threading.
				// There might be a better way to handle this, but I'll leave that
				// for people more knowledgeable with ffmpeg than myself. We don't
				// need threading for a single image anyways.
				m_codecCtx->thread_count = 1;
			}

			avcodec_decode_video2(m_codecCtx,
				m_frame, &frameFinished,
				&packet);

			// remember dts to compute exact frame number
			dts = packet.dts;
			if (frameFinished && !posFound) 
			{
				if (dts >= targetTs)
				{
					posFound = 1;
				}
			} 

			if (frameFinished && posFound == 1) 
			{
				AVFrame * input = 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)
				{
					av_free_packet(&packet);
					break;
				}

				if (m_deinterlace) 
				{
					if (avpicture_deinterlace(
						(AVPicture*) m_frameDeinterlaced,
						(const AVPicture*) m_frame,
						m_codecCtx->pix_fmt,
						m_codecCtx->width,
						m_codecCtx->height) >= 0)
					{
						input = m_frameDeinterlaced;
					}
				}
				// convert to RGB24
				sws_scale(m_imgConvertCtx,
					input->data,
					input->linesize,
					0,
					m_codecCtx->height,
					m_frameRGB->data,
					m_frameRGB->linesize);
				av_free_packet(&packet);
				frameLoaded = true;
				break;
			}
		}
		av_free_packet(&packet);
	}
	m_eof = m_isFile && !frameLoaded;
	if (frameLoaded)
	{
		m_curPosition = (long)((dts-startTs) * (m_baseFrameRate*timeBase) + 0.5);
		if (m_isThreaded)
		{
			// normal case for file: first locate, then start cache
			if (!startCache())
			{
				// Abnormal!! could not start cache, return to non-cache mode
				m_isThreaded = false;
			}
		}
		return m_frameRGB;
	}
	return NULL;
}
コード例 #2
0
static void init_iconfile_list(struct ListBase *list)
{
	IconFile *ifile;
	struct direntry *dir;
	int totfile, i, index = 1;
	const char *icondir;

	BLI_listbase_clear(list);
	icondir = BLI_get_folder(BLENDER_DATAFILES, "icons");

	if (icondir == NULL)
		return;
	
	totfile = BLI_dir_contents(icondir, &dir);

	for (i = 0; i < totfile; i++) {
		if ((dir[i].type & S_IFREG)) {
			const char *filename = dir[i].relname;
			
			if (BLI_testextensie(filename, ".png")) {
				/* loading all icons on file start is overkill & slows startup
				 * its possible they change size after blender load anyway. */
#if 0
				int ifilex, ifiley;
				char iconfilestr[FILE_MAX + 16]; /* allow 256 chars for file+dir */
				ImBuf *bbuf = NULL;
				/* check to see if the image is the right size, continue if not */
				/* copying strings here should go ok, assuming that we never get back
				 * a complete path to file longer than 256 chars */
				BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, filename);
				bbuf = IMB_loadiffname(iconfilestr, IB_rect);

				if (bbuf) {
					ifilex = bbuf->x;
					ifiley = bbuf->y;
					IMB_freeImBuf(bbuf);
				}
				else {
					ifilex = ifiley = 0;
				}
				
				/* bad size or failed to load */
				if ((ifilex != ICON_IMAGE_W) || (ifiley != ICON_IMAGE_H)) {
					printf("icon '%s' is wrong size %dx%d\n", iconfilestr, ifilex, ifiley);
					continue;
				}
#endif          /* removed */

				/* found a potential icon file, so make an entry for it in the cache list */
				ifile = MEM_callocN(sizeof(IconFile), "IconFile");
				
				BLI_strncpy(ifile->filename, filename, sizeof(ifile->filename));
				ifile->index = index;

				BLI_addtail(list, ifile);
				
				index++;
			}
		}
	}

	BLI_free_filelist(dir, totfile);
	dir = NULL;
}
コード例 #3
0
/* if forked && mirror-edit: makes two bones with flipped names */
static int armature_extrude_exec(bContext *C, wmOperator *op)
{
	Object *obedit;
	bArmature *arm;
	EditBone *newbone, *ebone, *flipbone, *first = NULL;
	int a, totbone = 0, do_extrude;
	bool forked = RNA_boolean_get(op->ptr, "forked");

	obedit = CTX_data_edit_object(C);
	arm = obedit->data;

	/* since we allow root extrude too, we have to make sure selection is OK */
	for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
		if (EBONE_VISIBLE(arm, ebone)) {
			if (ebone->flag & BONE_ROOTSEL) {
				if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
					if (ebone->parent->flag & BONE_TIPSEL)
						ebone->flag &= ~BONE_ROOTSEL;
				}
			}
		}
	}
	
	/* Duplicate the necessary bones */
	for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) {
		if (EBONE_VISIBLE(arm, ebone)) {
			/* we extrude per definition the tip */
			do_extrude = false;
			if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
				do_extrude = true;
			}
			else if (ebone->flag & BONE_ROOTSEL) {
				/* but, a bone with parent deselected we do the root... */
				if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) {
					/* pass */
				}
				else {
					do_extrude = 2;
				}
			}
			
			if (do_extrude) {
				/* we re-use code for mirror editing... */
				flipbone = NULL;
				if (arm->flag & ARM_MIRROR_EDIT) {
					flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone);
					if (flipbone) {
						forked = 0;  // we extrude 2 different bones
						if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED))
							/* don't want this bone to be selected... */
							flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
					}
					if ((flipbone == NULL) && (forked))
						flipbone = ebone;
				}
				
				for (a = 0; a < 2; a++) {
					if (a == 1) {
						if (flipbone == NULL)
							break;
						else {
							SWAP(EditBone *, flipbone, ebone);
						}
					}
					
					totbone++;
					newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
					
					if (do_extrude == true) {
						copy_v3_v3(newbone->head, ebone->tail);
						copy_v3_v3(newbone->tail, newbone->head);
						newbone->parent = ebone;
						
						newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING);  // copies it, in case mirrored bone
						
						if (newbone->parent) newbone->flag |= BONE_CONNECTED;
					}
					else {
						copy_v3_v3(newbone->head, ebone->head);
						copy_v3_v3(newbone->tail, ebone->head);
						newbone->parent = ebone->parent;
						
						newbone->flag = BONE_TIPSEL;
						
						if (newbone->parent && (ebone->flag & BONE_CONNECTED)) {
							newbone->flag |= BONE_CONNECTED;
						}
					}
					
					newbone->weight = ebone->weight;
					newbone->dist = ebone->dist;
					newbone->xwidth = ebone->xwidth;
					newbone->zwidth = ebone->zwidth;
					newbone->ease1 = ebone->ease1;
					newbone->ease2 = ebone->ease2;
					newbone->rad_head = ebone->rad_tail; // don't copy entire bone...
					newbone->rad_tail = ebone->rad_tail;
					newbone->segments = 1;
					newbone->layer = ebone->layer;
					
					BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
					
					if (flipbone && forked) {   // only set if mirror edit
						if (strlen(newbone->name) < (MAXBONENAME - 2)) {
							if (a == 0) strcat(newbone->name, "_L");
							else strcat(newbone->name, "_R");
						}
					}
					unique_editbone_name(arm->edbo, newbone->name, NULL);
					
					/* Add the new bone to the list */
					BLI_addtail(arm->edbo, newbone);
					if (!first)
						first = newbone;
					
					/* restore ebone if we were flipping */
					if (a == 1 && flipbone)
						SWAP(EditBone *, flipbone, ebone);
				}
			}
			
			/* Deselect the old bone */
			ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
		}
	}
	/* if only one bone, make this one active */
	if (totbone == 1 && first) arm->act_edbone = first;

	if (totbone == 0) return OPERATOR_CANCELLED;

	/* Transform the endpoints */
	ED_armature_sync_selection(arm->edbo);

	WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);

	return OPERATOR_FINISHED;
}
コード例 #4
0
static void build_pict_list(PlayState *ps, char *first, int totframes, int fstep, int fontid)
{
    char *mem, filepath[FILE_MAX];
//	short val;
    PlayAnimPict *picture = NULL;
    struct ImBuf *ibuf = NULL;
    char str[32 + FILE_MAX];
    struct anim *anim;

    if (IMB_isanim(first)) {
        /* OCIO_TODO: support different input color space */
        anim = IMB_open_anim(first, IB_rect, 0, NULL);
        if (anim) {
            int pic;
            ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
            if (ibuf) {
                playanim_toscreen(ps, NULL, ibuf, fontid, fstep);
                IMB_freeImBuf(ibuf);
            }

            for (pic = 0; pic < IMB_anim_get_duration(anim, IMB_TC_NONE); pic++) {
                picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "Pict");
                picture->anim = anim;
                picture->frame = pic;
                picture->IB_flags = IB_rect;
                BLI_snprintf(str, sizeof(str), "%s : %4.d", first, pic + 1);
                picture->name = strdup(str);
                BLI_addtail(&picsbase, picture);
            }
        }
        else {
            printf("couldn't open anim %s\n", first);
        }
    }
    else {
        int count = 0;

        BLI_strncpy(filepath, first, sizeof(filepath));

        pupdate_time();
        ptottime = 1.0;

        /* O_DIRECT
         *
         * If set, all reads and writes on the resulting file descriptor will
         * be performed directly to or from the user program buffer, provided
         * appropriate size and alignment restrictions are met.  Refer to the
         * F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
         * information about how to determine the alignment constraints.
         * O_DIRECT is a Silicon Graphics extension and is only supported on
         * local EFS and XFS file systems.
         */

        while (IMB_ispic(filepath) && totframes) {
            size_t size;
            int file;

            file = open(filepath, O_BINARY | O_RDONLY, 0);
            if (file < 0) {
                /* print errno? */
                return;
            }

            picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "picture");
            if (picture == NULL) {
                printf("Not enough memory for pict struct '%s'\n", filepath);
                close(file);
                return;
            }
            size = BLI_file_descriptor_size(file);

            if (size < 1) {
                close(file);
                MEM_freeN(picture);
                return;
            }

            picture->size = size;
            picture->IB_flags = IB_rect;

            if (fromdisk == FALSE) {
                mem = (char *)MEM_mallocN(size, "build pic list");
                if (mem == NULL) {
                    printf("Couldn't get memory\n");
                    close(file);
                    MEM_freeN(picture);
                    return;
                }

                if (read(file, mem, size) != size) {
                    printf("Error while reading %s\n", filepath);
                    close(file);
                    MEM_freeN(picture);
                    MEM_freeN(mem);
                    return;
                }
            }
            else {
                mem = NULL;
            }

            picture->mem = mem;
            picture->name = strdup(filepath);
            close(file);
            BLI_addtail(&picsbase, picture);
            count++;

            pupdate_time();

            if (ptottime > 1.0) {
                /* OCIO_TODO: support different input color space */
                if (picture->mem) {
                    ibuf = IMB_ibImageFromMemory((unsigned char *)picture->mem, picture->size,
                                                 picture->IB_flags, NULL, picture->name);
                }
                else {
                    ibuf = IMB_loadiffname(picture->name, picture->IB_flags, NULL);
                }
                if (ibuf) {
                    playanim_toscreen(ps, picture, ibuf, fontid, fstep);
                    IMB_freeImBuf(ibuf);
                }
                pupdate_time();
                ptottime = 0.0;
            }

            BLI_newname(filepath, +fstep);

#if 0 // XXX25
            while (qtest()) {
                switch (qreadN(&val)) {
                case ESCKEY:
                    if (val) return;
                    break;
                }
            }
#endif
            totframes--;
        }
    }
    return;
}
コード例 #5
0
VFont *load_vfont(Main *bmain, const char *name)
{
	char filename[FILE_MAXFILE];
	VFont *vfont= NULL;
	PackedFile *pf;
	PackedFile *tpf = NULL;	
	int is_builtin;
	struct TmpFont *tmpfnt;
	
	if (strcmp(name, FO_BUILTIN_NAME)==0) {
		BLI_strncpy(filename, name, sizeof(filename));
		
		pf= get_builtin_packedfile();
		is_builtin= 1;
	}
	else {
		char dir[FILE_MAXDIR];
		
		BLI_strncpy(dir, name, sizeof(dir));
		BLI_splitdirstring(dir, filename);

		pf= newPackedFile(NULL, name, bmain->name);
		tpf= newPackedFile(NULL, name, bmain->name);
		
		is_builtin= 0;
	}

	if (pf) {
		VFontData *vfd;

		vfd= BLI_vfontdata_from_freetypefont(pf);
		if (vfd) {
			vfont = alloc_libblock(&bmain->vfont, ID_VF, filename);
			vfont->data = vfd;

			/* if there's a font name, use it for the ID name */
			if (vfd->name[0] != '\0') {
				BLI_strncpy(vfont->id.name+2, vfd->name, sizeof(vfont->id.name)-2);
			}
			BLI_strncpy(vfont->name, name, sizeof(vfont->name));

			// if autopack is on store the packedfile in de font structure
			if (!is_builtin && (G.fileflags & G_AUTOPACK)) {
				vfont->packedfile = pf;
			}
			
			// Do not add FO_BUILTIN_NAME to temporary listbase
			if (strcmp(filename, FO_BUILTIN_NAME)) {
				tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
				tmpfnt->pf= tpf;
				tmpfnt->vfont= vfont;
				BLI_addtail(&ttfdata, tmpfnt);
			}			
		}
		
		// Free the packed file
		if (!vfont || vfont->packedfile != pf) {
			freePackedFile(pf);
		}
	
		//XXX waitcursor(0);
	}
	
	return vfont;
}
コード例 #6
0
ファイル: gpencil_edit.c プロジェクト: LucaRood/Blender
/* Make copies of selected point segments in a selected stroke */
static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes)
{
	bGPDspoint *pt;
	int i;
	
	int start_idx = -1;
	
	
	/* Step through the original stroke's points:
	 * - We accumulate selected points (from start_idx to current index)
	 *   and then convert that to a new stroke
	 */
	for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
		/* searching for start, are waiting for end? */
		if (start_idx == -1) {
			/* is this the first selected point for a new island? */
			if (pt->flag & GP_SPOINT_SELECT) {
				start_idx = i;
			}
		}
		else {
			size_t len = 0;
			
			/* is this the end of current island yet?
			 * 1) Point i-1 was the last one that was selected
			 * 2) Point i is the last in the array
			 */
			if ((pt->flag & GP_SPOINT_SELECT) == 0) {
				len = i - start_idx;
			}
			else if (i == gps->totpoints - 1) {
				len = i - start_idx + 1;
			}
			//printf("copying from %d to %d = %d\n", start_idx, i, len);
		
			/* make copies of the relevant data */
			if (len) {
				bGPDstroke *gpsd;
				
				/* make a stupid copy first of the entire stroke (to get the flags too) */
				gpsd = MEM_dupallocN(gps);
				
				/* initialize triangle memory - will be calculated on next redraw */
				gpsd->triangles = NULL;
				gpsd->flag |= GP_STROKE_RECALC_CACHES;
				gpsd->tot_triangles = 0;
				
				/* now, make a new points array, and copy of the relevant parts */
				gpsd->points = MEM_callocN(sizeof(bGPDspoint) * len, "gps stroke points copy");
				memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len);
				gpsd->totpoints = len;
				
				/* add to temp buffer */
				gpsd->next = gpsd->prev = NULL;
				BLI_addtail(new_strokes, gpsd);
				
				/* cleanup + reset for next */
				start_idx = -1;
			}
		}
	}
}
コード例 #7
0
static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf)
{
	ScanFillVertLink *sc = NULL, *sc1;
	ScanFillVert *eve, *v1, *v2, *v3;
	ScanFillEdge *eed, *nexted, *ed1, *ed2, *ed3;
	int a, b, verts, maxface, totface;
	short nr, test, twoconnected = 0;

	nr = pf->nr;

	/* PRINTS */
#if 0
	verts = pf->verts;
	eve = sf_ctx->fillvertbase.first;
	while (eve) {
		printf("vert: %x co: %f %f\n", eve, eve->xy[0], eve->xy[1]);
		eve = eve->next;
	}	
	eed = sf_ctx->filledgebase.first;
	while (eed) {
		printf("edge: %x  verts: %x %x\n", eed, eed->v1, eed->v2);
		eed = eed->next;
	}
#endif

	/* STEP 0: remove zero sized edges */
	eed = sf_ctx->filledgebase.first;
	while (eed) {
		if (equals_v2v2(eed->v1->xy, eed->v2->xy)) {
			if (eed->v1->f == SF_VERT_ZERO_LEN && eed->v2->f != SF_VERT_ZERO_LEN) {
				eed->v2->f = SF_VERT_ZERO_LEN;
				eed->v2->tmp.v = eed->v1->tmp.v;
			}
			else if (eed->v2->f == SF_VERT_ZERO_LEN && eed->v1->f != SF_VERT_ZERO_LEN) {
				eed->v1->f = SF_VERT_ZERO_LEN;
				eed->v1->tmp.v = eed->v2->tmp.v;
			}
			else if (eed->v2->f == SF_VERT_ZERO_LEN && eed->v1->f == SF_VERT_ZERO_LEN) {
				eed->v1->tmp.v = eed->v2->tmp.v;
			}
			else {
				eed->v2->f = SF_VERT_ZERO_LEN;
				eed->v2->tmp.v = eed->v1;
			}
		}
		eed = eed->next;
	}

	/* STEP 1: make using FillVert and FillEdge lists a sorted
	 * ScanFillVertLink list
	 */
	sc = sf_ctx->_scdata = (ScanFillVertLink *)MEM_callocN(pf->verts * sizeof(ScanFillVertLink), "Scanfill1");
	eve = sf_ctx->fillvertbase.first;
	verts = 0;
	while (eve) {
		if (eve->poly_nr == nr) {
			if (eve->f != SF_VERT_ZERO_LEN) {
				verts++;
				eve->f = 0;  /* flag for connectedges later on */
				sc->v1 = eve;
				sc++;
			}
		}
		eve = eve->next;
	}

	qsort(sf_ctx->_scdata, verts, sizeof(ScanFillVertLink), vergscdata);

	eed = sf_ctx->filledgebase.first;
	while (eed) {
		nexted = eed->next;
		BLI_remlink(&sf_ctx->filledgebase, eed);
		/* This code is for handling zero-length edges that get
		 * collapsed in step 0. It was removed for some time to
		 * fix trunk bug #4544, so if that comes back, this code
		 * may need some work, or there will have to be a better
		 * fix to #4544. */
		if (eed->v1->f == SF_VERT_ZERO_LEN) {
			v1 = eed->v1;
			while ((eed->v1->f == SF_VERT_ZERO_LEN) && (eed->v1->tmp.v != v1) && (eed->v1 != eed->v1->tmp.v))
				eed->v1 = eed->v1->tmp.v;
		}
		if (eed->v2->f == SF_VERT_ZERO_LEN) {
			v2 = eed->v2;
			while ((eed->v2->f == SF_VERT_ZERO_LEN) && (eed->v2->tmp.v != v2) && (eed->v2 != eed->v2->tmp.v))
				eed->v2 = eed->v2->tmp.v;
		}
		if (eed->v1 != eed->v2) addedgetoscanlist(sf_ctx, eed, verts);

		eed = nexted;
	}
#if 0
	sc = scdata;
	for (a = 0; a < verts; a++) {
		printf("\nscvert: %x\n", sc->v1);
		eed = sc->first;
		while (eed) {
			printf(" ed %x %x %x\n", eed, eed->v1, eed->v2);
			eed = eed->next;
		}
		sc++;
	}
#endif


	/* STEP 2: FILL LOOP */

	if (pf->f == 0) twoconnected = 1;

	/* (temporal) security: never much more faces than vertices */
	totface = 0;
	maxface = 2 * verts;       /* 2*verts: based at a filled circle within a triangle */

	sc = sf_ctx->_scdata;
	for (a = 0; a < verts; a++) {
		/* printf("VERTEX %d %x\n",a,sc->v1); */
		ed1 = sc->first;
		while (ed1) {   /* set connectflags  */
			nexted = ed1->next;
			if (ed1->v1->h == 1 || ed1->v2->h == 1) {
				BLI_remlink((ListBase *)&(sc->first), ed1);
				BLI_addtail(&sf_ctx->filledgebase, ed1);
				if (ed1->v1->h > 1) ed1->v1->h--;
				if (ed1->v2->h > 1) ed1->v2->h--;
			}
			else ed1->v2->f = SF_VERT_UNKNOWN;

			ed1 = nexted;
		}
		while (sc->first) { /* for as long there are edges */
			ed1 = sc->first;
			ed2 = ed1->next;
			
			/* commented out... the ESC here delivers corrupted memory (and doesnt work during grab) */
			/* if (callLocalInterruptCallBack()) break; */
			if (totface > maxface) {
				/* printf("Fill error: endless loop. Escaped at vert %d,  tot: %d.\n", a, verts); */
				a = verts;
				break;
			}
			if (ed2 == 0) {
				sc->first = sc->last = NULL;
				/* printf("just 1 edge to vert\n"); */
				BLI_addtail(&sf_ctx->filledgebase, ed1);
				ed1->v2->f = 0;
				ed1->v1->h--; 
				ed1->v2->h--;
			}
			else {
				/* test rest of vertices */
				float miny;
				v1 = ed1->v2;
				v2 = ed1->v1;
				v3 = ed2->v2;
				/* this happens with a serial of overlapping edges */
				if (v1 == v2 || v2 == v3) break;
				/* printf("test verts %x %x %x\n",v1,v2,v3); */
				miny = minf(v1->xy[1], v3->xy[1]);
				/*  miny= MIN2(v1->xy[1],v3->xy[1]); */
				sc1 = sc + 1;
				test = 0;

				for (b = a + 1; b < verts; b++) {
					if (sc1->v1->f == 0) {
						if (sc1->v1->xy[1] <= miny) break;

						if (testedgeside(v1->xy, v2->xy, sc1->v1->xy))
							if (testedgeside(v2->xy, v3->xy, sc1->v1->xy))
								if (testedgeside(v3->xy, v1->xy, sc1->v1->xy)) {
									/* point in triangle */
								
									test = 1;
									break;
								}
					}
					sc1++;
				}
				if (test) {
					/* make new edge, and start over */
					/* printf("add new edge %x %x and start again\n",v2,sc1->v1); */

					ed3 = BLI_addfilledge(sf_ctx, v2, sc1->v1);
					BLI_remlink(&sf_ctx->filledgebase, ed3);
					BLI_insertlinkbefore((ListBase *)&(sc->first), ed2, ed3);
					ed3->v2->f = SF_VERT_UNKNOWN;
					ed3->f = SF_EDGE_UNKNOWN;
					ed3->v1->h++; 
					ed3->v2->h++;
				}
				else {
					/* new triangle */
					/* printf("add face %x %x %x\n",v1,v2,v3); */
					addfillface(sf_ctx, v1, v2, v3);
					totface++;
					BLI_remlink((ListBase *)&(sc->first), ed1);
					BLI_addtail(&sf_ctx->filledgebase, ed1);
					ed1->v2->f = 0;
					ed1->v1->h--; 
					ed1->v2->h--;
					/* ed2 can be removed when it's a boundary edge */
					if ((ed2->f == 0 && twoconnected) || (ed2->f == SF_EDGE_BOUNDARY)) {
						BLI_remlink((ListBase *)&(sc->first), ed2);
						BLI_addtail(&sf_ctx->filledgebase, ed2);
						ed2->v2->f = 0;
						ed2->v1->h--; 
						ed2->v2->h--;
					}

					/* new edge */
					ed3 = BLI_addfilledge(sf_ctx, v1, v3);
					BLI_remlink(&sf_ctx->filledgebase, ed3);
					ed3->f = SF_EDGE_UNKNOWN;
					ed3->v1->h++; 
					ed3->v2->h++;
					
					/* printf("add new edge %x %x\n",v1,v3); */
					sc1 = addedgetoscanlist(sf_ctx, ed3, verts);
					
					if (sc1) {  /* ed3 already exists: remove if a boundary */
						/* printf("Edge exists\n"); */
						ed3->v1->h--; 
						ed3->v2->h--;

						ed3 = sc1->first;
						while (ed3) {
							if ( (ed3->v1 == v1 && ed3->v2 == v3) || (ed3->v1 == v3 && ed3->v2 == v1) ) {
								if (twoconnected || ed3->f == SF_EDGE_BOUNDARY) {
									BLI_remlink((ListBase *)&(sc1->first), ed3);
									BLI_addtail(&sf_ctx->filledgebase, ed3);
									ed3->v1->h--; 
									ed3->v2->h--;
								}
								break;
							}
							ed3 = ed3->next;
						}
					}

				}
			}
			/* test for loose edges */
			ed1 = sc->first;
			while (ed1) {
				nexted = ed1->next;
				if (ed1->v1->h < 2 || ed1->v2->h < 2) {
					BLI_remlink((ListBase *)&(sc->first), ed1);
					BLI_addtail(&sf_ctx->filledgebase, ed1);
					if (ed1->v1->h > 1) ed1->v1->h--;
					if (ed1->v2->h > 1) ed1->v2->h--;
				}

				ed1 = nexted;
			}
		}
		sc++;
	}

	MEM_freeN(sf_ctx->_scdata);
	sf_ctx->_scdata = NULL;

	return totface;
}
コード例 #8
0
/* UNUSED, keep in case we want to copy functionality for use elsewhere */
static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
{
	Object *ob;
	Base *base;
	Curve *cu, *cu1;
	Nurb *nu;
	int do_scene_sort= 0;
	
	if (scene->id.lib) return;

	if (!(ob=OBACT)) return;
	
	if (scene->obedit) { // XXX get from context
		/* obedit_copymenu(); */
		return;
	}
	if (event==9) {
		copymenu_properties(scene, v3d, ob);
		return;
	}
	else if (event==10) {
		copymenu_logicbricks(scene, v3d, ob);
		return;
	}
	else if (event==24) {
		/* moved to object_link_modifiers */
		/* copymenu_modifiers(bmain, scene, v3d, ob); */
		return;
	}

	for (base= FIRSTBASE; base; base= base->next) {
		if (base != BASACT) {
			if (TESTBASELIB(v3d, base)) {
				base->object->recalc |= OB_RECALC_OB;
				
				if (event==1) {  /* loc */
					copy_v3_v3(base->object->loc, ob->loc);
					copy_v3_v3(base->object->dloc, ob->dloc);
				}
				else if (event==2) {  /* rot */
					copy_v3_v3(base->object->rot, ob->rot);
					copy_v3_v3(base->object->drot, ob->drot);

					copy_qt_qt(base->object->quat, ob->quat);
					copy_qt_qt(base->object->dquat, ob->dquat);
				}
				else if (event==3) {  /* size */
					copy_v3_v3(base->object->size, ob->size);
					copy_v3_v3(base->object->dscale, ob->dscale);
				}
				else if (event==4) {  /* drawtype */
					base->object->dt= ob->dt;
					base->object->dtx= ob->dtx;
					base->object->empty_drawtype= ob->empty_drawtype;
					base->object->empty_drawsize= ob->empty_drawsize;
				}
				else if (event==5) {  /* time offs */
					base->object->sf= ob->sf;
				}
				else if (event==6) {  /* dupli */
					base->object->dupon= ob->dupon;
					base->object->dupoff= ob->dupoff;
					base->object->dupsta= ob->dupsta;
					base->object->dupend= ob->dupend;
					
					base->object->transflag &= ~OB_DUPLI;
					base->object->transflag |= (ob->transflag & OB_DUPLI);

					base->object->dup_group= ob->dup_group;
					if (ob->dup_group)
						id_lib_extern(&ob->dup_group->id);
				}
				else if (event==7) {	/* mass */
					base->object->mass= ob->mass;
				}
				else if (event==8) {	/* damping */
					base->object->damping= ob->damping;
					base->object->rdamping= ob->rdamping;
				}
				else if (event==11) {	/* all physical attributes */
					base->object->gameflag = ob->gameflag;
					base->object->inertia = ob->inertia;
					base->object->formfactor = ob->formfactor;
					base->object->damping= ob->damping;
					base->object->rdamping= ob->rdamping;
					base->object->min_vel= ob->min_vel;
					base->object->max_vel= ob->max_vel;
					if (ob->gameflag & OB_BOUNDS) {
						base->object->collision_boundtype = ob->collision_boundtype;
					}
					base->object->margin= ob->margin;
					base->object->bsoft= copy_bulletsoftbody(ob->bsoft);

				}
				else if (event==17) {	/* tex space */
					copy_texture_space(base->object, ob);
				}
				else if (event==18) {	/* font settings */
					
					if (base->object->type==ob->type) {
						cu= ob->data;
						cu1= base->object->data;
						
						cu1->spacemode= cu->spacemode;
						cu1->spacing= cu->spacing;
						cu1->linedist= cu->linedist;
						cu1->shear= cu->shear;
						cu1->fsize= cu->fsize;
						cu1->xof= cu->xof;
						cu1->yof= cu->yof;
						cu1->textoncurve= cu->textoncurve;
						cu1->wordspace= cu->wordspace;
						cu1->ulpos= cu->ulpos;
						cu1->ulheight= cu->ulheight;
						if (cu1->vfont) cu1->vfont->id.us--;
						cu1->vfont= cu->vfont;
						id_us_plus((ID *)cu1->vfont);
						if (cu1->vfontb) cu1->vfontb->id.us--;
						cu1->vfontb= cu->vfontb;
						id_us_plus((ID *)cu1->vfontb);
						if (cu1->vfonti) cu1->vfonti->id.us--;
						cu1->vfonti= cu->vfonti;
						id_us_plus((ID *)cu1->vfonti);
						if (cu1->vfontbi) cu1->vfontbi->id.us--;
						cu1->vfontbi= cu->vfontbi;
						id_us_plus((ID *)cu1->vfontbi);						

						BKE_text_to_curve(bmain, scene, base->object, 0); /* needed? */

						
						BLI_strncpy(cu1->family, cu->family, sizeof(cu1->family));
						
						base->object->recalc |= OB_RECALC_DATA;
					}
				}
				else if (event==19) {	/* bevel settings */
					
					if (ELEM(base->object->type, OB_CURVE, OB_FONT)) {
						cu= ob->data;
						cu1= base->object->data;
						
						cu1->bevobj= cu->bevobj;
						cu1->taperobj= cu->taperobj;
						cu1->width= cu->width;
						cu1->bevresol= cu->bevresol;
						cu1->ext1= cu->ext1;
						cu1->ext2= cu->ext2;
						
						base->object->recalc |= OB_RECALC_DATA;
					}
				}
				else if (event==25) {	/* curve resolution */

					if (ELEM(base->object->type, OB_CURVE, OB_FONT)) {
						cu= ob->data;
						cu1= base->object->data;
						
						cu1->resolu= cu->resolu;
						cu1->resolu_ren= cu->resolu_ren;
						
						nu= cu1->nurb.first;
						
						while (nu) {
							nu->resolu= cu1->resolu;
							nu= nu->next;
						}
						
						base->object->recalc |= OB_RECALC_DATA;
					}
				}
				else if (event==21) {
					if (base->object->type==OB_MESH) {
						ModifierData *md = modifiers_findByType(ob, eModifierType_Subsurf);

						if (md) {
							ModifierData *tmd = modifiers_findByType(base->object, eModifierType_Subsurf);

							if (!tmd) {
								tmd = modifier_new(eModifierType_Subsurf);
								BLI_addtail(&base->object->modifiers, tmd);
							}

							modifier_copyData(md, tmd);
							base->object->recalc |= OB_RECALC_DATA;
						}
					}
				}
				else if (event==22) {
					/* Copy the constraint channels over */
					copy_constraints(&base->object->constraints, &ob->constraints, TRUE);
					
					do_scene_sort= 1;
				}
				else if (event==23) {
					base->object->softflag= ob->softflag;
					if (base->object->soft) sbFree(base->object->soft);
					
					base->object->soft= copy_softbody(ob->soft);

					if (!modifiers_findByType(base->object, eModifierType_Softbody)) {
						BLI_addhead(&base->object->modifiers, modifier_new(eModifierType_Softbody));
					}
				}
				else if (event==26) {
#if 0 // XXX old animation system
					copy_nlastrips(&base->object->nlastrips, &ob->nlastrips);
#endif // XXX old animation system
				}
				else if (event==27) {	/* autosmooth */
					if (base->object->type==OB_MESH) {
						Mesh *me= ob->data;
						Mesh *cme= base->object->data;
						cme->smoothresh= me->smoothresh;
						if (me->flag & ME_AUTOSMOOTH)
							cme->flag |= ME_AUTOSMOOTH;
						else
							cme->flag &= ~ME_AUTOSMOOTH;
					}
				}
				else if (event==28) { /* UV orco */
					if (ELEM(base->object->type, OB_CURVE, OB_SURF)) {
						cu= ob->data;
						cu1= base->object->data;
						
						if (cu->flag & CU_UV_ORCO)
							cu1->flag |= CU_UV_ORCO;
						else
							cu1->flag &= ~CU_UV_ORCO;
					}		
				}
				else if (event==29) { /* protected bits */
					base->object->protectflag= ob->protectflag;
				}
				else if (event==30) { /* index object */
					base->object->index= ob->index;
				}
				else if (event==31) { /* object color */
					copy_v4_v4(base->object->col, ob->col);
				}
			}
		}
	}
	
	if (do_scene_sort)
		DAG_scene_sort(bmain, scene);

	DAG_ids_flush_update(bmain, 0);
}
コード例 #9
0
static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
{
	PTCacheID *pid;
	ListBase pidlist;
	SpaceTimeCache *stc = stime->caches.first;
	const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize);
	float yoffs = 0.f;
	
	if (!(stime->cache_display & TIME_CACHE_DISPLAY) || (!ob))
		return;

	BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0);

	/* iterate over pointcaches on the active object, 
	 * add spacetimecache and vertex array for each */
	for (pid = pidlist.first; pid; pid = pid->next) {
		float col[4], *fp;
		int i, sta = pid->cache->startframe, end = pid->cache->endframe;
		int len = (end - sta + 1) * 4;

		switch (pid->type) {
			case PTCACHE_TYPE_SOFTBODY:
				if (!(stime->cache_display & TIME_CACHE_SOFTBODY)) continue;
				break;
			case PTCACHE_TYPE_PARTICLES:
				if (!(stime->cache_display & TIME_CACHE_PARTICLES)) continue;
				break;
			case PTCACHE_TYPE_CLOTH:
				if (!(stime->cache_display & TIME_CACHE_CLOTH)) continue;
				break;
			case PTCACHE_TYPE_SMOKE_DOMAIN:
			case PTCACHE_TYPE_SMOKE_HIGHRES:
				if (!(stime->cache_display & TIME_CACHE_SMOKE)) continue;
				break;
			case PTCACHE_TYPE_DYNAMICPAINT:
				if (!(stime->cache_display & TIME_CACHE_DYNAMICPAINT)) continue;
				break;
			case PTCACHE_TYPE_RIGIDBODY:
				if (!(stime->cache_display & TIME_CACHE_RIGIDBODY)) continue;
				break;
		}

		if (pid->cache->cached_frames == NULL)
			continue;

		/* make sure we have stc with correct array length */
		if (stc == NULL || MEM_allocN_len(stc->array) != len * 2 * sizeof(float)) {
			if (stc) {
				MEM_freeN(stc->array);
			}
			else {
				stc = MEM_callocN(sizeof(SpaceTimeCache), "spacetimecache");
				BLI_addtail(&stime->caches, stc);
			}

			stc->array = MEM_callocN(len * 2 * sizeof(float), "SpaceTimeCache array");
		}

		/* fill the vertex array with a quad for each cached frame */
		for (i = sta, fp = stc->array; i <= end; i++) {
			if (pid->cache->cached_frames[i - sta]) {
				fp[0] = (float)i - 0.5f;
				fp[1] = 0.0;
				fp += 2;
				
				fp[0] = (float)i - 0.5f;
				fp[1] = 1.0;
				fp += 2;
				
				fp[0] = (float)i + 0.5f;
				fp[1] = 1.0;
				fp += 2;
				
				fp[0] = (float)i + 0.5f;
				fp[1] = 0.0;
				fp += 2;
			}
		}
		
		glPushMatrix();
		glTranslatef(0.0, (float)V2D_SCROLL_HEIGHT + yoffs, 0.0);
		glScalef(1.0, cache_draw_height, 0.0);
		
		switch (pid->type) {
			case PTCACHE_TYPE_SOFTBODY:
				col[0] = 1.0;   col[1] = 0.4;   col[2] = 0.02;
				col[3] = 0.1;
				break;
			case PTCACHE_TYPE_PARTICLES:
				col[0] = 1.0;   col[1] = 0.1;   col[2] = 0.02;
				col[3] = 0.1;
				break;
			case PTCACHE_TYPE_CLOTH:
				col[0] = 0.1;   col[1] = 0.1;   col[2] = 0.75;
				col[3] = 0.1;
				break;
			case PTCACHE_TYPE_SMOKE_DOMAIN:
			case PTCACHE_TYPE_SMOKE_HIGHRES:
				col[0] = 0.2;   col[1] = 0.2;   col[2] = 0.2;
				col[3] = 0.1;
				break;
			case PTCACHE_TYPE_DYNAMICPAINT:
				col[0] = 1.0;   col[1] = 0.1;   col[2] = 0.75;
				col[3] = 0.1;
				break;
			case PTCACHE_TYPE_RIGIDBODY:
				col[0] = 1.0;   col[1] = 0.6;   col[2] = 0.0;
				col[3] = 0.1;
				break;
			default:
				col[0] = 1.0;   col[1] = 0.0;   col[2] = 1.0;
				col[3] = 0.1;
				BLI_assert(0);
				break;
		}
		glColor4fv(col);
		
		glEnable(GL_BLEND);
		
		glRectf((float)sta, 0.0, (float)end, 1.0);
		
		col[3] = 0.4f;
		if (pid->cache->flag & PTCACHE_BAKED) {
			col[0] -= 0.4f; col[1] -= 0.4f; col[2] -= 0.4f;
		}
		else if (pid->cache->flag & PTCACHE_OUTDATED) {
			col[0] += 0.4f; col[1] += 0.4f; col[2] += 0.4f;
		}
		glColor4fv(col);
		
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(2, GL_FLOAT, 0, stc->array);
		glDrawArrays(GL_QUADS, 0, (fp - stc->array) / 2);
		glDisableClientState(GL_VERTEX_ARRAY);
		
		glDisable(GL_BLEND);
		
		glPopMatrix();
		
		yoffs += cache_draw_height;

		stc = stc->next;
	}

	BLI_freelistN(&pidlist);

	/* free excessive caches */
	while (stc) {
		SpaceTimeCache *tmp = stc->next;
		BLI_remlink(&stime->caches, stc);
		MEM_freeN(stc->array);
		MEM_freeN(stc);
		stc = tmp;
	}
}
コード例 #10
0
/* Selects all visible keyframes in the same frames as the specified elements */
static void columnselect_action_keys(bAnimContext *ac, short mode)
{
	ListBase anim_data = {NULL, NULL};
	bAnimListElem *ale;
	int filter;
	
	Scene *scene = ac->scene;
	CfraElem *ce;
	KeyframeEditFunc select_cb, ok_cb;
	KeyframeEditData ked = {{NULL}};
	
	/* initialize keyframe editing data */
	
	/* build list of columns */
	switch (mode) {
		case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */
			if (ac->datatype == ANIMCONT_GPENCIL) {
				filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
				ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
				
				for (ale = anim_data.first; ale; ale = ale->next)
					ED_gplayer_make_cfra_list(ale->data, &ked.list, 1);
			}
			else {
				filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/);
				ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
				
				for (ale = anim_data.first; ale; ale = ale->next)
					ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL);
			}
			ANIM_animdata_freelist(&anim_data);
			break;
			
		case ACTKEYS_COLUMNSEL_CFRA: /* current frame */
			/* make a single CfraElem for storing this */
			ce = MEM_callocN(sizeof(CfraElem), "cfraElem");
			BLI_addtail(&ked.list, ce);
			
			ce->cfra = (float)CFRA;
			break;
			
		case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
			ED_markers_make_cfra_list(ac->markers, &ked.list, SELECT);
			break;
			
		default: /* invalid option */
			return;
	}
	
	/* set up BezTriple edit callbacks */
	select_cb = ANIM_editkeyframes_select(SELECT_ADD);
	ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME);
	
	/* loop through all of the keys and select additional keyframes
	 * based on the keys found to be selected above
	 */
	if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
		filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
	else
		filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/);
	ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
	
	for (ale = anim_data.first; ale; ale = ale->next) {
		AnimData *adt = ANIM_nla_mapping_get(ac, ale);
		
		/* loop over cfraelems (stored in the KeyframeEditData->list)
		 *	- we need to do this here, as we can apply fewer NLA-mapping conversions
		 */
		for (ce = ked.list.first; ce; ce = ce->next) {
			/* set frame for validation callback to refer to */
			if (adt)
				ked.f1 = BKE_nla_tweakedit_remap(adt, ce->cfra, NLATIME_CONVERT_UNMAP);
			else
				ked.f1 = ce->cfra;
			
			/* select elements with frame number matching cfraelem */
			if (ale->type == ANIMTYPE_GPLAYER)
				ED_gpencil_select_frame(ale->data, ce->cfra, SELECT_ADD);
			else if (ale->type == ANIMTYPE_MASKLAYER)
				ED_mask_select_frame(ale->data, ce->cfra, SELECT_ADD);
			else
				ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
		}
	}
	
	/* free elements */
	BLI_freelistN(&ked.list);
	ANIM_animdata_freelist(&anim_data);
}
コード例 #11
0
/* name can be a dynamic string */
void undo_editmode_push(bContext *C, const char *name, 
						void * (*getdata)(bContext *C),
						void (*freedata)(void *), 
						void (*to_editmode)(void *, void *),  
						void *(*from_editmode)(void *),
						int (*validate_undo)(void *, void *))
{
	UndoElem *uel;
	Object *obedit= CTX_data_edit_object(C);
	void *editdata;
	int nr;
	uintptr_t memused, totmem, maxmem;

	/* at first here was code to prevent an "original" key to be insterted twice
	   this was giving conflicts for example when mesh changed due to keys or apply */
	
	/* remove all undos after (also when curundo==NULL) */
	while(undobase.last != curundo) {
		uel= undobase.last;
		uel->freedata(uel->undodata);
		BLI_freelinkN(&undobase, uel);
	}
	
	/* make new */
	curundo= uel= MEM_callocN(sizeof(UndoElem), "undo editmode");
	strncpy(uel->name, name, MAXUNDONAME-1);
	BLI_addtail(&undobase, uel);
	
	uel->getdata= getdata;
	uel->freedata= freedata;
	uel->to_editmode= to_editmode;
	uel->from_editmode= from_editmode;
	uel->validate_undo= validate_undo;
	
	/* limit amount to the maximum amount*/
	nr= 0;
	uel= undobase.last;
	while(uel) {
		nr++;
		if(nr==U.undosteps) break;
		uel= uel->prev;
	}
	if(uel) {
		while(undobase.first!=uel) {
			UndoElem *first= undobase.first;
			first->freedata(first->undodata);
			BLI_freelinkN(&undobase, first);
		}
	}

	/* copy  */
	memused= MEM_get_memory_in_use();
	editdata= getdata(C);
	curundo->undodata= curundo->from_editmode(editdata);
	curundo->undosize= MEM_get_memory_in_use() - memused;
	curundo->ob= obedit;
	curundo->id= obedit->id;
	curundo->type= obedit->type;

	if(U.undomemory != 0) {
		/* limit to maximum memory (afterwards, we can't know in advance) */
		totmem= 0;
		maxmem= ((uintptr_t)U.undomemory)*1024*1024;

		uel= undobase.last;
		while(uel && uel->prev) {
			totmem+= uel->undosize;
			if(totmem>maxmem) break;
			uel= uel->prev;
		}

		if(uel) {
			if(uel->prev && uel->prev->prev)
				uel= uel->prev;

			while(undobase.first!=uel) {
				UndoElem *first= undobase.first;
				first->freedata(first->undodata);
				BLI_freelinkN(&undobase, first);
			}
		}
	}
}
コード例 #12
0
ファイル: editaction_gpencil.c プロジェクト: jinjoh/NOOR
void paste_gpdata (Scene *scene)
{
	ListBase act_data = {NULL, NULL};
	bActListElem *ale;
	int filter;
	void *data;
	short datatype;
	
	const int offset = (CFRA - gpcopy_firstframe);
	short no_name= 0;
	
	/* check if buffer is empty */
	if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last)) {
		error("No data in buffer to paste");
		return;
	}
	/* check if single channel in buffer (disregard names if so)  */
	if (gpcopybuf.first == gpcopybuf.last)
		no_name= 1;
	
	/* get data */
	data= get_action_context(&datatype);
	if (data == NULL) return;
	if (datatype != ACTCONT_GPENCIL) return;
	
	/* filter data */
	filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT);
	actdata_filter(&act_data, filter, data, datatype);
	
	/* from selected channels */
	for (ale= act_data.first; ale; ale= ale->next) {
		bGPDlayer *gpld= (bGPDlayer *)ale->data;
		bGPDlayer *gpls= NULL;
		bGPDframe *gpfs, *gpf;
		
		/* find suitable layer from buffer to use to paste from */
		for (gpls= gpcopybuf.first; gpls; gpls= gpls->next) {
			/* check if layer name matches */
			if ((no_name) || (strcmp(gpls->info, gpld->info)==0))
				break;
		}
		
		/* this situation might occur! */
		if (gpls == NULL)
			continue;
		
		/* add frames from buffer */
		for (gpfs= gpls->frames.first; gpfs; gpfs= gpfs->next) {
			/* temporarily apply offset to buffer-frame while copying */
			gpfs->framenum += offset;
			
			/* get frame to copy data into (if no frame returned, then just ignore) */
			gpf= gpencil_layer_getframe(gpld, gpfs->framenum, 1);
			if (gpf) {
				bGPDstroke *gps, *gpsn;
				ScrArea *sa;
				
				/* get area that gp-data comes from */
				//sa= gpencil_data_findowner((bGPdata *)ale->owner);	
				sa = NULL;
				
				/* this should be the right frame... as it may be a pre-existing frame, 
				 * must make sure that only compatible stroke types get copied over 
				 *	- we cannot just add a duplicate frame, as that would cause errors
				 *	- need to check for compatible types to minimise memory usage (copying 'junk' over)
				 */
				for (gps= gpfs->strokes.first; gps; gps= gps->next) {
					short stroke_ok;
					
					/* if there's an area, check that it supports this type of stroke */
					if (sa) {
						stroke_ok= 0;
						
						/* check if spacetype supports this type of stroke
						 *	- NOTE: must sync this with gp_paint_initstroke() in gpencil.c
						 */
						switch (sa->spacetype) {
							case SPACE_VIEW3D: /* 3D-View: either screen-aligned or 3d-space */
								if ((gps->flag == 0) || (gps->flag & GP_STROKE_3DSPACE))
									stroke_ok= 1;
								break;
								
							case SPACE_NODE: /* Nodes Editor: either screen-aligned or view-aligned */
							case SPACE_IMAGE: /* Image Editor: either screen-aligned or view\image-aligned */
								if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DSPACE))
									stroke_ok= 1;
								break;
								
							case SPACE_SEQ: /* Sequence Editor: either screen-aligned or view-aligned */
								if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DIMAGE))
									stroke_ok= 1;
								break;
						}
					}
					else
						stroke_ok= 1;
					
					/* if stroke is ok, we make a copy of this stroke and add to frame */
					if (stroke_ok) {
						/* make a copy of stroke, then of its points array */
						gpsn= MEM_dupallocN(gps);
						gpsn->points= MEM_dupallocN(gps->points);
						
						/* append stroke to frame */
						BLI_addtail(&gpf->strokes, gpsn);
					}
				}
				
				/* if no strokes (i.e. new frame) added, free gpf */
				if (gpf->strokes.first == NULL)
					gpencil_layer_delframe(gpld, gpf);
			}
			
			/* unapply offset from buffer-frame */
			gpfs->framenum -= offset;
		}
	}
	
	/* free temp memory */
	BLI_freelistN(&act_data);
	
	/* undo and redraw stuff */
	BIF_undo_push("Paste Grease Pencil Frames");
}
コード例 #13
0
static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
{
	Object *obedit = CTX_data_edit_object(C);
	ListBase *editnurb;
	Nurb *nu;
	bool newob = false;
	bool enter_editmode;
	unsigned int layer;
	float dia;
	float loc[3], rot[3];
	float mat[4][4];

	WM_operator_view3d_unit_defaults(C, op);

	if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
		return OPERATOR_CANCELLED;

	if (!isSurf) { /* adding curve */
		if (obedit == NULL || obedit->type != OB_CURVE) {
			Curve *cu;

			obedit = ED_object_add_type(C, OB_CURVE, loc, rot, true, layer);
			newob = true;

			cu = (Curve *)obedit->data;
			cu->flag |= CU_DEFORM_FILL;

			if (type & CU_PRIM_PATH)
				cu->flag |= CU_PATH | CU_3D;
		}
		else {
			DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
		}
	}
	else { /* adding surface */
		if (obedit == NULL || obedit->type != OB_SURF) {
			obedit = ED_object_add_type(C, OB_SURF, loc, rot, true, layer);
			newob = true;
		}
		else {
			DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
		}
	}

	/* rename here, the undo stack checks name for valid undo pushes */
	if (newob) {
		if (obedit->type == OB_CURVE) {
			rename_id((ID *)obedit, get_curve_defname(type));
			rename_id((ID *)obedit->data, get_curve_defname(type));
		}
		else {
			rename_id((ID *)obedit, get_surf_defname(type));
			rename_id((ID *)obedit->data, get_surf_defname(type));
		}
	}

	/* ED_object_add_type doesnt do an undo, is needed for redo operator on primitive */
	if (newob && enter_editmode)
		ED_undo_push(C, "Enter Editmode");

	ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
	dia = RNA_float_get(op->ptr, "radius");
	mul_mat3_m4_fl(mat, dia);

	nu = add_nurbs_primitive(C, obedit, mat, type, newob);
	editnurb = object_editcurve_get(obedit);
	BLI_addtail(editnurb, nu);

	/* userdef */
	if (newob && !enter_editmode) {
		ED_object_editmode_exit(C, EM_FREEDATA);
	}

	WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);

	return OPERATOR_FINISHED;
}
コード例 #14
0
Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type, int newob)
{
	static int xzproj = 0;   /* this function calls itself... */
	ListBase *editnurb = object_editcurve_get(obedit);
	RegionView3D *rv3d = ED_view3d_context_rv3d(C);
	Nurb *nu = NULL;
	BezTriple *bezt;
	BPoint *bp;
	Curve *cu = (Curve *)obedit->data;
	float vec[3], zvec[3] = {0.0f, 0.0f, 1.0f};
	float umat[4][4], viewmat[4][4];
	float fac;
	int a, b;
	const float grid = 1.0f;
	const int cutype = (type & CU_TYPE); // poly, bezier, nurbs, etc
	const int stype = (type & CU_PRIMITIVE);
	const int force_3d = ((Curve *)obedit->data)->flag & CU_3D; /* could be adding to an existing 3D curve */

	unit_m4(umat);
	unit_m4(viewmat);

	if (rv3d) {
		copy_m4_m4(viewmat, rv3d->viewmat);
		copy_v3_v3(zvec, rv3d->viewinv[2]);
	}

	BKE_nurbList_flag_set(editnurb, 0);

	/* these types call this function to return a Nurb */
	if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) {
		nu = (Nurb *)MEM_callocN(sizeof(Nurb), "addNurbprim");
		nu->type = cutype;
		nu->resolu = cu->resolu;
		nu->resolv = cu->resolv;
	}

	switch (stype) {
		case CU_PRIM_CURVE: /* curve */
			nu->resolu = cu->resolu;
			if (cutype == CU_BEZIER) {
				if (!force_3d) nu->flag |= CU_2D;
				nu->pntsu = 2;
				nu->bezt = (BezTriple *)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1");
				bezt = nu->bezt;
				bezt->h1 = bezt->h2 = HD_ALIGN;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->radius = 1.0;

				bezt->vec[1][0] += -grid;
				bezt->vec[0][0] += -1.5f * grid;
				bezt->vec[0][1] += -0.5f * grid;
				bezt->vec[2][0] += -0.5f * grid;
				bezt->vec[2][1] +=  0.5f * grid;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);

				bezt++;
				bezt->h1 = bezt->h2 = HD_ALIGN;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->radius = bezt->weight = 1.0;

				bezt->vec[0][0] = 0;
				bezt->vec[0][1] = 0;
				bezt->vec[1][0] = grid;
				bezt->vec[1][1] = 0;
				bezt->vec[2][0] = grid * 2;
				bezt->vec[2][1] = 0;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);

				BKE_nurb_handles_calc(nu);
			}
			else {

				nu->pntsu = 4;
				nu->pntsv = 1;
				nu->orderu = 4;
				nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 4, "addNurbprim3");

				bp = nu->bp;
				for (a = 0; a < 4; a++, bp++) {
					bp->vec[3] = 1.0;
					bp->f1 = SELECT;
					bp->radius = bp->weight = 1.0;
				}

				bp = nu->bp;
				bp->vec[0] += -1.5f * grid;
				bp++;
				bp->vec[0] += -grid;
				bp->vec[1] +=  grid;
				bp++;
				bp->vec[0] += grid;
				bp->vec[1] += grid;
				bp++;
				bp->vec[0] += 1.5f * grid;

				bp = nu->bp;
				for (a = 0; a < 4; a++, bp++) mul_m4_v3(mat, bp->vec);

				if (cutype == CU_NURBS) {
					nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */
					BKE_nurb_knot_calc_u(nu);
				}

			}
			break;
		case CU_PRIM_PATH: /* 5 point path */
			nu->pntsu = 5;
			nu->pntsv = 1;
			nu->orderu = 5;
			nu->flagu = CU_NURB_ENDPOINT; /* endpoint */
			nu->resolu = cu->resolu;
			nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim3");

			bp = nu->bp;
			for (a = 0; a < 5; a++, bp++) {
				bp->vec[3] = 1.0;
				bp->f1 = SELECT;
				bp->radius = bp->weight = 1.0;
			}

			bp = nu->bp;
			bp->vec[0] += -2.0f * grid;
			bp++;
			bp->vec[0] += -grid;
			bp++; bp++;
			bp->vec[0] += grid;
			bp++;
			bp->vec[0] += 2.0f * grid;

			bp = nu->bp;
			for (a = 0; a < 5; a++, bp++) mul_m4_v3(mat, bp->vec);

			if (cutype == CU_NURBS) {
				nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */
				BKE_nurb_knot_calc_u(nu);
			}

			break;
		case CU_PRIM_CIRCLE: /* circle */
			nu->resolu = cu->resolu;

			if (cutype == CU_BEZIER) {
				if (!force_3d) nu->flag |= CU_2D;
				nu->pntsu = 4;
				nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * 4, "addNurbprim1");
				nu->flagu = CU_NURB_CYCLIC;
				bezt = nu->bezt;

				bezt->h1 = bezt->h2 = HD_AUTO;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->vec[1][0] += -grid;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);
				bezt->radius = bezt->weight = 1.0;

				bezt++;
				bezt->h1 = bezt->h2 = HD_AUTO;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->vec[1][1] += grid;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);
				bezt->radius = bezt->weight = 1.0;

				bezt++;
				bezt->h1 = bezt->h2 = HD_AUTO;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->vec[1][0] += grid;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);
				bezt->radius = bezt->weight = 1.0;

				bezt++;
				bezt->h1 = bezt->h2 = HD_AUTO;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->vec[1][1] += -grid;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);
				bezt->radius = bezt->weight = 1.0;

				BKE_nurb_handles_calc(nu);
			}
			else if (cutype == CU_NURBS) { /* nurb */
				nu->pntsu = 8;
				nu->pntsv = 1;
				nu->orderu = 4;
				nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 8, "addNurbprim6");
				nu->flagu = CU_NURB_CYCLIC;
				bp = nu->bp;

				for (a = 0; a < 8; a++) {
					bp->f1 = SELECT;
					if (xzproj == 0) {
						bp->vec[0] += nurbcircle[a][0] * grid;
						bp->vec[1] += nurbcircle[a][1] * grid;
					}
					else {
						bp->vec[0] += 0.25f * nurbcircle[a][0] * grid - 0.75f * grid;
						bp->vec[2] += 0.25f * nurbcircle[a][1] * grid;
					}
					if (a & 1) bp->vec[3] = 0.25 * M_SQRT2;
					else bp->vec[3] = 1.0;
					mul_m4_v3(mat, bp->vec);
					bp->radius = bp->weight = 1.0;

					bp++;
				}

				BKE_nurb_knot_calc_u(nu);
			}
			break;
		case CU_PRIM_PATCH: /* 4x4 patch */
			if (cutype == CU_NURBS) { /* nurb */

				nu->pntsu = 4;
				nu->pntsv = 4;
				nu->orderu = 4;
				nu->orderv = 4;
				nu->flag = CU_SMOOTH;
				nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * (4 * 4), "addNurbprim6");
				nu->flagu = 0;
				nu->flagv = 0;
				bp = nu->bp;

				for (a = 0; a < 4; a++) {
					for (b = 0; b < 4; b++) {
						bp->f1 = SELECT;
						fac = (float)a - 1.5f;
						bp->vec[0] += fac * grid;
						fac = (float)b - 1.5f;
						bp->vec[1] += fac * grid;
						if ((a == 1 || a == 2) && (b == 1 || b == 2)) {
							bp->vec[2] += grid;
						}
						mul_m4_v3(mat, bp->vec);
						bp->vec[3] = 1.0;
						bp++;
					}
				}

				BKE_nurb_knot_calc_u(nu);
				BKE_nurb_knot_calc_v(nu);
			}
			break;
		case CU_PRIM_TUBE: /* Cylinder */
			if (cutype == CU_NURBS) {
				nu = add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */
				nu->resolu = cu->resolu;
				nu->flag = CU_SMOOTH;
				BLI_addtail(editnurb, nu); /* temporal for extrude and translate */
				vec[0] = vec[1] = 0.0;
				vec[2] = -grid;

				mul_mat3_m4_v3(mat, vec);

				ed_editnurb_translate_flag(editnurb, SELECT, vec);
				ed_editnurb_extrude_flag(cu->editnurb, SELECT);
				mul_v3_fl(vec, -2.0f);
				ed_editnurb_translate_flag(editnurb, SELECT, vec);

				BLI_remlink(editnurb, nu);

				a = nu->pntsu * nu->pntsv;
				bp = nu->bp;
				while (a-- > 0) {
					bp->f1 |= SELECT;
					bp++;
				}
			}
			break;
		case CU_PRIM_SPHERE: /* sphere */
			if (cutype == CU_NURBS) {
				float tmp_cent[3] = {0.f, 0.f, 0.f};
				float tmp_vec[3] = {0.f, 0.f, 1.f};

				nu->pntsu = 5;
				nu->pntsv = 1;
				nu->orderu = 3;
				nu->resolu = cu->resolu;
				nu->resolv = cu->resolv;
				nu->flag = CU_SMOOTH;
				nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim6");
				nu->flagu = 0;
				bp = nu->bp;

				for (a = 0; a < 5; a++) {
					bp->f1 = SELECT;
					bp->vec[0] += nurbcircle[a][0] * grid;
					bp->vec[2] += nurbcircle[a][1] * grid;
					if (a & 1) bp->vec[3] = 0.5 * M_SQRT2;
					else bp->vec[3] = 1.0;
					mul_m4_v3(mat, bp->vec);
					bp++;
				}
				nu->flagu = CU_NURB_BEZIER;
				BKE_nurb_knot_calc_u(nu);

				BLI_addtail(editnurb, nu); /* temporal for spin */

				if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0)
					ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent);
				else if ((U.flag & USER_ADD_VIEWALIGNED))
					ed_editnurb_spin(viewmat, obedit, zvec, mat[3]);
				else
					ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]);

				BKE_nurb_knot_calc_v(nu);

				a = nu->pntsu * nu->pntsv;
				bp = nu->bp;
				while (a-- > 0) {
					bp->f1 |= SELECT;
					bp++;
				}
				BLI_remlink(editnurb, nu);
			}
			break;
		case CU_PRIM_DONUT: /* torus */
			if (cutype == CU_NURBS) {
				float tmp_cent[3] = {0.f, 0.f, 0.f};
				float tmp_vec[3] = {0.f, 0.f, 1.f};

				xzproj = 1;
				nu = add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */
				xzproj = 0;
				nu->resolu = cu->resolu;
				nu->resolv = cu->resolv;
				nu->flag = CU_SMOOTH;
				BLI_addtail(editnurb, nu); /* temporal for spin */

				/* same as above */
				if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0)
					ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent);
				else if ((U.flag & USER_ADD_VIEWALIGNED))
					ed_editnurb_spin(viewmat, obedit, zvec, mat[3]);
				else
					ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]);


				BLI_remlink(editnurb, nu);

				a = nu->pntsu * nu->pntsv;
				bp = nu->bp;
				while (a-- > 0) {
					bp->f1 |= SELECT;
					bp++;
				}

			}
			break;

		default: /* should never happen */
			BLI_assert(!"invalid nurbs type");
			return NULL;
	}

	BLI_assert(nu != NULL);

	if (nu) { /* should always be set */
		nu->flag |= CU_SMOOTH;
		cu->actnu = BLI_listbase_count(editnurb);
		cu->actvert = CU_ACT_NONE;

		BKE_nurb_test2D(nu);
	}

	return nu;
}
コード例 #15
0
/* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
{	
	bAnimListElem *ale;
	Scene *scene = ac->scene;
	
	/* clear buffer first */
	free_anim_copybuf();
	
	/* assume that each of these is an F-Curve */
	for (ale = anim_data->first; ale; ale = ale->next) {
		FCurve *fcu = (FCurve *)ale->key_data;
		tAnimCopybufItem *aci;
		BezTriple *bezt, *nbezt, *newbuf;
		int i;
		
		/* firstly, check if F-Curve has any selected keyframes
		 *	- skip if no selected keyframes found (so no need to create unnecessary copy-buffer data)
		 *	- this check should also eliminate any problems associated with using sample-data
		 */
		if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0)
			continue;
		
		/* init copybuf item info */
		aci = MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem");
		aci->id = ale->id;
		aci->id_type = GS(ale->id->name);
		aci->grp = fcu->grp;
		aci->rna_path = MEM_dupallocN(fcu->rna_path);
		aci->array_index = fcu->array_index;
		BLI_addtail(&animcopybuf, aci);
		
		/* add selected keyframes to buffer */
		/* TODO: currently, we resize array every time we add a new vert -
		 * this works ok as long as it is assumed only a few keys are copied */
		for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
			if (BEZSELECTED(bezt)) {
				/* add to buffer */
				newbuf = MEM_callocN(sizeof(BezTriple) * (aci->totvert + 1), "copybuf beztriple");
				
				/* assume that since we are just re-sizing the array, just copy all existing data across */
				if (aci->bezt)
					memcpy(newbuf, aci->bezt, sizeof(BezTriple) * (aci->totvert));
				
				/* copy current beztriple across too */
				nbezt = &newbuf[aci->totvert];
				*nbezt = *bezt;
				
				/* ensure copy buffer is selected so pasted keys are selected */
				BEZ_SEL(nbezt);
				
				/* free old array and set the new */
				if (aci->bezt) MEM_freeN(aci->bezt);
				aci->bezt = newbuf;
				aci->totvert++;
				
				/* check if this is the earliest frame encountered so far */
				if (bezt->vec[1][0] < animcopy_firstframe)
					animcopy_firstframe = bezt->vec[1][0];
				if (bezt->vec[1][0] > animcopy_lastframe)
					animcopy_lastframe = bezt->vec[1][0];
			}
		}
		
	}
	
	/* check if anything ended up in the buffer */
	if (ELEM(NULL, animcopybuf.first, animcopybuf.last))
		return -1;

	/* in case 'relative' paste method is used */
	animcopy_cfra = CFRA;

	/* everything went fine */
	return 0;
}
コード例 #16
0
ファイル: drivers.c プロジェクト: YasirArafath/blender-git
/* Get (or add relevant data to be able to do so) F-Curve from the driver stack, 
 * for the given Animation Data block. This assumes that all the destinations are valid.
 *	
 *	- add:	0 - don't add anything if not found, 
 *			1 - add new Driver FCurve (with keyframes for visual tweaking),
 *			2 - add new Driver FCurve (with generator, for script backwards compatibility)
 *			-1 - add new Driver FCurve without driver stuff (for pasting)
 */
FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, short add)
{
	AnimData *adt;
	FCurve *fcu;
	
	/* sanity checks */
	if (ELEM(NULL, id, rna_path))
		return NULL;
	
	/* init animdata if none available yet */
	adt = BKE_animdata_from_id(id);
	if ((adt == NULL) && (add))
		adt = BKE_id_add_animdata(id);
	if (adt == NULL) {
		/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
		return NULL;
	}
		
	/* try to find f-curve matching for this setting 
	 *	- add if not found and allowed to add one
	 *		TODO: add auto-grouping support? how this works will need to be resolved
	 */
	fcu = list_find_fcurve(&adt->drivers, rna_path, array_index);
	
	if ((fcu == NULL) && (add)) {
		/* use default settings to make a F-Curve */
		fcu = MEM_callocN(sizeof(FCurve), "FCurve");
		
		fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
		
		/* store path - make copy, and store that */
		fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
		fcu->array_index = array_index;
		
		/* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */
		if (add > 0) {
			BezTriple *bezt;
			size_t i;
			
			/* add some new driver data */
			fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
			fcu->driver->flag |= DRIVER_FLAG_SHOWDEBUG;
			
			/* F-Modifier or Keyframes? */
			// FIXME: replace these magic numbers with defines
			if (add == 2) {
				/* Python API Backwards compatibility hack:
				 * Create FModifier so that old scripts won't break
				 * for now before 2.7 series -- (September 4, 2013)
				 */
				add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
			}
			else {
				/* add 2 keyframes so that user has something to work with 
				 * - These are configured to 0,0 and 1,1 to give a 1-1 mapping
				 *   which can be easily tweaked from there.
				 */
				insert_vert_fcurve(fcu, 0.0f, 0.0f, INSERTKEY_FAST);
				insert_vert_fcurve(fcu, 1.0f, 1.0f, INSERTKEY_FAST);
				
				/* configure this curve to extrapolate */
				for (i = 0, bezt = fcu->bezt;  (i < fcu->totvert) && bezt;  i++, bezt++) {
					bezt->h1 = bezt->h2 = HD_VECT;
				}
				
				fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
				calchandles_fcurve(fcu);
			}
		}
		
		/* just add F-Curve to end of driver list */
		BLI_addtail(&adt->drivers, fcu);
	}
	
	/* return the F-Curve */
	return fcu;
}
コード例 #17
0
ファイル: render_opengl.c プロジェクト: mcgrathd/blender
static void screen_opengl_views_setup(OGLRender *oglrender)
{
	RenderResult *rr;
	RenderView *rv;
	SceneRenderView *srv;
	bool is_multiview;
	View3D *v3d = oglrender->v3d;

	RenderData *rd = &oglrender->scene->r;

	rr = RE_AcquireResultWrite(oglrender->re);

	is_multiview = screen_opengl_is_multiview(oglrender);

	if (!is_multiview) {
		/* we only have one view when multiview is off */
		rv = rr->views.first;

		if (rv == NULL) {
			rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
			BLI_addtail(&rr->views, rv);
		}

		while (rv->next) {
			RenderView *rv_del = rv->next;
			BLI_remlink(&rr->views, rv_del);

			if (rv_del->rectf)
				MEM_freeN(rv_del->rectf);

			if (rv_del->rectz)
				MEM_freeN(rv_del->rectz);

			MEM_freeN(rv_del);
		}
	}
	else {
		if (!oglrender->is_sequencer)
			RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));

		/* remove all the views that are not needed */
		rv = rr->views.last;
		while (rv) {
			srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
			if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
				if (rv->rectf == NULL)
					rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
				rv = rv->prev;
			}
			else {
				RenderView *rv_del = rv;
				rv  = rv_del->prev;

				BLI_remlink(&rr->views, rv_del);

				if (rv_del->rectf)
					MEM_freeN(rv_del->rectf);

				if (rv_del->rectz)
					MEM_freeN(rv_del->rectz);

				MEM_freeN(rv_del);
			}
		}

		/* create all the views that are needed */
		for (srv = rd->views.first; srv; srv = srv->next) {
			if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
				continue;

			rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));

			if (rv == NULL) {
				rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
				BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
				BLI_addtail(&rr->views, rv);
			}
		}
	}

	for (rv = rr->views.first; rv; rv = rv->next) {
		if (rv->rectf == NULL) {
			rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
		}
	}

	BLI_lock_thread(LOCK_DRAW_IMAGE);
	if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) {
		oglrender->ima->flag |= IMA_IS_STEREO;
	}
	else {
		oglrender->ima->flag &= ~IMA_IS_STEREO;
		oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
	}
	BLI_unlock_thread(LOCK_DRAW_IMAGE);

	RE_ReleaseResult(oglrender->re);
}
コード例 #18
0
/* reading without uifont will create one */
void uiStyleInit(void)
{
	uiFont *font;
	uiStyle *style = U.uistyles.first;
	int monofont_size = datatoc_bmonofont_ttf_size;
	unsigned char *monofont_ttf = (unsigned char *)datatoc_bmonofont_ttf;

	/* recover from uninitialized dpi */
	if (U.dpi == 0)
		U.dpi = 72;
	CLAMP(U.dpi, 48, 144);

	for (font = U.uifonts.first; font; font = font->next) {
		BLF_unload_id(font->blf_id);
	}

	if (blf_mono_font != -1) {
		BLF_unload_id(blf_mono_font);
		blf_mono_font = -1;
	}

	if (blf_mono_font_render != -1) {
		BLF_unload_id(blf_mono_font_render);
		blf_mono_font_render = -1;
	}

	font = U.uifonts.first;

	/* default builtin */
	if (font == NULL) {
		font = MEM_callocN(sizeof(uiFont), "ui font");
		BLI_addtail(&U.uifonts, font);
	}

	if (U.font_path_ui[0]) {
		BLI_strncpy(font->filename, U.font_path_ui, sizeof(font->filename));
		font->uifont_id = UIFONT_CUSTOM1;
	}
	else {
		BLI_strncpy(font->filename, "default", sizeof(font->filename));
		font->uifont_id = UIFONT_DEFAULT;
	}

	for (font = U.uifonts.first; font; font = font->next) {

		if (font->uifont_id == UIFONT_DEFAULT) {
#ifdef WITH_INTERNATIONAL
			int font_size = datatoc_bfont_ttf_size;
			unsigned char *font_ttf = (unsigned char *)datatoc_bfont_ttf;
			static int last_font_size = 0;

			/* use unicode font for translation */
			if (U.transopts & USER_DOTRANSLATE) {
				font_ttf = BLF_get_unifont(&font_size);

				if (!font_ttf) {
					/* fall back if not found */
					font_size = datatoc_bfont_ttf_size;
					font_ttf = (unsigned char *)datatoc_bfont_ttf;
				}
			}

			/* relload only if needed */
			if (last_font_size != font_size) {
				BLF_unload("default");
				last_font_size = font_size;
			}

			font->blf_id = BLF_load_mem("default", font_ttf, font_size);
#else
			font->blf_id = BLF_load_mem("default", (unsigned char *)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
#endif
		}
		else {
			font->blf_id = BLF_load(font->filename);
			if (font->blf_id == -1) {
				font->blf_id = BLF_load_mem("default", (unsigned char *)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
			}
		}

		BLF_default_set(font->blf_id);

		if (font->blf_id == -1) {
			if (G.debug & G_DEBUG)
				printf("%s: error, no fonts available\n", __func__);
		}
		else {
			/* ? just for speed to initialize?
			 * Yes, this build the glyph cache and create
			 * the texture.
			 */
			BLF_size(font->blf_id, 11 * U.pixelsize, U.dpi);
			BLF_size(font->blf_id, 12 * U.pixelsize, U.dpi);
			BLF_size(font->blf_id, 14 * U.pixelsize, U.dpi);
		}
	}

	if (style == NULL) {
		ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT);
	}

#ifdef WITH_INTERNATIONAL
	/* use unicode font for text editor and interactive console */
	if (U.transopts & USER_DOTRANSLATE) {
		monofont_ttf = BLF_get_unifont_mono(&monofont_size);

		if (!monofont_ttf) {
			/* fall back if not found */
			monofont_size = datatoc_bmonofont_ttf_size;
			monofont_ttf = (unsigned char *)datatoc_bmonofont_ttf;
		}
	}
#endif

	/* XXX, this should be moved into a style, but for now best only load the monospaced font once. */
	BLI_assert(blf_mono_font == -1);
	if (U.font_path_ui_mono[0]) {
		blf_mono_font = BLF_load_unique(U.font_path_ui_mono);
	}
	if (blf_mono_font == -1) {
		blf_mono_font = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size);
	}

	BLF_size(blf_mono_font, 12 * U.pixelsize, 72);

	/* Set default flags based on UI preferences (not render fonts) */
	{
		int flag_disable = BLF_MONOCHROME |
		                   BLF_HINTING_NONE |
		                   BLF_HINTING_SLIGHT |
		                   BLF_HINTING_FULL;
		int flag_enable = 0;

		if (U.text_render & USER_TEXT_HINTING_NONE) {
			flag_enable |= BLF_HINTING_NONE;
		}
		else if (U.text_render & USER_TEXT_HINTING_SLIGHT) {
			flag_enable |= BLF_HINTING_SLIGHT;
		}
		else if (U.text_render & USER_TEXT_HINTING_FULL) {
			flag_enable |= BLF_HINTING_FULL;
		}

		if (U.text_render & USER_TEXT_DISABLE_AA) {
			flag_enable |= BLF_MONOCHROME;
		}

		for (font = U.uifonts.first; font; font = font->next) {
			if (font->blf_id != -1) {
				BLF_disable(font->blf_id, flag_disable);
				BLF_enable(font->blf_id, flag_enable);
			}
		}
		if (blf_mono_font != -1) {
			BLF_disable(blf_mono_font, flag_disable);
			BLF_enable(blf_mono_font, flag_enable);
		}
	}

	/**
	 * Second for rendering else we get threading problems,
	 *
	 * \note This isn't good that the render font depends on the preferences,
	 * keep for now though, since without this there is no way to display many unicode chars.
	 */
	if (blf_mono_font_render == -1)
		blf_mono_font_render = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size);

	BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72);
}
コード例 #19
0
ファイル: gpencil_edit.c プロジェクト: LucaRood/Blender
static int gp_duplicate_exec(bContext *C, wmOperator *op)
{
	bGPdata *gpd = ED_gpencil_data_get_active(C);
	
	if (gpd == NULL) {
		BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
		return OPERATOR_CANCELLED;
	}
	
	/* for each visible (and editable) layer's selected strokes,
	 * copy the strokes into a temporary buffer, then append
	 * once all done
	 */
	CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
	{
		ListBase new_strokes = {NULL, NULL};
		bGPDframe *gpf = gpl->actframe;
		bGPDstroke *gps;
		
		if (gpf == NULL)
			continue;
		
		/* make copies of selected strokes, and deselect these once we're done */
		for (gps = gpf->strokes.first; gps; gps = gps->next) {
			/* skip strokes that are invalid for current view */
			if (ED_gpencil_stroke_can_use(C, gps) == false)
				continue;
			
			if (gps->flag & GP_STROKE_SELECT) {
				if (gps->totpoints == 1) {
					/* Special Case: If there's just a single point in this stroke... */
					bGPDstroke *gpsd;
					
					/* make direct copies of the stroke and its points */
					gpsd = MEM_dupallocN(gps);
					gpsd->points = MEM_dupallocN(gps->points);
					
					/* triangle information - will be calculated on next redraw */
					gpsd->flag |= GP_STROKE_RECALC_CACHES;
					gpsd->triangles = NULL;
					
					/* add to temp buffer */
					gpsd->next = gpsd->prev = NULL;
					BLI_addtail(&new_strokes, gpsd);
				}
				else {
					/* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
					gp_duplicate_points(gps, &new_strokes);
				}
				
				/* deselect original stroke, or else the originals get moved too
				 * (when using the copy + move macro)
				 */
				gps->flag &= ~GP_STROKE_SELECT;
			}
		}
		
		/* add all new strokes in temp buffer to the frame (preventing double-copies) */
		BLI_movelisttolist(&gpf->strokes, &new_strokes);
		BLI_assert(new_strokes.first == NULL);
	}
コード例 #20
0
BLI_mempool *BLI_mempool_create(int esize, int totelem, int pchunk, int flag)
{
	BLI_mempool *pool = NULL;
	BLI_freenode *lasttail = NULL, *curnode = NULL;
	int i, j, maxchunks;
	char *addr;

	/* allocate the pool structure */
	if (flag & BLI_MEMPOOL_SYSMALLOC) {
		pool = malloc(sizeof(BLI_mempool));
	}
	else {
		pool = MEM_mallocN(sizeof(BLI_mempool), "memory pool");
	}

	/* set the elem size */
	if (esize < MEMPOOL_ELEM_SIZE_MIN) {
		esize = MEMPOOL_ELEM_SIZE_MIN;
	}

	if (flag & BLI_MEMPOOL_ALLOW_ITER) {
		pool->esize = MAX2(esize, (int)sizeof(BLI_freenode));
	}
	else {
		pool->esize = esize;
	}

	pool->flag = flag;
	pool->pchunk = pchunk;
	pool->csize = esize * pchunk;
	pool->chunks.first = pool->chunks.last = NULL;
	pool->totalloc = 0;
	pool->totused = 0;

	maxchunks = totelem / pchunk + 1;
	if (maxchunks == 0) {
		maxchunks = 1;
	}

	/* allocate the actual chunks */
	for (i = 0; i < maxchunks; i++) {
		BLI_mempool_chunk *mpchunk;

		if (flag & BLI_MEMPOOL_SYSMALLOC) {
			mpchunk = malloc(sizeof(BLI_mempool_chunk));
			mpchunk->data = malloc((size_t)pool->csize);
		}
		else {
			mpchunk = MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk");
			mpchunk->data = MEM_mallocN((size_t)pool->csize, "BLI Mempool Chunk Data");
		}

		mpchunk->next = mpchunk->prev = NULL;
		BLI_addtail(&(pool->chunks), mpchunk);

		if (i == 0) {
			pool->free = mpchunk->data; /* start of the list */
			if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) {
				pool->free->freeword = FREEWORD;
			}
		}

		/* loop through the allocated data, building the pointer structures */
		for (addr = mpchunk->data, j = 0; j < pool->pchunk; j++) {
			curnode = ((BLI_freenode *)addr);
			addr += pool->esize;
			curnode->next = (BLI_freenode *)addr;
			if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) {
				if (j != pool->pchunk - 1)
					curnode->next->freeword = FREEWORD;
				curnode->freeword = FREEWORD;
			}
		}
		/* final pointer in the previously allocated chunk is wrong */
		if (lasttail) {
			lasttail->next = mpchunk->data;
			if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) {
				lasttail->freeword = FREEWORD;
			}
		}

		/* set the end of this chunks memory to the new tail for next iteration */
		lasttail = curnode;
#ifdef USE_TOTALLOC
		pool->totalloc += pool->pchunk;
#endif
	}
	/* terminate the list */
	curnode->next = NULL;
	return pool;
}
コード例 #21
0
ファイル: blender_undo.c プロジェクト: mgschwan/blensor
/* name can be a dynamic string */
void BKE_undo_write(bContext *C, const char *name)
{
	int nr /*, success */ /* UNUSED */;
	UndoElem *uel;

	if ((U.uiflag & USER_GLOBALUNDO) == 0) {
		return;
	}

	if (U.undosteps == 0) {
		return;
	}

	/* remove all undos after (also when curundo == NULL) */
	while (undobase.last != curundo) {
		uel = undobase.last;
		BLI_remlink(&undobase, uel);
		BLO_memfile_free(&uel->memfile);
		MEM_freeN(uel);
	}

	/* make new */
	curundo = uel = MEM_callocN(sizeof(UndoElem), "undo file");
	BLI_strncpy(uel->name, name, sizeof(uel->name));
	BLI_addtail(&undobase, uel);

	/* and limit amount to the maximum */
	nr = 0;
	uel = undobase.last;
	while (uel) {
		nr++;
		if (nr == U.undosteps) break;
		uel = uel->prev;
	}
	if (uel) {
		while (undobase.first != uel) {
			UndoElem *first = undobase.first;
			BLI_remlink(&undobase, first);
			/* the merge is because of compression */
			BLO_memfile_merge(&first->memfile, &first->next->memfile);
			MEM_freeN(first);
		}
	}


	/* disk save version */
	if (UNDO_DISK) {
		static int counter = 0;
		char filename[FILE_MAX];
		char numstr[32];
		int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */

		/* Calculate current filename. */
		counter++;
		counter = counter % U.undosteps;

		BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
		BLI_make_file_string("/", filename, BKE_tempdir_session(), numstr);

		/* success = */ /* UNUSED */ BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL);

		BLI_strncpy(curundo->filename, filename, sizeof(curundo->filename));
	}
	else {
		MemFile *prevfile = NULL;

		if (curundo->prev) prevfile = &(curundo->prev->memfile);

		/* success = */ /* UNUSED */ BLO_write_file_mem(CTX_data_main(C), prevfile, &curundo->memfile, G.fileflags);
		curundo->undo_size = curundo->memfile.size;
	}

	if (U.undomemory != 0) {
		size_t maxmem, totmem;
		/* limit to maximum memory (afterwards, we can't know in advance) */
		totmem = 0;
		maxmem = ((size_t)U.undomemory) * 1024 * 1024;

		/* keep at least two (original + other) */
		uel = undobase.last;
		while (uel && uel->prev) {
			totmem += uel->undo_size;
			if (totmem > maxmem) break;
			uel = uel->prev;
		}

		if (uel) {
			if (uel->prev && uel->prev->prev)
				uel = uel->prev;

			while (undobase.first != uel) {
				UndoElem *first = undobase.first;
				BLI_remlink(&undobase, first);
				/* the merge is because of compression */
				BLO_memfile_merge(&first->memfile, &first->next->memfile);
				MEM_freeN(first);
			}
		}
	}
}
コード例 #22
0
/*
 * - loop over selected shapekeys.
 * - find firstsel/lastsel pairs.
 * - move these into a temp list.
 * - re-key all the original shapes.
 * - copy unselected values back from the original.
 * - free the original.
 */
static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
{
	Scene *scene = CTX_data_scene(C);
	const int frame = CFRA;
	Mask *mask = CTX_data_edit_mask(C);
	MaskLayer *masklay;
	bool changed = false;

	const bool do_feather  = RNA_boolean_get(op->ptr, "feather");
	const bool do_location = RNA_boolean_get(op->ptr, "location");

	for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {

		if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
			continue;
		}

		/* we need at least one point selected here to bother re-interpolating */
		if (!ED_mask_layer_select_check(masklay)) {
			continue;
		}

		if (masklay->splines_shapes.first) {
			MaskLayerShape *masklay_shape, *masklay_shape_next;
			MaskLayerShape *masklay_shape_lastsel = NULL;

			for (masklay_shape = masklay->splines_shapes.first;
			     masklay_shape;
			     masklay_shape = masklay_shape_next)
			{
				MaskLayerShape *masklay_shape_a = NULL;
				MaskLayerShape *masklay_shape_b = NULL;

				masklay_shape_next = masklay_shape->next;

				/* find contiguous selections */
				if (masklay_shape->flag & MASK_SHAPE_SELECT) {
					if (masklay_shape_lastsel == NULL) {
						masklay_shape_lastsel = masklay_shape;
					}
					if ((masklay_shape->next == NULL) ||
					    (((MaskLayerShape *)masklay_shape->next)->flag & MASK_SHAPE_SELECT) == 0)
					{
						masklay_shape_a = masklay_shape_lastsel;
						masklay_shape_b = masklay_shape;
						masklay_shape_lastsel = NULL;

						/* this will be freed below, step over selection */
						masklay_shape_next = masklay_shape->next;
					}
				}

				/* we have a from<>to? - re-interpolate! */
				if (masklay_shape_a && masklay_shape_b) {
					ListBase shapes_tmp = {NULL, NULL};
					MaskLayerShape *masklay_shape_tmp;
					MaskLayerShape *masklay_shape_tmp_next;
					MaskLayerShape *masklay_shape_tmp_last = masklay_shape_b->next;
					MaskLayerShape *masklay_shape_tmp_rekey;

					/* move keys */
					for (masklay_shape_tmp = masklay_shape_a;
					     masklay_shape_tmp && (masklay_shape_tmp != masklay_shape_tmp_last);
					     masklay_shape_tmp = masklay_shape_tmp_next)
					{
						masklay_shape_tmp_next = masklay_shape_tmp->next;
						BLI_remlink(&masklay->splines_shapes, masklay_shape_tmp);
						BLI_addtail(&shapes_tmp, masklay_shape_tmp);
					}

					/* re-key, note: cant modify the keys here since it messes uop */
					for (masklay_shape_tmp = shapes_tmp.first;
					     masklay_shape_tmp;
					     masklay_shape_tmp = masklay_shape_tmp->next)
					{
						BKE_mask_layer_evaluate(masklay, masklay_shape_tmp->frame, true);
						masklay_shape_tmp_rekey = BKE_mask_layer_shape_verify_frame(masklay, masklay_shape_tmp->frame);
						BKE_mask_layer_shape_from_mask(masklay, masklay_shape_tmp_rekey);
						masklay_shape_tmp_rekey->flag = masklay_shape_tmp->flag & MASK_SHAPE_SELECT;
					}

					/* restore unselected points and free copies */
					for (masklay_shape_tmp = shapes_tmp.first;
					     masklay_shape_tmp;
					     masklay_shape_tmp = masklay_shape_tmp_next)
					{
						/* restore */
						int i_abs = 0;
						int i;
						MaskSpline *spline;
						MaskLayerShapeElem *shape_ele_src;
						MaskLayerShapeElem *shape_ele_dst;

						masklay_shape_tmp_next = masklay_shape_tmp->next;

						/* we know this exists, added above */
						masklay_shape_tmp_rekey = BKE_mask_layer_shape_find_frame(masklay, masklay_shape_tmp->frame);

						shape_ele_src = (MaskLayerShapeElem *)masklay_shape_tmp->data;
						shape_ele_dst = (MaskLayerShapeElem *)masklay_shape_tmp_rekey->data;

						for (spline = masklay->splines.first; spline; spline = spline->next) {
							for (i = 0; i < spline->tot_point; i++) {
								MaskSplinePoint *point = &spline->points[i];

								/* not especially efficient but makes this easier to follow */
								SWAP(MaskLayerShapeElem, *shape_ele_src, *shape_ele_dst);

								if (MASKPOINT_ISSEL_ANY(point)) {
									if (do_location) {
										memcpy(shape_ele_dst->value, shape_ele_src->value, sizeof(float) * 6);
									}
									if (do_feather) {
										shape_ele_dst->value[6] = shape_ele_src->value[6];
									}
								}

								shape_ele_src++;
								shape_ele_dst++;

								i_abs++;
							}
						}

						BKE_mask_layer_shape_free(masklay_shape_tmp);
					}

					changed = true;
				}
			}

			/* re-evaluate */
			BKE_mask_layer_evaluate(masklay, frame, true);
		}
	}

	if (changed) {
		WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
		DAG_id_tag_update(&mask->id, 0);

		return OPERATOR_FINISHED;
	}
	else {
		return OPERATOR_CANCELLED;
	}
}
コード例 #23
0
static VFontData *vfont_get_data(Main *bmain, VFont *vfont)
{
	struct TmpFont *tmpfnt = NULL;
	PackedFile *tpf;
	
	if (vfont==NULL) return NULL;
	
	// Try finding the font from font list
	tmpfnt = vfont_find_tmpfont(vfont);
	
	// And then set the data	
	if (!vfont->data) {
		PackedFile *pf;
		
		if (strcmp(vfont->name, FO_BUILTIN_NAME)==0) {
			pf= get_builtin_packedfile();
		}
		else {
			if (vfont->packedfile) {
				pf= vfont->packedfile;
				
				// We need to copy a tmp font to memory unless it is already there
				if (!tmpfnt) {
					tpf= MEM_callocN(sizeof(*tpf), "PackedFile");
					tpf->data= MEM_mallocN(pf->size, "packFile");
					tpf->size= pf->size;
					memcpy(tpf->data, pf->data, pf->size);
					
					// Add temporary packed file to globals
					tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
					tmpfnt->pf= tpf;
					tmpfnt->vfont= vfont;
					BLI_addtail(&ttfdata, tmpfnt);
				}
			}
			else {
				pf= newPackedFile(NULL, vfont->name, ID_BLEND_PATH(bmain, &vfont->id));

				if (!tmpfnt) {
					tpf= newPackedFile(NULL, vfont->name, ID_BLEND_PATH(bmain, &vfont->id));
					
					// Add temporary packed file to globals
					tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
					tmpfnt->pf= tpf;
					tmpfnt->vfont= vfont;
					BLI_addtail(&ttfdata, tmpfnt);
				}
			}
			if (!pf) {
				printf("Font file doesn't exist: %s\n", vfont->name);

				strcpy(vfont->name, FO_BUILTIN_NAME);
				pf= get_builtin_packedfile();
			}
		}
		
		if (pf) {
			vfont->data= BLI_vfontdata_from_freetypefont(pf);
			if (pf != vfont->packedfile) {
				freePackedFile(pf);
			}
		}
	}
	
	return vfont->data;	
}
コード例 #24
0
// can be inlined if necessary
static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob)
{
	int a = 0;
	
	if (ob->adt)
		outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
	
	outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this
	
	if (ob->proxy && ob->id.lib==NULL)
		outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
	
	outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
	
	if (ob->pose) {
		bArmature *arm= ob->data;
		bPoseChannel *pchan;
		TreeElement *ten;
		TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0);
		
		tenla->name= "Pose";
		
		/* channels undefined in editmode, but we want the 'tenla' pose icon itself */
		if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
			int a= 0, const_index= 1000;	/* ensure unique id for bone constraints */
			
			for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next, a++) {
				ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
				ten->name= pchan->name;
				ten->directdata= pchan;
				pchan->temp= (void *)ten;
				
				if(pchan->constraints.first) {
					//Object *target;
					bConstraint *con;
					TreeElement *ten1;
					TreeElement *tenla1= outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
					//char *str;
					
					tenla1->name= "Constraints";
					for(con= pchan->constraints.first; con; con= con->next, const_index++) {
						ten1= outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
#if 0 /* disabled as it needs to be reworked for recoded constraints system */
						target= get_constraint_target(con, &str);
						if(str && str[0]) ten1->name= str;
						else if(target) ten1->name= target->id.name+2;
						else ten1->name= con->name;
#endif
						ten1->name= con->name;
						ten1->directdata= con;
						/* possible add all other types links? */
					}
				}
			}
			/* make hierarchy */
			ten= tenla->subtree.first;
			while(ten) {
				TreeElement *nten= ten->next, *par;
				tselem= TREESTORE(ten);
				if(tselem->type==TSE_POSE_CHANNEL) {
					pchan= (bPoseChannel *)ten->directdata;
					if(pchan->parent) {
						BLI_remlink(&tenla->subtree, ten);
						par= (TreeElement *)pchan->parent->temp;
						BLI_addtail(&par->subtree, ten);
						ten->parent= par;
					}
				}
				ten= nten;
			}
		}
		
		/* Pose Groups */
		if(ob->pose->agroups.first) {
			bActionGroup *agrp;
			TreeElement *ten;
			TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
			int a= 0;
			
			tenla->name= "Bone Groups";
			for (agrp=ob->pose->agroups.first; agrp; agrp=agrp->next, a++) {
				ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSEGRP, a);
				ten->name= agrp->name;
				ten->directdata= agrp;
			}
		}
	}
	
	for(a=0; a<ob->totcol; a++) 
		outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a);
	
	if(ob->constraints.first) {
		//Object *target;
		bConstraint *con;
		TreeElement *ten;
		TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
		//char *str;
		
		tenla->name= "Constraints";
		for (con=ob->constraints.first, a=0; con; con= con->next, a++) {
			ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
#if 0 /* disabled due to constraints system targets recode... code here needs review */
			target= get_constraint_target(con, &str);
			if(str && str[0]) ten->name= str;
			else if(target) ten->name= target->id.name+2;
			else ten->name= con->name;
#endif
			ten->name= con->name;
			ten->directdata= con;
			/* possible add all other types links? */
		}
	}
	
	if (ob->modifiers.first) {
		ModifierData *md;
		TreeElement *temod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
		int index;
		
		temod->name = "Modifiers";
		for (index=0,md=ob->modifiers.first; md; index++,md=md->next) {
			TreeElement *te = outliner_add_element(soops, &temod->subtree, ob, temod, TSE_MODIFIER, index);
			te->name= md->name;
			te->directdata = md;
			
			if (md->type==eModifierType_Lattice) {
				outliner_add_element(soops, &te->subtree, ((LatticeModifierData*) md)->object, te, TSE_LINKED_OB, 0);
			} 
			else if (md->type==eModifierType_Curve) {
				outliner_add_element(soops, &te->subtree, ((CurveModifierData*) md)->object, te, TSE_LINKED_OB, 0);
			} 
			else if (md->type==eModifierType_Armature) {
				outliner_add_element(soops, &te->subtree, ((ArmatureModifierData*) md)->object, te, TSE_LINKED_OB, 0);
			} 
			else if (md->type==eModifierType_Hook) {
				outliner_add_element(soops, &te->subtree, ((HookModifierData*) md)->object, te, TSE_LINKED_OB, 0);
			} 
			else if (md->type==eModifierType_ParticleSystem) {
				TreeElement *ten;
				ParticleSystem *psys= ((ParticleSystemModifierData*) md)->psys;
				
				ten = outliner_add_element(soops, &te->subtree, ob, te, TSE_LINKED_PSYS, 0);
				ten->directdata = psys;
				ten->name = psys->part->id.name+2;
			}
		}
	}
	
	/* vertex groups */
	if (ob->defbase.first) {
		bDeformGroup *defgroup;
		TreeElement *ten;
		TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
		
		tenla->name= "Vertex Groups";
		for (defgroup=ob->defbase.first, a=0; defgroup; defgroup=defgroup->next, a++) {
			ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a);
			ten->name= defgroup->name;
			ten->directdata= defgroup;
		}
	}
	
	/* duplicated group */
	if (ob->dup_group)
		outliner_add_element(soops, &te->subtree, ob->dup_group, te, 0, 0);	
}
コード例 #25
0
static void buildchar(Main *bmain, Curve *cu, unsigned long character, CharInfo *info, float ofsx, float ofsy, float rot, int charidx)
{
	BezTriple *bezt1, *bezt2;
	Nurb *nu1 = NULL, *nu2 = NULL;
	float *fp, fsize, shear, x, si, co;
	VFontData *vfd = NULL;
	VChar *che = NULL;
	int i;

	vfd= vfont_get_data(bmain, which_vfont(cu, info));
	if (!vfd) return;

#if 0
	if (cu->selend < cu->selstart) {
		if ((charidx >= (cu->selend)) && (charidx <= (cu->selstart-2)))
			sel= 1;
	}
	else {
		if ((charidx >= (cu->selstart-1)) && (charidx <= (cu->selend-1)))
			sel= 1;
	}
#endif

	/* make a copy at distance ofsx,ofsy with shear*/
	fsize= cu->fsize;
	shear= cu->shear;
	si= (float)sin(rot);
	co= (float)cos(rot);

	che= find_vfont_char(vfd, character);
	
	// Select the glyph data
	if (che)
		nu1 = che->nurbsbase.first;

	// Create the character
	while (nu1)
	{
		bezt1 = nu1->bezt;
		if (bezt1) {
			nu2 =(Nurb*) MEM_mallocN(sizeof(Nurb),"duplichar_nurb");
			if (nu2 == NULL) break;
			memcpy(nu2, nu1, sizeof(struct Nurb));
			nu2->resolu= cu->resolu;
			nu2->bp = NULL;
			nu2->knotsu = nu2->knotsv = NULL;
			nu2->flag= CU_SMOOTH;
			nu2->charidx = charidx;
			if (info->mat_nr > 0) {
				nu2->mat_nr= info->mat_nr-1;
			}
			else {
				nu2->mat_nr= 0;
			}
			/* nu2->trim.first = 0; */
			/* nu2->trim.last = 0; */
			i = nu2->pntsu;

			bezt2 = (BezTriple*)MEM_mallocN(i * sizeof(BezTriple),"duplichar_bezt2"); 
			if (bezt2 == NULL) {
				MEM_freeN(nu2);
				break;
			}
			memcpy(bezt2, bezt1, i * sizeof(struct BezTriple));
			nu2->bezt = bezt2;
			
			if (shear != 0.0f) {
				bezt2 = nu2->bezt;
				
				for (i= nu2->pntsu; i > 0; i--) {
					bezt2->vec[0][0] += shear * bezt2->vec[0][1];
					bezt2->vec[1][0] += shear * bezt2->vec[1][1];
					bezt2->vec[2][0] += shear * bezt2->vec[2][1];
					bezt2++;
				}
			}
			if (rot != 0.0f) {
				bezt2= nu2->bezt;
				for (i=nu2->pntsu; i > 0; i--) {
					fp= bezt2->vec[0];
					
					x= fp[0];
					fp[0]= co*x + si*fp[1];
					fp[1]= -si*x + co*fp[1];
					x= fp[3];
					fp[3]= co*x + si*fp[4];
					fp[4]= -si*x + co*fp[4];
					x= fp[6];
					fp[6]= co*x + si*fp[7];
					fp[7]= -si*x + co*fp[7];

					bezt2++;
				}
			}
			bezt2 = nu2->bezt;

			if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
				const float sca= cu->smallcaps_scale;
				for (i= nu2->pntsu; i > 0; i--) {
					fp= bezt2->vec[0];
					fp[0] *= sca;
					fp[1] *= sca;
					fp[3] *= sca;
					fp[4] *= sca;
					fp[6] *= sca;
					fp[7] *= sca;
					bezt2++;
				}
			}
			bezt2 = nu2->bezt;

			for (i= nu2->pntsu; i > 0; i--) {
				fp= bezt2->vec[0];
				fp[0]= (fp[0]+ofsx)*fsize;
				fp[1]= (fp[1]+ofsy)*fsize;
				fp[3]= (fp[3]+ofsx)*fsize;
				fp[4]= (fp[4]+ofsy)*fsize;
				fp[6]= (fp[6]+ofsx)*fsize;
				fp[7]= (fp[7]+ofsy)*fsize;
				bezt2++;
			}
			
			BLI_addtail(&(cu->nurb), nu2);
		}
		
		nu1 = nu1->next;
	}
}
コード例 #26
0
// can be inlined if necessary
static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, ID *id)
{
	/* tuck pointer back in object, to construct hierarchy */
	if (GS(id->name)==ID_OB) id->newid= (ID *)te;
	
	/* expand specific data always */
	switch (GS(id->name)) {
		case ID_LI:
		{
			te->name= ((Library *)id)->name;
		}
			break;
		case ID_SCE:
		{
			outliner_add_scene_contents(soops, &te->subtree, (Scene *)id, te);
		}
			break;
		case ID_OB:
		{
			outliner_add_object_contents(soops, te, tselem, (Object *)id);
		}
			break;
		case ID_ME:
		{
			Mesh *me= (Mesh *)id;
			int a;
			
			if (me->adt)
				outliner_add_element(soops, &te->subtree, me, te, TSE_ANIM_DATA, 0);
			
			outliner_add_element(soops, &te->subtree, me->key, te, 0, 0);
			for(a=0; a<me->totcol; a++) 
				outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a);
			/* could do tfaces with image links, but the images are not grouped nicely.
			   would require going over all tfaces, sort images in use. etc... */
		}
			break;
		case ID_CU:
		{
			Curve *cu= (Curve *)id;
			int a;
			
			if (cu->adt)
				outliner_add_element(soops, &te->subtree, cu, te, TSE_ANIM_DATA, 0);
			
			for(a=0; a<cu->totcol; a++) 
				outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a);
		}
			break;
		case ID_MB:
		{
			MetaBall *mb= (MetaBall *)id;
			int a;
			
			if (mb->adt)
				outliner_add_element(soops, &te->subtree, mb, te, TSE_ANIM_DATA, 0);
			
			for(a=0; a<mb->totcol; a++) 
				outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a);
		}
			break;
		case ID_MA:
		{
			Material *ma= (Material *)id;
			int a;
			
			if (ma->adt)
				outliner_add_element(soops, &te->subtree, ma, te, TSE_ANIM_DATA, 0);
			
			for(a=0; a<MAX_MTEX; a++) {
				if(ma->mtex[a]) outliner_add_element(soops, &te->subtree, ma->mtex[a]->tex, te, 0, a);
			}
		}
			break;
		case ID_TE:
		{
			Tex *tex= (Tex *)id;
			
			if (tex->adt)
				outliner_add_element(soops, &te->subtree, tex, te, TSE_ANIM_DATA, 0);
			
			outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0);
		}
			break;
		case ID_CA:
		{
			Camera *ca= (Camera *)id;
			
			if (ca->adt)
				outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0);
		}
			break;
		case ID_LA:
		{
			Lamp *la= (Lamp *)id;
			int a;
			
			if (la->adt)
				outliner_add_element(soops, &te->subtree, la, te, TSE_ANIM_DATA, 0);
			
			for(a=0; a<MAX_MTEX; a++) {
				if(la->mtex[a]) outliner_add_element(soops, &te->subtree, la->mtex[a]->tex, te, 0, a);
			}
		}
			break;
		case ID_SPK:
			{
				Speaker *spk= (Speaker *)id;

				if(spk->adt)
					outliner_add_element(soops, &te->subtree, spk, te, TSE_ANIM_DATA, 0);
			}
			break;
		case ID_WO:
		{
			World *wrld= (World *)id;
			int a;
			
			if (wrld->adt)
				outliner_add_element(soops, &te->subtree, wrld, te, TSE_ANIM_DATA, 0);
			
			for(a=0; a<MAX_MTEX; a++) {
				if(wrld->mtex[a]) outliner_add_element(soops, &te->subtree, wrld->mtex[a]->tex, te, 0, a);
			}
		}
			break;
		case ID_KE:
		{
			Key *key= (Key *)id;
			
			if (key->adt)
				outliner_add_element(soops, &te->subtree, key, te, TSE_ANIM_DATA, 0);
		}
			break;
		case ID_AC:
		{
			// XXX do we want to be exposing the F-Curves here?
			//bAction *act= (bAction *)id;
		}
			break;
		case ID_AR:
		{
			bArmature *arm= (bArmature *)id;
			int a= 0;
			
			if (arm->adt)
				outliner_add_element(soops, &te->subtree, arm, te, TSE_ANIM_DATA, 0);
			
			if(arm->edbo) {
				EditBone *ebone;
				TreeElement *ten;
				
				for (ebone = arm->edbo->first; ebone; ebone=ebone->next, a++) {
					ten= outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
					ten->directdata= ebone;
					ten->name= ebone->name;
					ebone->temp= ten;
				}
				/* make hierarchy */
				ten= arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp : NULL;
				while(ten) {
					TreeElement *nten= ten->next, *par;
					ebone= (EditBone *)ten->directdata;
					if(ebone->parent) {
						BLI_remlink(&te->subtree, ten);
						par= ebone->parent->temp;
						BLI_addtail(&par->subtree, ten);
						ten->parent= par;
					}
					ten= nten;
				}
			}
			else {
				/* do not extend Armature when we have posemode */
				tselem= TREESTORE(te->parent);
				if( GS(tselem->id->name)==ID_OB && ((Object *)tselem->id)->mode & OB_MODE_POSE);
				else {
					Bone *curBone;
					for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
						outliner_add_bone(soops, &te->subtree, id, curBone, te, &a);
					}
				}
			}
		}
			break;
	}
}
コード例 #27
0
int join_mesh_exec(bContext *C, wmOperator *op)
{
	Main *bmain= CTX_data_main(C);
	Scene *scene= CTX_data_scene(C);
	Object *ob= CTX_data_active_object(C);
	Material **matar, *ma;
	Mesh *me;
	MVert *mvert, *mv;
	MEdge *medge = NULL;
	MFace *mface = NULL;
	Key *key, *nkey=NULL;
	KeyBlock *kb, *okb, *kbn;
	float imat[4][4], cmat[4][4], *fp1, *fp2, curpos;
	int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0;
	int vertofs, *matmap=NULL;
	int	i, j, index, haskey=0, edgeofs, faceofs;
	bDeformGroup *dg, *odg;
	MDeformVert *dvert;
	CustomData vdata, edata, fdata;

	if(scene->obedit) {
		BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode");
		return OPERATOR_CANCELLED;
	}
	
	/* ob is the object we are adding geometry to */
	if(!ob || ob->type!=OB_MESH) {
		BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh");
		return OPERATOR_CANCELLED;
	}
	
	/* count & check */
	CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
		if(base->object->type==OB_MESH) {
			me= base->object->data;
			
			totvert+= me->totvert;
			totedge+= me->totedge;
			totface+= me->totface;
			totmat+= base->object->totcol;
			
			if(base->object == ob)
				ok= 1;
			
			/* check for shapekeys */
			if(me->key)
				haskey++;
		}
	}
	CTX_DATA_END;
	
	/* that way the active object is always selected */ 
	if(ok==0) {
		BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh");
		return OPERATOR_CANCELLED;
	}
	
	/* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */
	me= (Mesh *)ob->data;
	key= me->key;

	if(totvert==0 || totvert==me->totvert) {
		BKE_report(op->reports, RPT_WARNING, "No mesh data to join");
		return OPERATOR_CANCELLED;
	}
	
	if(totvert > MESH_MAX_VERTS) {
		BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is " STRINGIFY(MESH_MAX_VERTS), totvert);
		return OPERATOR_CANCELLED;		
	}

	/* new material indices and material array */
	matar= MEM_callocN(sizeof(void*)*totmat, "join_mesh matar");
	if (totmat) matmap= MEM_callocN(sizeof(int)*totmat, "join_mesh matmap");
	totcol= ob->totcol;
	
	/* obact materials in new main array, is nicer start! */
	for(a=0; a<ob->totcol; a++) {
		matar[a]= give_current_material(ob, a+1);
		id_us_plus((ID *)matar[a]);
		/* increase id->us : will be lowered later */
	}
	
	/* - if destination mesh had shapekeys, move them somewhere safe, and set up placeholders
	 * 	with arrays that are large enough to hold shapekey data for all meshes
	 * -	if destination mesh didn't have shapekeys, but we encountered some in the meshes we're 
	 *	joining, set up a new keyblock and assign to the mesh
	 */
	if(key) {
		/* make a duplicate copy that will only be used here... (must remember to free it!) */
		nkey= copy_key(key);
		
		/* for all keys in old block, clear data-arrays */
		for(kb= key->block.first; kb; kb= kb->next) {
			if(kb->data) MEM_freeN(kb->data);
			kb->data= MEM_callocN(sizeof(float)*3*totvert, "join_shapekey");
			kb->totelem= totvert;
			kb->weights= NULL;
		}
	}
	else if(haskey) {
		/* add a new key-block and add to the mesh */
		key= me->key= add_key((ID *)me);
		key->type = KEY_RELATIVE;
	}
	
	/* first pass over objects - copying materials and vertexgroups across */
	CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
		/* only act if a mesh, and not the one we're joining to */
		if((ob!=base->object) && (base->object->type==OB_MESH)) {
			me= base->object->data;
			
			/* Join this object's vertex groups to the base one's */
			for(dg=base->object->defbase.first; dg; dg=dg->next) {
				/* See if this group exists in the object (if it doesn't, add it to the end) */
				if(!defgroup_find_name(ob, dg->name)) {
					odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup");
					memcpy(odg, dg, sizeof(bDeformGroup));
					BLI_addtail(&ob->defbase, odg);
				}
			}
			if(ob->defbase.first && ob->actdef==0)
				ob->actdef=1;
			
			
			if(me->totvert) {
				/* Add this object's materials to the base one's if they don't exist already (but only if limits not exceeded yet) */
				if(totcol < MAXMAT) {
					for(a=1; a<=base->object->totcol; a++) {
						ma= give_current_material(base->object, a);

						for(b=0; b<totcol; b++) {
							if(ma == matar[b]) break;
						}
						if(b==totcol) {
							matar[b]= ma;
							if(ma) {
								id_us_plus(&ma->id);
							}
							totcol++;
						}
						if(totcol >= MAXMAT)
							break;
					}
				}
				
				/* if this mesh has shapekeys, check if destination mesh already has matching entries too */
				if(me->key && key) {
					for(kb= me->key->block.first; kb; kb= kb->next) {
						/* if key doesn't exist in destination mesh, add it */
						if(key_get_named_keyblock(key, kb->name) == NULL) {
							/* copy this existing one over to the new shapekey block */
							kbn= MEM_dupallocN(kb);
							kbn->prev= kbn->next= NULL;
							
							/* adjust adrcode and other settings to fit (allocate a new data-array) */
							kbn->data= MEM_callocN(sizeof(float)*3*totvert, "joined_shapekey");
							kbn->totelem= totvert;
							kbn->weights= NULL;
							
							okb= key->block.last;
							curpos= (okb) ? okb->pos : -0.1f;
							if(key->type == KEY_RELATIVE)
								kbn->pos= curpos + 0.1f;
							else
								kbn->pos= curpos;
							
							BLI_addtail(&key->block, kbn);
							kbn->adrcode= key->totkey;
							key->totkey++;
							if(key->totkey==1) key->refkey= kbn;
							
							// XXX 2.5 Animato
#if 0
							/* also, copy corresponding ipo-curve to ipo-block if applicable */
							if(me->key->ipo && key->ipo) {
								// FIXME... this is a luxury item!
								puts("FIXME: ignoring IPO's when joining shapekeys on Meshes for now...");
							}
#endif
						}
					}
				}
			}
		}
	}
	CTX_DATA_END;
	
	/* setup new data for destination mesh */
	memset(&vdata, 0, sizeof(vdata));
	memset(&edata, 0, sizeof(edata));
	memset(&fdata, 0, sizeof(fdata));
	
	mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
	medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
	mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);

	vertofs= 0;
	edgeofs= 0;
	faceofs= 0;
	
	/* inverse transform for all selected meshes in this object */
	invert_m4_m4(imat, ob->obmat);
	
	CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
		/* only join if this is a mesh */
		if(base->object->type==OB_MESH) {
			me= base->object->data;
			
			if(me->totvert) {
				/* standard data */
				CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
				CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert);
				
				/* vertex groups */
				dvert= CustomData_get(&vdata, vertofs, CD_MDEFORMVERT);
				
				/* NB: vertex groups here are new version */
				if(dvert) {
					for(i=0; i<me->totvert; i++) {
						for(j=0; j<dvert[i].totweight; j++) {
							/*	Find the old vertex group */
							odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr);
							if(odg) {
								/*	Search for a match in the new object, and set new index */
								for(dg=ob->defbase.first, index=0; dg; dg=dg->next, index++) {
									if(!strcmp(dg->name, odg->name)) {
										dvert[i].dw[j].def_nr = index;
										break;
									}
								}
							}
						}
					}
				}
				
				/* if this is the object we're merging into, no need to do anything */
				if(base->object != ob) {
					/* watch this: switch matmul order really goes wrong */
					mul_m4_m4m4(cmat, base->object->obmat, imat);
					
					/* transform vertex coordinates into new space */
					for(a=0, mv=mvert; a < me->totvert; a++, mv++) {
						mul_m4_v3(cmat, mv->co);
					}
					
					/* for each shapekey in destination mesh:
					 *	- if there's a matching one, copy it across (will need to transform vertices into new space...)
					 *	- otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space)
					 */
					if(key) {
						/* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
						for(kb= key->block.first; kb; kb= kb->next) {
							/* get pointer to where to write data for this mesh in shapekey's data array */
							fp1= ((float *)kb->data) + (vertofs*3);	
							
							/* check if this mesh has such a shapekey */
							okb= key_get_named_keyblock(me->key, kb->name);
							if(okb) {
								/* copy this mesh's shapekey to the destination shapekey (need to transform first) */
								fp2= ((float *)(okb->data));
								for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) {
									VECCOPY(fp1, fp2);
									mul_m4_v3(cmat, fp1);
								}
							}
							else {
								/* copy this mesh's vertex coordinates to the destination shapekey */
								mv= mvert;
								for(a=0; a < me->totvert; a++, fp1+=3, mv++) {
									VECCOPY(fp1, mv->co);
								}
							}
						}
					}
				}
				else {
					/* for each shapekey in destination mesh:
					 *	- if it was an 'original', copy the appropriate data from nkey
					 *	- otherwise, copy across plain coordinates (no need to transform coordinates)
					 */
					if(key) {
						for(kb= key->block.first; kb; kb= kb->next) {
							/* get pointer to where to write data for this mesh in shapekey's data array */
							fp1= ((float *)kb->data) + (vertofs*3);	
							
							/* check if this was one of the original shapekeys */
							okb= key_get_named_keyblock(nkey, kb->name);
							if(okb) {
								/* copy this mesh's shapekey to the destination shapekey */
								fp2= ((float *)(okb->data));
								for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) {
									VECCOPY(fp1, fp2);
								}
							}
							else {
								/* copy base-coordinates to the destination shapekey */
								mv= mvert;
								for(a=0; a < me->totvert; a++, fp1+=3, mv++) {
									VECCOPY(fp1, mv->co);
								}
							}
						}
					}
				}
				
				/* advance mvert pointer to end of base mesh's data */
				mvert+= me->totvert;
			}
			
			if(me->totface) {
				/* make mapping for materials */
				for(a=1; a<=base->object->totcol; a++) {
					ma= give_current_material(base->object, a);

					for(b=0; b<totcol; b++) {
						if(ma == matar[b]) {
							matmap[a-1]= b;
							break;
						}
					}
				}
				
				if(base->object!=ob)
					multiresModifier_prepare_join(scene, base->object, ob);

				CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
				CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface);
				
				for(a=0; a<me->totface; a++, mface++) {
					mface->v1+= vertofs;
					mface->v2+= vertofs;
					mface->v3+= vertofs;
					if(mface->v4) mface->v4+= vertofs;
					
					if (matmap)
						mface->mat_nr= matmap[(int)mface->mat_nr];
					else 
						mface->mat_nr= 0;
				}
				
				faceofs += me->totface;
			}
			
			if(me->totedge) {
				CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
				CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge);
				
				for(a=0; a<me->totedge; a++, medge++) {
					medge->v1+= vertofs;
					medge->v2+= vertofs;
				}
				
				edgeofs += me->totedge;
			}
			
			/* vertofs is used to help newly added verts be reattached to their edge/face 
			 * (cannot be set earlier, or else reattaching goes wrong)
			 */
			vertofs += me->totvert;
			
			/* free base, now that data is merged */
			if(base->object != ob)
				ED_base_object_free_and_unlink(bmain, scene, base);
		}
	}
	CTX_DATA_END;
	
	/* return to mesh we're merging to */
	me= ob->data;
	
	CustomData_free(&me->vdata, me->totvert);
	CustomData_free(&me->edata, me->totedge);
	CustomData_free(&me->fdata, me->totface);

	me->totvert= totvert;
	me->totedge= totedge;
	me->totface= totface;
	
	me->vdata= vdata;
	me->edata= edata;
	me->fdata= fdata;

	mesh_update_customdata_pointers(me);
	
	/* old material array */
	for(a=1; a<=ob->totcol; a++) {
		ma= ob->mat[a-1];
		if(ma) ma->id.us--;
	}
	for(a=1; a<=me->totcol; a++) {
		ma= me->mat[a-1];
		if(ma) ma->id.us--;
	}
	if(ob->mat) MEM_freeN(ob->mat);
	if(ob->matbits) MEM_freeN(ob->matbits);
	if(me->mat) MEM_freeN(me->mat);
	ob->mat= me->mat= NULL;
	ob->matbits= NULL;
	
	if(totcol) {
		me->mat= matar;
		ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar");
		ob->matbits= MEM_callocN(sizeof(char)*totcol, "join obmatbits");
	}
	else
		MEM_freeN(matar);
	
	ob->totcol= me->totcol= totcol;
	ob->colbits= 0;

	if (matmap) MEM_freeN(matmap);
	
	/* other mesh users */
	test_object_materials((ID *)me);
	
	/* free temp copy of destination shapekeys (if applicable) */
	if(nkey) {
		// XXX 2.5 Animato
#if 0
		/* free it's ipo too - both are not actually freed from memory yet as ID-blocks */
		if(nkey->ipo) {
			free_ipo(nkey->ipo);
			BLI_remlink(&bmain->ipo, nkey->ipo);
			MEM_freeN(nkey->ipo);
		}
#endif
		
		free_key(nkey);
		BLI_remlink(&bmain->key, nkey);
		MEM_freeN(nkey);
	}
	
	DAG_scene_sort(bmain, scene);	// removed objects, need to rebuild dag before editmode call

#if 0
	ED_object_enter_editmode(C, EM_WAITCURSOR);
	ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO);
#else
	/* toggle editmode using lower level functions so this can be called from python */
	make_editMesh(scene, ob);
	load_editMesh(scene, ob);
	free_editMesh(me->edit_mesh);
	MEM_freeN(me->edit_mesh);
	me->edit_mesh= NULL;
	DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA);
#endif
	WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);

	return OPERATOR_FINISHED;
}
コード例 #28
0
// TODO: this function needs to be split up! It's getting a bit too large...
static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv, 
										 TreeElement *parent, short type, short index)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	ID *id= idv;
	int a = 0;
	
	if(ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
		id= ((PointerRNA*)idv)->id.data;
		if(!id) id= ((PointerRNA*)idv)->data;
	}

	if(id==NULL) return NULL;

	te= MEM_callocN(sizeof(TreeElement), "tree elem");
	/* add to the visual tree */
	BLI_addtail(lb, te);
	/* add to the storage */
	check_persistent(soops, te, id, type, index);
	tselem= TREESTORE(te);	
	
	/* if we are searching for something expand to see child elements */
	if(SEARCHING_OUTLINER(soops))
		tselem->flag |= TSE_CHILDSEARCH;
	
	te->parent= parent;
	te->index= index;	// for data arays
	if(ELEM3(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP));
	else if(ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM));
	else if(type==TSE_ANIM_DATA);
	else {
		te->name= id->name+2; // default, can be overridden by Library or non-ID data
		te->idcode= GS(id->name);
	}
	
	if(type==0) {
		/* ID datablock */
		outliner_add_id_contents(soops, te, tselem, id);
	}
	else if(type==TSE_ANIM_DATA) {
		IdAdtTemplate *iat = (IdAdtTemplate *)idv;
		AnimData *adt= (AnimData *)iat->adt;
		
		/* this element's info */
		te->name= "Animation";
		te->directdata= adt;
		
		/* Action */
		outliner_add_element(soops, &te->subtree, adt->action, te, 0, 0);
		
		/* Drivers */
		if (adt->drivers.first) {
			TreeElement *ted= outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0);
			ID *lastadded= NULL;
			FCurve *fcu;
			
			ted->name= "Drivers";
		
			for (fcu= adt->drivers.first; fcu; fcu= fcu->next) {
				if (fcu->driver && fcu->driver->variables.first)  {
					ChannelDriver *driver= fcu->driver;
					DriverVar *dvar;
					
					for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
						/* loop over all targets used here */
						DRIVER_TARGETS_USED_LOOPER(dvar) 
						{
							if (lastadded != dtar->id) {
								// XXX this lastadded check is rather lame, and also fails quite badly...
								outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0);
								lastadded= dtar->id;
							}
						}
						DRIVER_TARGETS_LOOPER_END
					}
				}
			}
コード例 #29
0
static int armature_subdivide_exec(bContext *C, wmOperator *op)
{
	Object *obedit = CTX_data_edit_object(C);
	bArmature *arm = obedit->data;
	EditBone *newbone, *tbone;
	int cuts, i;
	
	/* there may not be a number_cuts property defined (for 'simple' subdivide) */
	cuts = RNA_int_get(op->ptr, "number_cuts");
	
	/* loop over all editable bones */
	// XXX the old code did this in reverse order though!
	CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
	{
		for (i = cuts + 1; i > 1; i--) {
			/* compute cut ratio first */
			float cutratio = 1.0f / (float)i;
			float cutratioI = 1.0f - cutratio;
			
			float val1[3];
			float val2[3];
			float val3[3];
			
			newbone = MEM_mallocN(sizeof(EditBone), "ebone subdiv");
			*newbone = *ebone;
			BLI_addtail(arm->edbo, newbone);
			
			/* calculate location of newbone->head */
			copy_v3_v3(val1, ebone->head);
			copy_v3_v3(val2, ebone->tail);
			copy_v3_v3(val3, newbone->head);
			
			val3[0] = val1[0] * cutratio + val2[0] * cutratioI;
			val3[1] = val1[1] * cutratio + val2[1] * cutratioI;
			val3[2] = val1[2] * cutratio + val2[2] * cutratioI;
			
			copy_v3_v3(newbone->head, val3);
			copy_v3_v3(newbone->tail, ebone->tail);
			copy_v3_v3(ebone->tail, newbone->head);
			
			newbone->rad_head = ((ebone->rad_head * cutratio) + (ebone->rad_tail * cutratioI));
			ebone->rad_tail = newbone->rad_head;
			
			newbone->flag |= BONE_CONNECTED;

			newbone->prop = NULL;

			unique_editbone_name(arm->edbo, newbone->name, NULL);
			
			/* correct parent bones */
			for (tbone = arm->edbo->first; tbone; tbone = tbone->next) {
				if (tbone->parent == ebone)
					tbone->parent = newbone;
			}
			newbone->parent = ebone;
		}
	}
	CTX_DATA_END;
	
	/* note, notifier might evolve */
	WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
	
	return OPERATOR_FINISHED;
}
コード例 #30
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;
}