// 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; }
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; }
/* 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; }
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; }
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; }
/* 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; } } } }
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; }
/* 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); }
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; } }
/* 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); }
/* 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); } } } }
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"); }
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; }
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; }
/* 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; }
/* 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; }
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); }
/* 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); }
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); }
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; }
/* 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); } } } }
/* * - 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; } }
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; }
// 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); }
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; } }
// 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; } }
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; }
// 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 } } }
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; }
/* * 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; }