/* note, doesnt run exit() call WM_exit() for that */ void WM_exit_ext(bContext *C, const bool do_python) { wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL; BKE_sound_exit(); /* first wrap up running stuff, we assume only the active WM is running */ /* modal handlers are on window level freed, others too? */ /* note; same code copied in wm_files.c */ if (C && wm) { wmWindow *win; if (!G.background) { if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_is_valid(NULL)) { /* save the undo state as quit.blend */ char filename[FILE_MAX]; bool has_edited; int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY); BLI_make_file_string("/", filename, BKE_tempdir_base(), BLENDER_QUIT_FILE); has_edited = ED_editors_flush_edits(C, false); if ((has_edited && BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL)) || BKE_undo_save_file(filename)) { printf("Saved session recovery to '%s'\n", filename); } } } WM_jobs_kill_all(wm); for (win = wm->windows.first; win; win = win->next) { CTX_wm_window_set(C, win); /* needed by operator close callbacks */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); ED_screen_exit(C, win, win->screen); } } BKE_addon_pref_type_free(); wm_operatortype_free(); wm_dropbox_free(); WM_menutype_free(); WM_uilisttype_free(); /* all non-screen and non-space stuff editors did, like editmode */ if (C) ED_editors_exit(C); // XXX // BIF_GlobalReebFree(); // BIF_freeRetarget(); BIF_freeTemplates(C); free_openrecent(); BKE_mball_cubeTable_free(); /* render code might still access databases */ RE_FreeAllRender(); RE_engines_exit(); ED_preview_free_dbase(); /* frees a Main dbase, before free_blender! */ if (C && wm) wm_free_reports(C); /* before free_blender! - since the ListBases get freed there */ BKE_sequencer_free_clipboard(); /* sequencer.c */ BKE_tracking_clipboard_free(); BKE_mask_clipboard_free(); #ifdef WITH_COMPOSITOR COM_deinitialize(); #endif free_blender(); /* blender.c, does entire library and spacetypes */ // free_matcopybuf(); free_anim_copybuf(); free_anim_drivers_copybuf(); free_fmodifiers_copybuf(); ED_gpencil_strokes_copybuf_free(); ED_clipboard_posebuf_free(); BKE_node_clipboard_clear(); BLF_exit(); #ifdef WITH_INTERNATIONAL BLF_free_unifont(); BLF_free_unifont_mono(); BLT_lang_free(); #endif ANIM_keyingset_infos_exit(); // free_txt_data(); #ifdef WITH_PYTHON /* option not to close python so we can use 'atexit' */ if (do_python) { /* XXX - old note */ /* before free_blender so py's gc happens while library still exists */ /* needed at least for a rare sigsegv that can happen in pydrivers */ /* Update for blender 2.5, move after free_blender because blender now holds references to PyObject's * so decref'ing them after python ends causes bad problems every time * the pyDriver bug can be fixed if it happens again we can deal with it then */ BPY_python_end(); } #else (void)do_python; #endif #ifdef WITH_OPENSUBDIV openSubdiv_cleanup(); #endif if (!G.background) { GPU_global_buffer_pool_free(); GPU_free_unused_buffers(); GPU_exit(); } BKE_undo_reset(); ED_file_exit(); /* for fsmenu */ UI_exit(); BKE_userdef_free(); RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */ wm_ghost_exit(); CTX_free(C); #ifdef WITH_GAMEENGINE SYS_DeleteSystem(SYS_GetSystem()); #endif GHOST_DisposeSystemPaths(); BLI_threadapi_exit(); if (MEM_get_memory_blocks_in_use() != 0) { size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use(); printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n", MEM_get_memory_blocks_in_use(), (double)mem_in_use / 1024 / 1024); MEM_printmemlist(); } wm_autosave_delete(); BKE_tempdir_session_purge(); }
/* join armature exec is exported for use in object->join objects operator... */ int join_armature_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); bArmature *arm = (ob) ? ob->data : NULL; bPose *pose, *opose; bPoseChannel *pchan, *pchann; EditBone *curbone; float mat[4][4], oimat[4][4]; bool ok = false; /* Ensure we're not in editmode and that the active object is an armature*/ if (!ob || ob->type != OB_ARMATURE) return OPERATOR_CANCELLED; if (!arm || arm->edbo) return OPERATOR_CANCELLED; CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) { if (base->object == ob) { ok = true; break; } } CTX_DATA_END; /* that way the active object is always selected */ if (ok == false) { BKE_report(op->reports, RPT_WARNING, "Active object is not a selected armature"); return OPERATOR_CANCELLED; } /* Get editbones of active armature to add editbones to */ ED_armature_to_edit(arm); /* get pose of active object and move it out of posemode */ pose = ob->pose; ob->mode &= ~OB_MODE_POSE; CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) { if ((base->object->type == OB_ARMATURE) && (base->object != ob)) { bArmature *curarm = base->object->data; /* Make a list of editbones in current armature */ ED_armature_to_edit(base->object->data); /* Get Pose of current armature */ opose = base->object->pose; base->object->mode &= ~OB_MODE_POSE; //BASACT->flag &= ~OB_MODE_POSE; /* Find the difference matrix */ invert_m4_m4(oimat, ob->obmat); mul_m4_m4m4(mat, oimat, base->object->obmat); /* Copy bones and posechannels from the object to the edit armature */ for (pchan = opose->chanbase.first; pchan; pchan = pchann) { pchann = pchan->next; curbone = ED_armature_bone_find_name(curarm->edbo, pchan->name); /* Get new name */ unique_editbone_name(arm->edbo, curbone->name, NULL); /* Transform the bone */ { float premat[4][4]; float postmat[4][4]; float difmat[4][4]; float imat[4][4]; float temp[3][3]; /* Get the premat */ ED_armature_ebone_to_mat3(curbone, temp); unit_m4(premat); /* mul_m4_m3m4 only sets 3x3 part */ mul_m4_m3m4(premat, temp, mat); mul_m4_v3(mat, curbone->head); mul_m4_v3(mat, curbone->tail); /* Get the postmat */ ED_armature_ebone_to_mat3(curbone, temp); copy_m4_m3(postmat, temp); /* Find the roll */ invert_m4_m4(imat, premat); mul_m4_m4m4(difmat, imat, postmat); curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]); } /* Fix Constraints and Other Links to this Bone and Armature */ joined_armature_fix_links(ob, base->object, pchan, curbone); /* Rename pchan */ BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name)); /* Jump Ship! */ BLI_remlink(curarm->edbo, curbone); BLI_addtail(arm->edbo, curbone); BLI_remlink(&opose->chanbase, pchan); BLI_addtail(&pose->chanbase, pchan); BKE_pose_channels_hash_free(opose); BKE_pose_channels_hash_free(pose); } ED_base_object_free_and_unlink(bmain, scene, base); } } CTX_DATA_END; DAG_relations_tag_update(bmain); /* because we removed object(s) */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; }
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-1) { 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-1) 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; }
void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, MTex *slot, int sizex, int sizey, int method) { Object *ob = CTX_data_active_object(C); wmJob *wm_job; ShaderPreview *sp; Scene *scene = CTX_data_scene(C); short id_type = GS(id->name); /* Use workspace render only for buttons Window, * since the other previews are related to the datablock. */ if (!check_engine_supports_preview(scene)) { return; } /* Only texture node preview is supported with Cycles. */ if (method == PR_NODE_RENDER && id_type != ID_TE) { return; } ED_preview_ensure_dbase(); wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Shader Preview", WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); sp = MEM_callocN(sizeof(ShaderPreview), "shader preview"); /* customdata for preview thread */ sp->scene = scene; sp->depsgraph = CTX_data_depsgraph(C); sp->owner = owner; sp->sizex = sizex; sp->sizey = sizey; sp->pr_method = method; sp->id = id; sp->id_copy = duplicate_ids(id); sp->own_id_copy = true; sp->parent = parent; sp->slot = slot; sp->bmain = CTX_data_main(C); Material *ma = NULL; /* hardcoded preview .blend for Eevee + Cycles, this should be solved * once with custom preview .blend path for external engines */ /* grease pencil use its own preview file */ if (GS(id->name) == ID_MA) { ma = (Material *)id; } if ((ma == NULL) || (ma->gp_style == NULL)) { sp->pr_main = G_pr_main; } else { sp->pr_main = G_pr_main_grease_pencil; } if (ob && ob->totcol) { copy_v4_v4(sp->color, ob->color); } else { ARRAY_SET_ITEMS(sp->color, 0.0f, 0.0f, 0.0f, 1.0f); } /* setup job */ WM_jobs_customdata_set(wm_job, sp, shader_preview_free); WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL); WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL); WM_jobs_start(CTX_wm_manager(C), wm_job); }
/* using context, starts job */ static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event) { /* new render clears all callbacks */ Main *mainp; Scene *scene = CTX_data_scene(C); SceneRenderLayer *srl = NULL; View3D *v3d = CTX_wm_view3d(C); Render *re; wmJob *steve; RenderJob *rj; Image *ima; int jobflag; const short is_animation = RNA_boolean_get(op->ptr, "animation"); const short is_write_still = RNA_boolean_get(op->ptr, "write_still"); struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; const char *name; /* only one render job at a time */ if (WM_jobs_test(CTX_wm_manager(C), scene)) return OPERATOR_CANCELLED; if (!RE_is_rendering_allowed(scene, camera_override, op->reports)) { return OPERATOR_CANCELLED; } if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) { BKE_report(op->reports, RPT_ERROR, "Can't write a single file with an animation format selected"); return OPERATOR_CANCELLED; } /* stop all running jobs, currently previews frustrate Render */ WM_jobs_stop_all(CTX_wm_manager(C)); /* get main */ if (G.rt == 101) { /* thread-safety experiment, copy main from the undo buffer */ mainp = BKE_undo_get_main(&scene); } else mainp = CTX_data_main(C); /* cancel animation playback */ if (ED_screen_animation_playing(CTX_wm_manager(C))) ED_screen_animation_play(C, 0, 0); /* handle UI stuff */ WM_cursor_wait(1); /* flush multires changes (for sculpt) */ multires_force_render_update(CTX_data_active_object(C)); /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into * the output rendering. We can't put that into RE_BlenderFrame, * since sequence rendering can call that recursively... (peter) */ seq_stripelem_cache_cleanup(); /* get editmode results */ ED_object_exit_editmode(C, 0); /* 0 = does not exit editmode */ // store spare // get view3d layer, local layer, make this nice api call to render // store spare /* ensure at least 1 area shows result */ render_view_open(C, event->x, event->y); jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS; /* custom scene and single layer re-render */ screen_render_scene_layer_set(op, mainp, &scene, &srl); if (RNA_struct_property_is_set(op->ptr, "layer")) jobflag |= WM_JOB_SUSPEND; /* job custom data */ rj = MEM_callocN(sizeof(RenderJob), "render job"); rj->main = mainp; rj->scene = scene; rj->win = CTX_wm_window(C); rj->srl = srl; rj->camera_override = camera_override; rj->lay = (v3d) ? v3d->lay : scene->lay; rj->anim = is_animation; rj->write_still = is_write_still && !is_animation; rj->iuser.scene = scene; rj->iuser.ok = 1; rj->reports = op->reports; /* setup job */ if (RE_seq_render_active(scene, &scene->r)) name = "Sequence Render"; else name = "Render"; steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, name, jobflag); WM_jobs_customdata(steve, rj, render_freejob); WM_jobs_timer(steve, 0.2, NC_SCENE | ND_RENDER_RESULT, 0); WM_jobs_callbacks(steve, render_startjob, NULL, NULL, render_endjob); /* get a render result image, and make sure it is empty */ ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); BKE_image_backup_render(rj->scene, ima); rj->image = ima; /* setup new render */ re = RE_NewRender(scene->id.name); RE_test_break_cb(re, rj, render_breakjob); RE_draw_lock_cb(re, rj, render_drawlock); RE_display_draw_cb(re, rj, image_rect_update); RE_stats_draw_cb(re, rj, image_renderinfo_cb); RE_progress_cb(re, rj, render_progress_update); rj->re = re; G.afbreek = 0; WM_jobs_start(CTX_wm_manager(C), steve); WM_cursor_wait(0); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); /* we set G.rendering here already instead of only in the job, this ensure * main loop or other scene updates are disabled in time, since they may * have started before the job thread */ G.rendering = 1; /* add modal handler for ESC */ WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; }
static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); // Object *obedit= CTX_data_edit_object(C); View3D *v3d= CTX_wm_view3d(C); // BoundBox *bb; Object *ob= OBACT; TransformProperties *tfp= v3d->properties_storage; switch(event) { case B_REDR: ED_area_tag_redraw(CTX_wm_area(C)); return; /* no notifier! */ case B_OBJECTPANEL: DAG_id_tag_update(&ob->id, OB_RECALC_OB); break; case B_OBJECTPANELMEDIAN: if(ob) { v3d_editvertex_buts(NULL, v3d, ob, 1.0); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } break; /* note; this case also used for parbone */ case B_OBJECTPANELPARENT: if(ob) { if(ob->id.lib || test_parent_loop(ob->parent, ob) ) ob->parent= NULL; else { DAG_scene_sort(bmain, scene); DAG_id_tag_update(&ob->id, OB_RECALC_OB); } } break; case B_ARMATUREPANEL3: // rotate button on channel { bPoseChannel *pchan; float eul[3]; pchan= get_active_posechannel(ob); if (!pchan) return; /* make a copy to eul[3], to allow TAB on buttons to work */ eul[0]= (float)M_PI*tfp->ob_eul[0]/180.0f; eul[1]= (float)M_PI*tfp->ob_eul[1]/180.0f; eul[2]= (float)M_PI*tfp->ob_eul[2]/180.0f; if (pchan->rotmode == ROT_MODE_AXISANGLE) { float quat[4]; /* convert to axis-angle, passing through quats */ eul_to_quat( quat,eul); quat_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,quat); } else if (pchan->rotmode == ROT_MODE_QUAT) eul_to_quat( pchan->quat,eul); else copy_v3_v3(pchan->eul, eul); } /* no break, pass on */ case B_ARMATUREPANEL2: { ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } break; case B_TRANSFORMSPACEADD: { char names[sizeof(((TransformOrientation *)NULL)->name)]= ""; BIF_createTransformOrientation(C, NULL, names, 1, 0); break; } case B_TRANSFORMSPACECLEAR: BIF_clearTransformOrientation(C); break; #if 0 // XXX case B_WEIGHT0_0: wpaint->weight = 0.0f; break; case B_WEIGHT1_4: wpaint->weight = 0.25f; break; case B_WEIGHT1_2: wpaint->weight = 0.5f; break; case B_WEIGHT3_4: wpaint->weight = 0.75f; break; case B_WEIGHT1_0: wpaint->weight = 1.0f; break; case B_OPA1_8: wpaint->a = 0.125f; break; case B_OPA1_4: wpaint->a = 0.25f; break; case B_OPA1_2: wpaint->a = 0.5f; break; case B_OPA3_4: wpaint->a = 0.75f; break; case B_OPA1_0: wpaint->a = 1.0f; break; #endif case B_CLR_WPAINT: // if(!multires_level1_test()) { { bDeformGroup *defGroup = BLI_findlink(&ob->defbase, ob->actdef-1); if(defGroup) { Mesh *me= ob->data; int a; for(a=0; a<me->totvert; a++) ED_vgroup_vert_remove (ob, defGroup, a); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } } break; case B_RV3D_LOCKED: case B_RV3D_BOXVIEW: case B_RV3D_BOXCLIP: { ScrArea *sa= CTX_wm_area(C); ARegion *ar= sa->regionbase.last; RegionView3D *rv3d; short viewlock; ar= ar->prev; rv3d= ar->regiondata; viewlock= rv3d->viewlock; if((viewlock & RV3D_LOCKED)==0) viewlock= 0; else if((viewlock & RV3D_BOXVIEW)==0) viewlock &= ~RV3D_BOXCLIP; for(; ar; ar= ar->prev) { if(ar->alignment==RGN_ALIGN_QSPLIT) { rv3d= ar->regiondata; rv3d->viewlock= viewlock; } } if(rv3d->viewlock & RV3D_BOXVIEW) view3d_boxview_copy(sa, sa->regionbase.last); ED_area_tag_redraw(sa); } break; } /* default for now */ WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, ob); }
static int open_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); bScreen *screen = CTX_wm_screen(C); Main *bmain = CTX_data_main(C); PropertyPointerRNA *pprop; PointerRNA idptr; MovieClip *clip = NULL; char str[FILE_MAX]; if (RNA_collection_length(op->ptr, "files")) { PointerRNA fileptr; PropertyRNA *prop; char dir_only[FILE_MAX], file_only[FILE_MAX]; bool relative = RNA_boolean_get(op->ptr, "relative_path"); RNA_string_get(op->ptr, "directory", dir_only); if (relative) BLI_path_rel(dir_only, G.main->name); prop = RNA_struct_find_property(op->ptr, "files"); RNA_property_collection_lookup_int(op->ptr, prop, 0, &fileptr); RNA_string_get(&fileptr, "name", file_only); BLI_join_dirfile(str, sizeof(str), dir_only, file_only); } else { BKE_report(op->reports, RPT_ERROR, "No files selected to be opened"); return OPERATOR_CANCELLED; } /* default to frame 1 if there's no scene in context */ errno = 0; clip = BKE_movieclip_file_add(bmain, str); if (!clip) { if (op->customdata) MEM_freeN(op->customdata); BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s", str, errno ? strerror(errno) : TIP_("unsupported movie clip format")); return OPERATOR_CANCELLED; } if (!op->customdata) open_init(C, op); /* hook into UI */ pprop = op->customdata; if (pprop->prop) { /* when creating new ID blocks, use is already 1, but RNA * pointer se also increases user, so this compensates it */ clip->id.us--; RNA_id_pointer_create(&clip->id, &idptr); RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); RNA_property_update(C, &pprop->ptr, pprop->prop); } else if (sc) { ED_space_clip_set_clip(C, screen, sc, clip); } WM_event_add_notifier(C, NC_MOVIECLIP | NA_ADDED, clip); MEM_freeN(op->customdata); return OPERATOR_FINISHED; }
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); OGLRender *oglrender = op->customdata; Scene *scene = oglrender->scene; ImBuf *ibuf, *ibuf_save = NULL; void *lock; char name[FILE_MAX]; int ok = 0; const short view_context = (oglrender->v3d != NULL); Object *camera = NULL; int is_movie; /* go to next frame */ if (CFRA < oglrender->nfra) CFRA++; while (CFRA < oglrender->nfra) { unsigned int lay = screen_opengl_layers(oglrender); if (lay & 0xFF000000) lay &= 0xFF000000; BKE_scene_update_for_newframe(bmain, scene, lay); CFRA++; } is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype); if (!is_movie) { BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, TRUE); if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) { BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name); ok = true; goto finally; } } WM_cursor_time(oglrender->win, scene->r.cfra); BKE_scene_update_for_newframe(bmain, scene, screen_opengl_layers(oglrender)); if (view_context) { if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera && oglrender->v3d->scenelock) { /* since BKE_scene_update_for_newframe() is used rather * then ED_update_for_newframe() the camera needs to be set */ if (BKE_scene_camera_switch_update(scene)) { oglrender->v3d->camera = scene->camera; } camera = oglrender->v3d->camera; } } else { BKE_scene_camera_switch_update(scene); camera = scene->camera; } /* render into offscreen buffer */ screen_opengl_render_apply(oglrender); /* save to disk */ ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock); if (ibuf) { int needs_free = FALSE; ibuf_save = ibuf; if (is_movie || !BKE_imtype_requires_linear_float(scene->r.im_format.imtype)) { ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &scene->view_settings, &scene->display_settings, &scene->r.im_format); needs_free = TRUE; } /* color -> grayscale */ /* editing directly would alter the render view */ if (scene->r.im_format.planes == R_IMF_PLANES_BW) { ImBuf *ibuf_bw = IMB_dupImBuf(ibuf_save); IMB_color_to_bw(ibuf_bw); if (needs_free) IMB_freeImBuf(ibuf_save); ibuf_save = ibuf_bw; } else { /* this is lightweight & doesnt re-alloc the buffers, only do this * to save the correct bit depth since the image is always RGBA */ ImBuf *ibuf_cpy = IMB_allocImBuf(ibuf_save->x, ibuf_save->y, scene->r.im_format.planes, 0); ibuf_cpy->rect = ibuf_save->rect; ibuf_cpy->rect_float = ibuf_save->rect_float; ibuf_cpy->zbuf_float = ibuf_save->zbuf_float; if (needs_free) { ibuf_cpy->mall = ibuf_save->mall; ibuf_save->mall = 0; IMB_freeImBuf(ibuf_save); } ibuf_save = ibuf_cpy; } if (is_movie) { ok = oglrender->mh->append_movie(&scene->r, PSFRA, CFRA, (int *)ibuf_save->rect, oglrender->sizex, oglrender->sizey, oglrender->reports); if (ok) { printf("Append frame %d", scene->r.cfra); BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra); } } else { ok = BKE_imbuf_write_stamp(scene, camera, ibuf_save, name, &scene->r.im_format); if (ok == 0) { printf("Write error: cannot save %s\n", name); BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name); } else { printf("Saved: %s", name); BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name); } } if (needs_free) IMB_freeImBuf(ibuf_save); } BKE_image_release_ibuf(oglrender->ima, ibuf, lock); /* movie stats prints have no line break */ printf("\n"); finally: /* Step the frame and bail early if needed */ /* go to next frame */ oglrender->nfra += scene->r.frame_step; /* stop at the end or on error */ if (CFRA >= PEFRA || !ok) { screen_opengl_render_end(C, op->customdata); return 0; } return 1; }
static PointerRNA rna_Context_main_get(PointerRNA *ptr) { bContext *C= (bContext*)ptr->data; return rna_pointer_inherit_refine(ptr, &RNA_BlendData, CTX_data_main(C)); }
void draw_image_seq(const bContext* C, Scene *scene, ARegion *ar, SpaceSeq *sseq, int cfra, int frame_ofs) { struct Main *bmain= CTX_data_main(C); struct ImBuf *ibuf= NULL; struct ImBuf *scope= NULL; struct View2D *v2d = &ar->v2d; int rectx, recty; float viewrectx, viewrecty; float render_size = 0.0; float proxy_size = 100.0; GLuint texid; GLuint last_texid; SeqRenderData context; render_size = sseq->render_size; if (render_size == 0) { render_size = scene->r.size; } else { proxy_size = render_size; } if (render_size < 0) { return; } viewrectx = (render_size*(float)scene->r.xsch)/100.0f; viewrecty = (render_size*(float)scene->r.ysch)/100.0f; rectx = viewrectx + 0.5f; recty = viewrecty + 0.5f; if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { viewrectx *= scene->r.xasp / scene->r.yasp; viewrectx /= proxy_size / 100.0f; viewrecty /= proxy_size / 100.0f; } if(frame_ofs == 0) { /* XXX TODO: take color from theme */ glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); } /* without this colors can flicker from previous opengl state */ glColor4ub(255, 255, 255, 255); UI_view2d_totRect_set(v2d, viewrectx + 0.5f, viewrecty + 0.5f); UI_view2d_curRect_validate(v2d); /* only initialize the preview if a render is in progress */ if(G.rendering) return; context = seq_new_render_data(bmain, scene, rectx, recty, proxy_size); if (special_seq_update) ibuf= give_ibuf_seq_direct(context, cfra + frame_ofs, special_seq_update); else if (!U.prefetchframes) // XXX || (G.f & G_PLAYANIM) == 0) { ibuf= (ImBuf *)give_ibuf_seq(context, cfra + frame_ofs, sseq->chanshown); else ibuf= (ImBuf *)give_ibuf_seq_threaded(context, cfra + frame_ofs, sseq->chanshown); if(ibuf==NULL) return; if(ibuf->rect==NULL && ibuf->rect_float == NULL) return; switch(sseq->mainb) { case SEQ_DRAW_IMG_IMBUF: if (sseq->zebra != 0) { scope = make_zebra_view_from_ibuf(ibuf, sseq->zebra); } break; case SEQ_DRAW_IMG_WAVEFORM: if ((sseq->flag & SEQ_DRAW_COLOR_SEPERATED) != 0) { scope = make_sep_waveform_view_from_ibuf(ibuf); } else { scope = make_waveform_view_from_ibuf(ibuf); } break; case SEQ_DRAW_IMG_VECTORSCOPE: scope = make_vectorscope_view_from_ibuf(ibuf); break; case SEQ_DRAW_IMG_HISTOGRAM: scope = make_histogram_view_from_ibuf(ibuf); break; } if (scope) { IMB_freeImBuf(ibuf); ibuf = scope; } if(ibuf->rect_float && ibuf->rect==NULL) { IMB_rect_from_float(ibuf); } /* setting up the view - actual drawing starts here */ UI_view2d_view_ortho(v2d); last_texid= glaGetOneInteger(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D); glGenTextures(1, (GLuint *)&texid); glBindTexture(GL_TEXTURE_2D, texid); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); glBegin(GL_QUADS); if(frame_ofs) { rctf tot_clip; tot_clip.xmin= v2d->tot.xmin + (ABS(v2d->tot.xmax - v2d->tot.xmin) * scene->ed->over_border.xmin); tot_clip.ymin= v2d->tot.ymin + (ABS(v2d->tot.ymax - v2d->tot.ymin) * scene->ed->over_border.ymin); tot_clip.xmax= v2d->tot.xmin + (ABS(v2d->tot.xmax - v2d->tot.xmin) * scene->ed->over_border.xmax); tot_clip.ymax= v2d->tot.ymin + (ABS(v2d->tot.ymax - v2d->tot.ymin) * scene->ed->over_border.ymax); glTexCoord2f(scene->ed->over_border.xmin, scene->ed->over_border.ymin); glVertex2f(tot_clip.xmin, tot_clip.ymin); glTexCoord2f(scene->ed->over_border.xmin, scene->ed->over_border.ymax); glVertex2f(tot_clip.xmin, tot_clip.ymax); glTexCoord2f(scene->ed->over_border.xmax, scene->ed->over_border.ymax); glVertex2f(tot_clip.xmax, tot_clip.ymax); glTexCoord2f(scene->ed->over_border.xmax, scene->ed->over_border.ymin); glVertex2f(tot_clip.xmax, tot_clip.ymin); } else { glTexCoord2f(0.0f, 0.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymin); glTexCoord2f(0.0f, 1.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymax); glTexCoord2f(1.0f, 1.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymax); glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin); } glEnd( ); glBindTexture(GL_TEXTURE_2D, last_texid); glDisable(GL_TEXTURE_2D); glDeleteTextures(1, &texid); if(sseq->mainb == SEQ_DRAW_IMG_IMBUF) { float x1 = v2d->tot.xmin; float y1 = v2d->tot.ymin; float x2 = v2d->tot.xmax; float y2 = v2d->tot.ymax; /* border */ setlinestyle(3); UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0); glBegin(GL_LINE_LOOP); glVertex2f(x1-0.5f, y1-0.5f); glVertex2f(x1-0.5f, y2+0.5f); glVertex2f(x2+0.5f, y2+0.5f); glVertex2f(x2+0.5f, y1-0.5f); glEnd(); /* safety border */ if ((sseq->flag & SEQ_DRAW_SAFE_MARGINS) != 0) { float fac= 0.1; float a= fac*(x2-x1); x1+= a; x2-= a; a= fac*(y2-y1); y1+= a; y2-= a; glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); uiSetRoundBox(UI_CNR_ALL); uiDrawBox(GL_LINE_LOOP, x1, y1, x2, y2, 12.0); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } setlinestyle(0); } /* draw grease-pencil (image aligned) */ // if (sseq->flag & SEQ_DRAW_GPENCIL) // XXX draw_gpencil_2dimage(sa, ibuf); IMB_freeImBuf(ibuf); /* draw grease-pencil (screen aligned) */ // if (sseq->flag & SEQ_DRAW_GPENCIL) // XXX draw_gpencil_view2d(sa, 0); /* ortho at pixel level */ UI_view2d_view_restore(C); }
extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *cam_frame, int always_use_expand_framing) { /* context values */ struct wmWindowManager *wm= CTX_wm_manager(C); struct wmWindow *win= CTX_wm_window(C); struct Scene *startscene= CTX_data_scene(C); struct Main* maggie1= CTX_data_main(C); RAS_Rect area_rect; area_rect.SetLeft(cam_frame->xmin); area_rect.SetBottom(cam_frame->ymin); area_rect.SetRight(cam_frame->xmax); area_rect.SetTop(cam_frame->ymax); int exitrequested = KX_EXIT_REQUEST_NO_REQUEST; Main* blenderdata = maggie1; char* startscenename = startscene->id.name+2; char pathname[FILE_MAXDIR+FILE_MAXFILE], oldsce[FILE_MAXDIR+FILE_MAXFILE]; STR_String exitstring = ""; BlendFileData *bfd= NULL; BLI_strncpy(pathname, blenderdata->name, sizeof(pathname)); BLI_strncpy(oldsce, G.main->name, sizeof(oldsce)); #ifdef WITH_PYTHON resetGamePythonPath(); // need this so running a second time wont use an old blendfiles path setGamePythonPath(G.main->name); // Acquire Python's GIL (global interpreter lock) // so we can safely run Python code and API calls PyGILState_STATE gilstate = PyGILState_Ensure(); PyObject *pyGlobalDict = PyDict_New(); /* python utility storage, spans blend file loading */ #endif bgl::InitExtensions(true); // VBO code for derived mesh is not compatible with BGE (couldn't find why), so disable int disableVBO = (U.gameflags & USER_DISABLE_VBO); U.gameflags |= USER_DISABLE_VBO; // Globals to be carried on over blender files GlobalSettings gs; gs.matmode= startscene->gm.matmode; gs.glslflag= startscene->gm.flag; do { View3D *v3d= CTX_wm_view3d(C); RegionView3D *rv3d= CTX_wm_region_view3d(C); // get some preferences SYS_SystemHandle syshandle = SYS_GetSystem(); bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0); bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0); bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0); bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); bool animation_record = (SYS_GetCommandLineInt(syshandle, "animation_record", 0) != 0); bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0) && GPU_display_list_support(); #ifdef WITH_PYTHON bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 0) != 0); #endif // bool novertexarrays = (SYS_GetCommandLineInt(syshandle, "novertexarrays", 0) != 0); bool mouse_state = startscene->gm.flag & GAME_SHOW_MOUSE; bool restrictAnimFPS = startscene->gm.flag & GAME_RESTRICT_ANIM_UPDATES; if (animation_record) usefixed= false; /* override since you don't want to run full-speed for sim recording */ // create the canvas and rasterizer RAS_ICanvas* canvas = new KX_BlenderCanvas(wm, win, area_rect, ar); // default mouse state set on render panel if (mouse_state) canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); else canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); // Setup vsync int previous_vsync = canvas->GetSwapInterval(); if (startscene->gm.vsync == VSYNC_ADAPTIVE) canvas->SetSwapInterval(-1); else canvas->SetSwapInterval((startscene->gm.vsync == VSYNC_ON) ? 1 : 0); RAS_IRasterizer* rasterizer = NULL; //Don't use displaylists with VBOs //If auto starts using VBOs, make sure to check for that here if (displaylists && startscene->gm.raster_storage != RAS_STORE_VBO) rasterizer = new RAS_ListRasterizer(canvas, true, startscene->gm.raster_storage); else rasterizer = new RAS_OpenGLRasterizer(canvas, startscene->gm.raster_storage); RAS_IRasterizer::MipmapOption mipmapval = rasterizer->GetMipmapping(); // create the inputdevices KX_BlenderKeyboardDevice* keyboarddevice = new KX_BlenderKeyboardDevice(); KX_BlenderMouseDevice* mousedevice = new KX_BlenderMouseDevice(); // create a networkdevice NG_NetworkDeviceInterface* networkdevice = new NG_LoopBackNetworkDeviceInterface(); // // create a ketsji/blendersystem (only needed for timing and stuff) KX_BlenderSystem* kxsystem = new KX_BlenderSystem(); // create the ketsjiengine KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem); // set the devices ketsjiengine->SetKeyboardDevice(keyboarddevice); ketsjiengine->SetMouseDevice(mousedevice); ketsjiengine->SetNetworkDevice(networkdevice); ketsjiengine->SetCanvas(canvas); ketsjiengine->SetRasterizer(rasterizer); ketsjiengine->SetUseFixedTime(usefixed); ketsjiengine->SetTimingDisplay(frameRate, profile, properties); ketsjiengine->SetRestrictAnimationFPS(restrictAnimFPS); KX_KetsjiEngine::SetExitKey(ConvertKeyCode(startscene->gm.exitkey)); //set the global settings (carried over if restart/load new files) ketsjiengine->SetGlobalSettings(&gs); #ifdef WITH_PYTHON CValue::SetDeprecationWarnings(nodepwarnings); #endif //lock frame and camera enabled - storing global values int tmp_lay= startscene->lay; Object *tmp_camera = startscene->camera; if (v3d->scenelock==0) { startscene->lay= v3d->lay; startscene->camera= v3d->camera; } // some blender stuff float camzoom; int draw_letterbox = 0; if (rv3d->persp==RV3D_CAMOB) { if (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) { /* Letterbox */ camzoom = 1.0f; draw_letterbox = 1; } else { camzoom = 1.0f / BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); } } else { camzoom = 2.0; } ketsjiengine->SetDrawType(v3d->drawtype); ketsjiengine->SetCameraZoom(camzoom); // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file if (exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME || exitrequested == KX_EXIT_REQUEST_RESTART_GAME) { exitrequested = KX_EXIT_REQUEST_NO_REQUEST; if (bfd) BLO_blendfiledata_free(bfd); char basedpath[FILE_MAX]; // base the actuator filename with respect // to the original file working directory if (exitstring != "") BLI_strncpy(basedpath, exitstring.ReadPtr(), sizeof(basedpath)); // load relative to the last loaded file, this used to be relative // to the first file but that makes no sense, relative paths in // blend files should be relative to that file, not some other file // that happened to be loaded first BLI_path_abs(basedpath, pathname); bfd = load_game_data(basedpath); // if it wasn't loaded, try it forced relative if (!bfd) { // just add "//" in front of it char temppath[FILE_MAX] = "//"; BLI_strncpy(temppath + 2, basedpath, FILE_MAX - 2); BLI_path_abs(temppath, pathname); bfd = load_game_data(temppath); } // if we got a loaded blendfile, proceed if (bfd) { blenderdata = bfd->main; startscenename = bfd->curscene->id.name + 2; if (blenderdata) { BLI_strncpy(G.main->name, blenderdata->name, sizeof(G.main->name)); BLI_strncpy(pathname, blenderdata->name, sizeof(pathname)); #ifdef WITH_PYTHON setGamePythonPath(G.main->name); #endif } } // else forget it, we can't find it else { exitrequested = KX_EXIT_REQUEST_QUIT_GAME; } } Scene *scene= bfd ? bfd->curscene : (Scene *)BLI_findstring(&blenderdata->scene, startscenename, offsetof(ID, name) + 2); if (scene) { int startFrame = scene->r.cfra; ketsjiengine->SetAnimRecordMode(animation_record, startFrame); // Quad buffered needs a special window. if (scene->gm.stereoflag == STEREO_ENABLED) { if (scene->gm.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) scene->gm.stereomode); rasterizer->SetEyeSeparation(scene->gm.eyeseparation); } rasterizer->SetBackColor(scene->gm.framing.col[0], scene->gm.framing.col[1], scene->gm.framing.col[2], 0.0f); } if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME) { if (rv3d->persp != RV3D_CAMOB) { ketsjiengine->EnableCameraOverride(startscenename); ketsjiengine->SetCameraOverrideUseOrtho((rv3d->persp == RV3D_ORTHO)); ketsjiengine->SetCameraOverrideProjectionMatrix(MT_CmMatrix4x4(rv3d->winmat)); ketsjiengine->SetCameraOverrideViewMatrix(MT_CmMatrix4x4(rv3d->viewmat)); if (rv3d->persp == RV3D_ORTHO) { ketsjiengine->SetCameraOverrideClipping(v3d->near, v3d->far); } else { ketsjiengine->SetCameraOverrideClipping(v3d->near, v3d->far); } ketsjiengine->SetCameraOverrideLens(v3d->lens); } // create a scene converter, create and convert the startingscene KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(blenderdata, ketsjiengine); ketsjiengine->SetSceneConverter(sceneconverter); sceneconverter->addInitFromFrame=false; if (always_use_expand_framing) sceneconverter->SetAlwaysUseExpandFraming(true); bool usemat = false, useglslmat = false; if (GLEW_ARB_multitexture && GLEW_VERSION_1_1) usemat = true; if (GPU_glsl_support()) useglslmat = true; else if (gs.matmode == GAME_MAT_GLSL) usemat = false; if (usemat) sceneconverter->SetMaterials(true); if (useglslmat && (gs.matmode == GAME_MAT_GLSL)) sceneconverter->SetGLSLMaterials(true); if (scene->gm.flag & GAME_NO_MATERIAL_CACHING) sceneconverter->SetCacheMaterials(false); KX_Scene* startscene = new KX_Scene(keyboarddevice, mousedevice, networkdevice, startscenename, scene, canvas); #ifdef WITH_PYTHON // some python things PyObject *gameLogic, *gameLogic_keys; setupGamePython(ketsjiengine, startscene, blenderdata, pyGlobalDict, &gameLogic, &gameLogic_keys, 0, NULL); #endif // WITH_PYTHON //initialize Dome Settings if (scene->gm.stereoflag == STEREO_DOME) ketsjiengine->InitDome(scene->gm.dome.res, scene->gm.dome.mode, scene->gm.dome.angle, scene->gm.dome.resbuf, scene->gm.dome.tilt, scene->gm.dome.warptext); // initialize 3D Audio Settings AUD_I3DDevice* dev = AUD_get3DDevice(); if (dev) { dev->setSpeedOfSound(scene->audio.speed_of_sound); dev->setDopplerFactor(scene->audio.doppler_factor); dev->setDistanceModel(AUD_DistanceModel(scene->audio.distance_model)); } // from see blender.c: // FIXME: this version patching should really be part of the file-reading code, // but we still get too many unrelated data-corruption crashes otherwise... if (blenderdata->versionfile < 250) do_versions_ipos_to_animato(blenderdata); if (sceneconverter) { // convert and add scene sceneconverter->ConvertScene( startscene, rasterizer, canvas); ketsjiengine->AddScene(startscene); // init the rasterizer rasterizer->Init(); // start the engine ketsjiengine->StartEngine(true); // Set the animation playback rate for ipo's and actions // the framerate below should patch with FPS macro defined in blendef.h // Could be in StartEngine set the framerate, we need the scene to do this ketsjiengine->SetAnimFrameRate(FPS); #ifdef WITH_PYTHON char *python_main = NULL; pynextframestate.state = NULL; pynextframestate.func = NULL; python_main = KX_GetPythonMain(scene); // the mainloop printf("\nBlender Game Engine Started\n"); if (python_main) { char *python_code = KX_GetPythonCode(blenderdata, python_main); if (python_code) { ketsjinextframestate.ketsjiengine = ketsjiengine; ketsjinextframestate.C = C; ketsjinextframestate.win = win; ketsjinextframestate.scene = scene; ketsjinextframestate.ar = ar; ketsjinextframestate.keyboarddevice = keyboarddevice; ketsjinextframestate.mousedevice = mousedevice; ketsjinextframestate.draw_letterbox = draw_letterbox; pynextframestate.state = &ketsjinextframestate; pynextframestate.func = &BL_KetsjiPyNextFrame; printf("Yielding control to Python script '%s'...\n", python_main); PyRun_SimpleString(python_code); printf("Exit Python script '%s'\n", python_main); MEM_freeN(python_code); } } else #endif /* WITH_PYTHON */ { while (!exitrequested) { exitrequested = BL_KetsjiNextFrame(ketsjiengine, C, win, scene, ar, keyboarddevice, mousedevice, draw_letterbox); } } printf("Blender Game Engine Finished\n"); exitstring = ketsjiengine->GetExitString(); #ifdef WITH_PYTHON if (python_main) MEM_freeN(python_main); #endif /* WITH_PYTHON */ gs = *(ketsjiengine->GetGlobalSettings()); // when exiting the mainloop #ifdef WITH_PYTHON // Clears the dictionary by hand: // This prevents, extra references to global variables // inside the GameLogic dictionary when the python interpreter is finalized. // which allows the scene to safely delete them :) // see: (space.c)->start_game //PyDict_Clear(PyModule_GetDict(gameLogic)); // Keep original items, means python plugins will autocomplete members PyObject *gameLogic_keys_new = PyDict_Keys(PyModule_GetDict(gameLogic)); const Py_ssize_t numitems= PyList_GET_SIZE(gameLogic_keys_new); Py_ssize_t listIndex; for (listIndex=0; listIndex < numitems; listIndex++) { PyObject *item = PyList_GET_ITEM(gameLogic_keys_new, listIndex); if (!PySequence_Contains(gameLogic_keys, item)) { PyDict_DelItem( PyModule_GetDict(gameLogic), item); } } Py_DECREF(gameLogic_keys_new); gameLogic_keys_new = NULL; #endif ketsjiengine->StopEngine(); #ifdef WITH_PYTHON exitGamePythonScripting(); #endif networkdevice->Disconnect(); } if (sceneconverter) { delete sceneconverter; sceneconverter = NULL; } #ifdef WITH_PYTHON Py_DECREF(gameLogic_keys); gameLogic_keys = NULL; #endif } //lock frame and camera enabled - restoring global values if (v3d->scenelock==0) { startscene->lay= tmp_lay; startscene->camera= tmp_camera; } if (exitrequested != KX_EXIT_REQUEST_OUTSIDE) { // set the cursor back to normal canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); // set mipmap setting back to its original value rasterizer->SetMipmapping(mipmapval); } // clean up some stuff if (ketsjiengine) { delete ketsjiengine; ketsjiengine = NULL; } if (kxsystem) { delete kxsystem; kxsystem = NULL; } if (networkdevice) { delete networkdevice; networkdevice = NULL; } if (keyboarddevice) { delete keyboarddevice; keyboarddevice = NULL; } if (mousedevice) { delete mousedevice; mousedevice = NULL; } if (rasterizer) { delete rasterizer; rasterizer = NULL; } if (canvas) { canvas->SetSwapInterval(previous_vsync); // Set the swap interval back delete canvas; canvas = NULL; } // stop all remaining playing sounds AUD_getDevice()->stopAll(); } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME); if (!disableVBO) U.gameflags &= ~USER_DISABLE_VBO; if (bfd) BLO_blendfiledata_free(bfd); BLI_strncpy(G.main->name, oldsce, sizeof(G.main->name)); #ifdef WITH_PYTHON Py_DECREF(pyGlobalDict); // Release Python's GIL PyGILState_Release(gilstate); #endif }
static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) { wmOperatorType *ot; int error_val = 0; PointerRNA ptr; int operator_ret = OPERATOR_CANCELLED; const char *opname; const char *context_str = NULL; PyObject *kw = NULL; /* optional args */ PyObject *context_dict = NULL; /* optional args */ PyObject *context_dict_back; /* note that context is an int, python does the conversion in this case */ int context = WM_OP_EXEC_DEFAULT; int is_undo = false; /* XXX Todo, work out a better solution for passing on context, * could make a tuple from self and pack the name and Context into it... */ bContext *C = (bContext *)BPy_GetContext(); if (C == NULL) { PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators"); return NULL; } if (!PyArg_ParseTuple(args, "sO|O!si:_bpy.ops.call", &opname, &context_dict, &PyDict_Type, &kw, &context_str, &is_undo)) { return NULL; } ot = WM_operatortype_find(opname, true); if (ot == NULL) { PyErr_Format(PyExc_AttributeError, "Calling operator \"bpy.ops.%s\" error, " "could not be found", opname); return NULL; } if (!pyrna_write_check()) { PyErr_Format(PyExc_RuntimeError, "Calling operator \"bpy.ops.%s\" error, " "can't modify blend data in this state (drawing/rendering)", opname); return NULL; } if (context_str) { if (RNA_enum_value_from_id(operator_context_items, context_str, &context) == 0) { char *enum_str = BPy_enum_as_string(operator_context_items); PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s\" error, " "expected a string enum in (%s)", opname, enum_str); MEM_freeN(enum_str); return NULL; } } if (context_dict == NULL || context_dict == Py_None) { context_dict = NULL; } else if (!PyDict_Check(context_dict)) { PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s\" error, " "custom context expected a dict or None, got a %.200s", opname, Py_TYPE(context_dict)->tp_name); return NULL; } context_dict_back = CTX_py_dict_get(C); CTX_py_dict_set(C, (void *)context_dict); Py_XINCREF(context_dict); /* so we done loose it */ if (WM_operator_poll_context((bContext *)C, ot, context) == false) { const char *msg = CTX_wm_operator_poll_msg_get(C); PyErr_Format(PyExc_RuntimeError, "Operator bpy.ops.%.200s.poll() %.200s", opname, msg ? msg : "failed, context is incorrect"); CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */ error_val = -1; } else { WM_operator_properties_create_ptr(&ptr, ot); WM_operator_properties_sanitize(&ptr, 0); if (kw && PyDict_Size(kw)) error_val = pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); if (error_val == 0) { ReportList *reports; reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); BKE_reports_init(reports, RPT_STORE | RPT_OP_HOLD); /* own so these don't move into global reports */ #ifdef BPY_RELEASE_GIL /* release GIL, since a thread could be started from an operator * that updates a driver */ /* note: I have not seen any examples of code that does this * so it may not be officially supported but seems to work ok. */ { PyThreadState *ts = PyEval_SaveThread(); #endif operator_ret = WM_operator_call_py(C, ot, context, &ptr, reports, is_undo); #ifdef BPY_RELEASE_GIL /* regain GIL */ PyEval_RestoreThread(ts); } #endif error_val = BPy_reports_to_error(reports, PyExc_RuntimeError, false); /* operator output is nice to have in the terminal/console too */ if (!BLI_listbase_is_empty(&reports->list)) { Report *report; for (report = reports->list.first; report; report = report->next) { PySys_WriteStdout("%s: %s\n", report->typestr, report->message); } } BKE_reports_clear(reports); if ((reports->flag & RPT_FREE) == 0) { MEM_freeN(reports); } } WM_operator_properties_free(&ptr); #if 0 /* if there is some way to know an operator takes args we should use this */ { /* no props */ if (kw != NULL) { PyErr_Format(PyExc_AttributeError, "Operator \"%s\" does not take any args", opname); return NULL; } WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL); } #endif } /* restore with original context dict, probably NULL but need this for nested operator calls */ Py_XDECREF(context_dict); CTX_py_dict_set(C, (void *)context_dict_back); if (error_val == -1) { return NULL; } /* when calling bpy.ops.wm.read_factory_settings() bpy.data's main pointer is freed by clear_globals(), * further access will crash blender. setting context is not needed in this case, only calling because this * function corrects bpy.data (internal Main pointer) */ BPY_modules_update(C); /* needed for when WM_OT_read_factory_settings us called from within a script */ bpy_import_main_set(CTX_data_main(C)); /* return operator_ret as a bpy enum */ return pyrna_enum_bitfield_to_py(operator_return_items, operator_ret); }
static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) { SpaceOops *soops= CTX_wm_space_outliner(C); int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0; eOutliner_AnimDataOps event; short updateDeps = 0; /* check for invalid states */ if (soops == NULL) return OPERATOR_CANCELLED; event= RNA_enum_get(op->ptr, "type"); set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); if (datalevel != TSE_ANIM_DATA) return OPERATOR_CANCELLED; /* perform the core operation */ switch (event) { case OUTLINER_ANIMOP_SET_ACT: /* delegate once again... */ WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL); break; case OUTLINER_ANIMOP_CLEAR_ACT: /* clear active action - using standard rules */ outliner_do_data_operation(soops, datalevel, event, &soops->tree, unlinkact_animdata_cb); WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL); ED_undo_push(C, "Unlink action"); break; case OUTLINER_ANIMOP_REFRESH_DRV: outliner_do_data_operation(soops, datalevel, event, &soops->tree, refreshdrivers_animdata_cb); WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN, NULL); //ED_undo_push(C, "Refresh Drivers"); /* no undo needed - shouldn't have any impact? */ updateDeps = 1; break; case OUTLINER_ANIMOP_CLEAR_DRV: outliner_do_data_operation(soops, datalevel, event, &soops->tree, cleardrivers_animdata_cb); WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN, NULL); ED_undo_push(C, "Clear Drivers"); updateDeps = 1; break; default: // invalid break; } /* update dependencies */ if (updateDeps) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); /* rebuild depsgraph for the new deps */ DAG_scene_sort(bmain, scene); /* force an update of depsgraph */ DAG_ids_flush_update(bmain, 0); } return OPERATOR_FINISHED; }
static int outliner_object_operation_exec(bContext *C, wmOperator *op) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); SpaceOops *soops= CTX_wm_space_outliner(C); int event; const char *str= NULL; /* check for invalid states */ if (soops == NULL) return OPERATOR_CANCELLED; event= RNA_enum_get(op->ptr, "type"); if (event==1) { Scene *sce= scene; // to be able to delete, scenes are set... outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_cb); if (scene != sce) { ED_screen_set_scene(C, CTX_wm_screen(C), sce); } str= "Select Objects"; WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene); } else if (event==2) { outliner_do_object_operation(C, scene, soops, &soops->tree, object_deselect_cb); str= "Deselect Objects"; WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene); } else if (event==4) { outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb); /* XXX: tree management normally happens from draw_outliner(), but when * you're clicking to fast on Delete object from context menu in * outliner several mouse events can be handled in one cycle without * handling notifiers/redraw which leads to deleting the same object twice. * cleanup tree here to prevent such cases. */ outliner_cleanup_tree(soops); DAG_scene_sort(bmain, scene); str= "Delete Objects"; WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene); } else if (event==5) { /* disabled, see above enum (ton) */ outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb); str= "Localized Objects"; } else if (event==6) { outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb); str= "Toggle Visibility"; WM_event_add_notifier(C, NC_SCENE|ND_OB_VISIBLE, scene); } else if (event==7) { outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb); str= "Toggle Selectability"; WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene); } else if (event==8) { outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb); str= "Toggle Renderability"; WM_event_add_notifier(C, NC_SCENE|ND_OB_RENDER, scene); } else if (event==9) { outliner_do_object_operation(C, scene, soops, &soops->tree, item_rename_cb); str= "Rename Object"; } ED_undo_push(C, str); return OPERATOR_FINISHED; }
static bool python_script_exec( bContext *C, const char *fn, struct Text *text, struct ReportList *reports, const bool do_jump) { Main *bmain_old = CTX_data_main(C); PyObject *main_mod = NULL; PyObject *py_dict = NULL, *py_result = NULL; PyGILState_STATE gilstate; BLI_assert(fn || text); if (fn == NULL && text == NULL) { return 0; } bpy_context_set(C, &gilstate); PyC_MainModule_Backup(&main_mod); if (text) { char fn_dummy[FILE_MAXDIR]; bpy_text_filename_get(fn_dummy, sizeof(fn_dummy), text); if (text->compiled == NULL) { /* if it wasn't already compiled, do it now */ char *buf; PyObject *fn_dummy_py; fn_dummy_py = PyC_UnicodeFromByte(fn_dummy); buf = txt_to_buf(text); text->compiled = Py_CompileStringObject(buf, fn_dummy_py, Py_file_input, NULL, -1); MEM_freeN(buf); Py_DECREF(fn_dummy_py); if (PyErr_Occurred()) { if (do_jump) { python_script_error_jump_text(text); } BPY_text_free_code(text); } } if (text->compiled) { py_dict = PyC_DefaultNameSpace(fn_dummy); py_result = PyEval_EvalCode(text->compiled, py_dict, py_dict); } } else { FILE *fp = BLI_fopen(fn, "r"); if (fp) { py_dict = PyC_DefaultNameSpace(fn); #ifdef _WIN32 /* Previously we used PyRun_File to run directly the code on a FILE * object, but as written in the Python/C API Ref Manual, chapter 2, * 'FILE structs for different C libraries can be different and * incompatible'. * So now we load the script file data to a buffer */ { const char *pystring = "ns = globals().copy()\n" "with open(__file__, 'rb') as f: exec(compile(f.read(), __file__, 'exec'), ns)"; fclose(fp); py_result = PyRun_String(pystring, Py_file_input, py_dict, py_dict); } #else py_result = PyRun_File(fp, fn, Py_file_input, py_dict, py_dict); fclose(fp); #endif } else { PyErr_Format(PyExc_IOError, "Python file \"%s\" could not be opened: %s", fn, strerror(errno)); py_result = NULL; } } if (!py_result) { if (text) { if (do_jump) { /* ensure text is valid before use, the script may have freed its self */ Main *bmain_new = CTX_data_main(C); if ((bmain_old == bmain_new) && (BLI_findindex(&bmain_new->text, text) != -1)) { python_script_error_jump_text(text); } } } BPy_errors_to_report(reports); } else { Py_DECREF(py_result); } if (py_dict) { #ifdef PYMODULE_CLEAR_WORKAROUND PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItemString(PyThreadState_GET()->interp->modules, "__main__"); PyObject *dict_back = mmod->md_dict; /* freeing the module will clear the namespace, * gives problems running classes defined in this namespace being used later. */ mmod->md_dict = NULL; Py_DECREF(dict_back); #endif #undef PYMODULE_CLEAR_WORKAROUND } PyC_MainModule_Restore(main_mod); bpy_context_clear(C, &gilstate); return (py_result != NULL); }
static bool screen_opengl_render_init(bContext *C, wmOperator *op) { /* new render clears all callbacks */ wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); ScrArea *prevsa = CTX_wm_area(C); ARegion *prevar = CTX_wm_region(C); GPUOffScreen *ofs; OGLRender *oglrender; int sizex, sizey; bool is_view_context = RNA_boolean_get(op->ptr, "view_context"); const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); char err_out[256] = "unknown"; if (G.background) { BKE_report(op->reports, RPT_ERROR, "Cannot use OpenGL render in background mode (no opengl context)"); return false; } /* only one render job at a time */ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) return false; if (is_sequencer) { is_view_context = false; } else { /* ensure we have a 3d view */ if (!ED_view3d_context_activate(C)) { RNA_boolean_set(op->ptr, "view_context", false); is_view_context = false; } if (!is_view_context && scene->camera == NULL) { BKE_report(op->reports, RPT_ERROR, "Scene has no camera"); return false; } } if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) { BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected"); return false; } /* stop all running jobs, except screen one. currently previews frustrate Render */ WM_jobs_kill_all_except(wm, CTX_wm_screen(C)); /* create offscreen buffer */ sizex = (scene->r.size * scene->r.xsch) / 100; sizey = (scene->r.size * scene->r.ysch) / 100; /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ ofs = GPU_offscreen_create(sizex, sizey, err_out); if (!ofs) { BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out); return false; } /* allocate opengl render */ oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender"); op->customdata = oglrender; oglrender->ofs = ofs; oglrender->sizex = sizex; oglrender->sizey = sizey; oglrender->bmain = CTX_data_main(C); oglrender->scene = scene; oglrender->cfrao = scene->r.cfra; oglrender->write_still = is_write_still && !is_animation; oglrender->is_sequencer = is_sequencer; if (is_sequencer) { oglrender->sseq = CTX_wm_space_seq(C); } oglrender->prevsa = prevsa; oglrender->prevar = prevar; if (is_view_context) { ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->ar); /* so quad view renders camera */ oglrender->rv3d = oglrender->ar->regiondata; /* MUST be cleared on exit */ oglrender->scene->customdata_mask_modal = ED_view3d_datamask(oglrender->scene, oglrender->v3d); /* apply immediately in case we're rendering from a script, * running notifiers again will overwrite */ oglrender->scene->customdata_mask |= oglrender->scene->customdata_mask_modal; if (oglrender->v3d->fx_settings.fx_flag & (GPU_FX_FLAG_DOF | GPU_FX_FLAG_SSAO)) { oglrender->fx = GPU_fx_compositor_create(); } } /* create render */ oglrender->re = RE_NewRender(scene->id.name); /* create image and image user */ oglrender->ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(oglrender->ima, NULL, IMA_SIGNAL_FREE); BKE_image_backup_render(oglrender->scene, oglrender->ima); oglrender->iuser.scene = scene; oglrender->iuser.ok = 1; /* create render result */ RE_InitState(oglrender->re, NULL, &scene->r, NULL, sizex, sizey, NULL); /* create render views */ screen_opengl_views_setup(oglrender); /* wm vars */ oglrender->wm = wm; oglrender->win = win; oglrender->totvideos = 0; oglrender->mh = NULL; oglrender->movie_ctx_arr = NULL; return true; }
static int view3d_layers_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; int nr = RNA_int_get(op->ptr, "nr"); const bool toggle = RNA_boolean_get(op->ptr, "toggle"); if (nr < 0) return OPERATOR_CANCELLED; if (nr == 0) { /* all layers */ if (!v3d->lay_prev) v3d->lay_prev = 1; if (toggle && v3d->lay == ((1 << 20) - 1)) { /* return to active layer only */ v3d->lay = v3d->lay_prev; view3d_layers_editmode_ensure(scene, v3d); } else { v3d->lay_prev = v3d->lay; v3d->lay |= (1 << 20) - 1; } } else { int bit; nr--; if (RNA_boolean_get(op->ptr, "extend")) { if (toggle && v3d->lay & (1 << nr) && (v3d->lay & ~(1 << nr))) v3d->lay &= ~(1 << nr); else v3d->lay |= (1 << nr); } else { v3d->lay = (1 << nr); } view3d_layers_editmode_ensure(scene, v3d); /* set active layer, ensure to always have one */ if (v3d->lay & (1 << nr)) v3d->layact = 1 << nr; else if ((v3d->lay & v3d->layact) == 0) { for (bit = 0; bit < 32; bit++) { if (v3d->lay & (1 << bit)) { v3d->layact = 1 << bit; break; } } } } if (v3d->scenelock) handle_view3d_lock(C); DAG_on_visible_update(CTX_data_main(C), false); ED_area_tag_redraw(sa); return OPERATOR_FINISHED; }
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); OGLRender *oglrender = op->customdata; Scene *scene = oglrender->scene; char name[FILE_MAX]; bool ok = false; const bool view_context = (oglrender->v3d != NULL); bool is_movie; RenderResult *rr; /* go to next frame */ if (CFRA < oglrender->nfra) CFRA++; while (CFRA < oglrender->nfra) { unsigned int lay = screen_opengl_layers(oglrender); if (lay & 0xFF000000) lay &= 0xFF000000; BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, lay); CFRA++; } is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype); if (!is_movie) { BKE_image_path_from_imformat( name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) { BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name); ok = true; goto finally; } } WM_cursor_time(oglrender->win, scene->r.cfra); BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, screen_opengl_layers(oglrender)); if (view_context) { if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera && oglrender->v3d->scenelock) { /* since BKE_scene_update_for_newframe() is used rather * then ED_update_for_newframe() the camera needs to be set */ if (BKE_scene_camera_switch_update(scene)) { oglrender->v3d->camera = scene->camera; } } } else { BKE_scene_camera_switch_update(scene); } /* render into offscreen buffer */ screen_opengl_render_apply(oglrender); /* save to disk */ rr = RE_AcquireResultRead(oglrender->re); if (is_movie) { ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh, oglrender->sizex, oglrender->sizey, oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0); if (ok) { printf("Append frame %d", scene->r.cfra); BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra); } } else { BKE_render_result_stamp_info(scene, scene->camera, rr, false); ok = RE_WriteRenderViewsImage(op->reports, rr, scene, true, name); if (ok) { printf("Saved: %s", name); BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name); } else { printf("Write error: cannot save %s\n", name); BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name); } } RE_ReleaseResult(oglrender->re); /* movie stats prints have no line break */ printf("\n"); finally: /* Step the frame and bail early if needed */ /* go to next frame */ oglrender->nfra += scene->r.frame_step; /* stop at the end or on error */ if (CFRA >= PEFRA || !ok) { screen_opengl_render_end(C, op->customdata); return 0; } return 1; }
/* name can be a dynamic string */ void BKE_write_undo(bContext *C, const char *name) { uintptr_t maxmem, totmem, memused; 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_free_memfile(&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_merge_memfile(&first->memfile, &first->next->memfile); MEM_freeN(first); } } /* disk save version */ if (UNDO_DISK) { static int counter = 0; char filepath[FILE_MAX]; char numstr[32]; int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */ /* calculate current filepath */ counter++; counter = counter % U.undosteps; BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter); BLI_make_file_string("/", filepath, BLI_temporary_dir(), numstr); /* success = */ /* UNUSED */ BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL); BLI_strncpy(curundo->str, filepath, sizeof(curundo->str)); } else { MemFile *prevfile = NULL; if (curundo->prev) prevfile = &(curundo->prev->memfile); memused = MEM_get_memory_in_use(); /* success = */ /* UNUSED */ BLO_write_file_mem(CTX_data_main(C), prevfile, &curundo->memfile, G.fileflags); curundo->undosize = MEM_get_memory_in_use() - memused; } if (U.undomemory != 0) { /* limit to maximum memory (afterwards, we can't know in advance) */ totmem = 0; maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024; /* keep at least two (original + other) */ 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; BLI_remlink(&undobase, first); /* the merge is because of compression */ BLO_merge_memfile(&first->memfile, &first->next->memfile); MEM_freeN(first); } } } }
static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) { Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); bScreen *screen = WM_window_get_active_screen(win); /* Draw screen areas into own frame buffer. */ ED_screen_areas_iter(win, screen, sa) { CTX_wm_area_set(C, sa); /* Compute UI layouts for dynamically size regions. */ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->visible && ar->do_draw && ar->type && ar->type->layout) { CTX_wm_region_set(C, ar); ED_region_do_layout(C, ar); CTX_wm_region_set(C, NULL); } } ED_area_update_region_sizes(wm, win, sa); if (sa->flag & AREA_FLAG_ACTIVE_TOOL_UPDATE) { if ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) { WM_toolsystem_update_from_context(C, CTX_wm_workspace(C), CTX_data_view_layer(C), sa); } sa->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE; } /* Then do actual drawing of regions. */ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->visible && ar->do_draw) { CTX_wm_region_set(C, ar); bool use_viewport = wm_region_use_viewport(sa, ar); if (stereo && wm_draw_region_stereo_set(bmain, sa, ar, STEREO_LEFT_ID)) { wm_draw_region_buffer_create(ar, true, use_viewport); for (int view = 0; view < 2; view++) { eStereoViews sview; if (view == 0) { sview = STEREO_LEFT_ID; } else { sview = STEREO_RIGHT_ID; wm_draw_region_stereo_set(bmain, sa, ar, sview); } wm_draw_region_bind(ar, view); ED_region_do_draw(C, ar); wm_draw_region_unbind(ar, view); } } else { wm_draw_region_buffer_create(ar, false, use_viewport); wm_draw_region_bind(ar, 0); ED_region_do_draw(C, ar); wm_draw_region_unbind(ar, 0); } ar->do_draw = false; CTX_wm_region_set(C, NULL); } } wm_area_mark_invalid_backbuf(sa); CTX_wm_area_set(C, NULL); }
/* using context, starts job */ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* new render clears all callbacks */ Main *mainp; Scene *scene = CTX_data_scene(C); SceneRenderLayer *srl = NULL; Render *re; wmJob *wm_job; RenderJob *rj; Image *ima; int jobflag; const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport"); View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL; struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; const char *name; ScrArea *sa; /* only one render job at a time */ if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER)) return OPERATOR_CANCELLED; if (RE_force_single_renderlayer(scene)) WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL); if (!RE_is_rendering_allowed(scene, camera_override, op->reports)) { return OPERATOR_CANCELLED; } if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) { BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected"); return OPERATOR_CANCELLED; } /* stop all running jobs, except screen one. currently previews frustrate Render */ WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); /* get main */ if (G.debug_value == 101) { /* thread-safety experiment, copy main from the undo buffer */ mainp = BKE_undo_get_main(&scene); } else mainp = CTX_data_main(C); /* cancel animation playback */ if (ED_screen_animation_playing(CTX_wm_manager(C))) ED_screen_animation_play(C, 0, 0); /* handle UI stuff */ WM_cursor_wait(1); /* flush sculpt and editmode changes */ ED_editors_flush_edits(C, true); /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into * the output rendering. We can't put that into RE_BlenderFrame, * since sequence rendering can call that recursively... (peter) */ BKE_sequencer_cache_cleanup(); // store spare // get view3d layer, local layer, make this nice api call to render // store spare /* ensure at least 1 area shows result */ sa = render_view_open(C, event->x, event->y); jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS; /* custom scene and single layer re-render */ screen_render_scene_layer_set(op, mainp, &scene, &srl); if (RNA_struct_property_is_set(op->ptr, "layer")) jobflag |= WM_JOB_SUSPEND; /* job custom data */ rj = MEM_callocN(sizeof(RenderJob), "render job"); rj->main = mainp; rj->scene = scene; rj->current_scene = rj->scene; rj->srl = srl; rj->camera_override = camera_override; rj->lay_override = 0; rj->anim = is_animation; rj->write_still = is_write_still && !is_animation; rj->iuser.scene = scene; rj->iuser.ok = 1; rj->reports = op->reports; rj->orig_layer = 0; rj->last_layer = 0; rj->sa = sa; BKE_color_managed_display_settings_copy(&rj->display_settings, &scene->display_settings); BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings); if (sa) { SpaceImage *sima = sa->spacedata.first; rj->orig_layer = sima->iuser.layer; } if (v3d) { if (scene->lay != v3d->lay) { rj->lay_override = v3d->lay; rj->v3d_override = true; } else if (camera_override && camera_override != scene->camera) rj->v3d_override = true; if (v3d->localvd) rj->lay_override |= v3d->localvd->lay; } /* Lock the user interface depending on render settings. */ if (scene->r.use_lock_interface) { int renderlay = rj->lay_override ? rj->lay_override : scene->lay; WM_set_locked_interface(CTX_wm_manager(C), true); /* Set flag interface need to be unlocked. * * This is so because we don't have copy of render settings * accessible from render job and copy is needed in case * of non-locked rendering, so we wouldn't try to unlock * anything if option was initially unset but then was * enabled during rendering. */ rj->interface_locked = true; /* Clean memory used by viewport? */ clean_viewport_memory(rj->main, scene, renderlay); } /* setup job */ if (RE_seq_render_active(scene, &scene->r)) name = "Sequence Render"; else name = "Render"; wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, name, jobflag, WM_JOB_TYPE_RENDER); WM_jobs_customdata_set(wm_job, rj, render_freejob); WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0); WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob); /* get a render result image, and make sure it is empty */ ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); BKE_image_backup_render(rj->scene, ima); rj->image = ima; /* setup new render */ re = RE_NewRender(scene->id.name); RE_test_break_cb(re, rj, render_breakjob); RE_draw_lock_cb(re, rj, render_drawlock); RE_display_update_cb(re, rj, image_rect_update); RE_current_scene_update_cb(re, rj, current_scene_update); RE_stats_draw_cb(re, rj, image_renderinfo_cb); RE_progress_cb(re, rj, render_progress_update); rj->re = re; G.is_break = false; /* store actual owner of job, so modal operator could check for it, * the reason of this is that active scene could change when rendering * several layers from compositor [#31800] */ op->customdata = scene; WM_jobs_start(CTX_wm_manager(C), wm_job); WM_cursor_wait(0); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); /* we set G.is_rendering here already instead of only in the job, this ensure * main loop or other scene updates are disabled in time, since they may * have started before the job thread */ G.is_rendering = true; /* add modal handler for ESC */ WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; }
void unpack_menu(bContext *C, const char *opname, const char *id_name, const char *abs_name, const char *folder, struct PackedFile *pf) { Main *bmain = CTX_data_main(C); PointerRNA props_ptr; uiPopupMenu *pup; uiLayout *layout; char line[FILE_MAX + 100]; wmOperatorType *ot = WM_operatortype_find(opname, 1); pup = UI_popup_menu_begin(C, IFACE_("Unpack File"), ICON_NONE); layout = UI_popup_menu_layout(pup); uiItemFullO_ptr( layout, ot, IFACE_("Remove Pack"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_REMOVE); RNA_string_set(&props_ptr, "id", id_name); if (G.relbase_valid) { char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; BLI_split_file_part(abs_name, fi, sizeof(fi)); BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi); if (!STREQ(abs_name, local_name)) { switch (checkPackedFile(BKE_main_blendfile_path(bmain), local_name, pf)) { case PF_NOFILE: BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), local_name); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL); RNA_string_set(&props_ptr, "id", id_name); break; case PF_EQUAL: BLI_snprintf(line, sizeof(line), IFACE_("Use %s (identical)"), local_name); //uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_LOCAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL); RNA_string_set(&props_ptr, "id", id_name); break; case PF_DIFFERS: BLI_snprintf(line, sizeof(line), IFACE_("Use %s (differs)"), local_name); //uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_LOCAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL); RNA_string_set(&props_ptr, "id", id_name); BLI_snprintf(line, sizeof(line), IFACE_("Overwrite %s"), local_name); //uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_LOCAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL); RNA_string_set(&props_ptr, "id", id_name); break; } } } switch (checkPackedFile(BKE_main_blendfile_path(bmain), abs_name, pf)) { case PF_NOFILE: BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), abs_name); //uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL); RNA_string_set(&props_ptr, "id", id_name); break; case PF_EQUAL: BLI_snprintf(line, sizeof(line), IFACE_("Use %s (identical)"), abs_name); //uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_ORIGINAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL); RNA_string_set(&props_ptr, "id", id_name); break; case PF_DIFFERS: BLI_snprintf(line, sizeof(line), IFACE_("Use %s (differs)"), abs_name); //uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_ORIGINAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL); RNA_string_set(&props_ptr, "id", id_name); BLI_snprintf(line, sizeof(line), IFACE_("Overwrite %s"), abs_name); //uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL); RNA_string_set(&props_ptr, "id", id_name); break; } UI_popup_menu_end(C, pup); }
/* add new node connected to this socket, or replace an existing one */ static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, int type, NodeLinkItem *item) { bNode *node_from; bNodeSocket *sock_from_tmp; bNode *node_prev = NULL; /* unlink existing node */ if (sock_to->link) { node_prev = sock_to->link->fromnode; nodeRemLink(ntree, sock_to->link); } /* find existing node that we can use */ for (node_from = ntree->nodes.first; node_from; node_from = node_from->next) if (node_from->type == type) break; if (node_from) if (node_from->inputs.first || node_from->typeinfo->draw_buttons || node_from->typeinfo->draw_buttons_ex) node_from = NULL; if (node_prev && node_prev->type == type && node_link_item_compare(node_prev, item)) { /* keep the previous node if it's the same type */ node_from = node_prev; } else if (!node_from) { node_from = nodeAddStaticNode(C, ntree, type); node_from->locx = node_to->locx - (node_from->typeinfo->width + 50); node_from->locy = node_to->locy; node_link_item_apply(node_from, item); } nodeSetActive(ntree, node_from); /* add link */ sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index); nodeAddLink(ntree, node_from, sock_from_tmp, node_to, sock_to); sock_to->flag &= ~SOCK_COLLAPSED; /* copy input sockets from previous node */ if (node_prev && node_from != node_prev) { bNodeSocket *sock_prev, *sock_from; for (sock_prev = node_prev->inputs.first; sock_prev; sock_prev = sock_prev->next) { for (sock_from = node_from->inputs.first; sock_from; sock_from = sock_from->next) { if (nodeCountSocketLinks(ntree, sock_from) >= sock_from->limit) continue; if (STREQ(sock_prev->name, sock_from->name) && sock_prev->type == sock_from->type) { bNodeLink *link = sock_prev->link; if (link && link->fromnode) { nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from); nodeRemLink(ntree, link); } node_socket_copy_default_value(sock_from, sock_prev); } } } /* also preserve mapping for texture nodes */ if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE && node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE) { memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase)); } /* remove node */ node_remove_linked(ntree, node_prev); } nodeUpdate(ntree, node_from); nodeUpdate(ntree, node_to); ntreeUpdateTree(CTX_data_main(C), ntree); ED_node_tag_update_nodetree(CTX_data_main(C), ntree); }
/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, int mode, int norm_weights, float rad_fac, int link_strokes, tGpTimingData *gtd) { struct Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0); bGPDstroke *gps, *prev_gps = NULL; Object *ob; Curve *cu; Nurb *nu = NULL; Base *base_orig = BASACT, *base_new = NULL; float minmax_weights[2] = {1.0f, 0.0f}; /* camera framing */ rctf subrect, *subrect_ptr = NULL; /* error checking */ if (ELEM3(NULL, gpd, gpl, gpf)) return; /* only convert if there are any strokes on this layer's frame to convert */ if (gpf->strokes.first == NULL) return; /* initialize camera framing */ if (gp_camera_view_subrect(C, &subrect)) { subrect_ptr = &subrect; } /* init the curve object (remove rotation and get curve data from it) * - must clear transforms set on object, as those skew our results */ ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info); cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE); base_new = BKE_scene_base_add(scene, ob); cu->flag |= CU_3D; gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime; /* add points to curve */ for (gps = gpf->strokes.first; gps; gps = gps->next) { /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached, * and stitch them to previous one. */ int stitch = FALSE; if (prev_gps) { bGPDspoint *pt1 = prev_gps->points + prev_gps->totpoints - 1; bGPDspoint *pt2 = gps->points; if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) { stitch = TRUE; } } /* Decide whether we connect this stroke to previous one */ if (!(stitch || link_strokes)) { nu = NULL; } switch (mode) { case GP_STROKECONVERT_PATH: gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch, gtd); break; case GP_STROKECONVERT_CURVE: case GP_STROKECONVERT_POLY: /* convert after */ gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch, gtd); break; default: BLI_assert(!"invalid mode"); break; } prev_gps = gps; } /* If link_strokes, be sure first and last points have a zero weight/size! */ if (link_strokes) { gp_stroke_finalize_curve_endpoints(cu); } /* Update curve's weights, if needed */ if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) { gp_stroke_norm_curve_weights(cu, minmax_weights); } /* Create the path animation, if needed */ gp_stroke_path_animation(C, reports, cu, gtd); if (mode == GP_STROKECONVERT_POLY) { for (nu = cu->nurb.first; nu; nu = nu->next) { BKE_nurb_type_convert(nu, CU_POLY, false); } } /* set the layer and select */ base_new->lay = ob->lay = base_orig ? base_orig->lay : scene->lay; base_new->flag = ob->flag = base_new->flag | SELECT; }
void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& joint_by_uid, TransformReader *tm) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature); ArmatureModifierData *amd = (ArmatureModifierData *)md; amd->object = ob_arm; copy_m4_m4(ob->obmat, bind_shape_matrix); BKE_object_apply_mat4(ob, ob->obmat, 0, 0); #if 1 bc_set_parent(ob, ob_arm, C); #else Object workob; ob->parent = ob_arm; ob->partype = PAROBJECT; BKE_object_workob_calc_parent(scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA; DAG_scene_sort(bmain, scene); DAG_ids_flush_update(bmain, 0); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); #endif amd->deformflag = ARM_DEF_VGROUP; // create all vertex groups std::vector<JointData>::iterator it; int joint_index; for (it = joint_data.begin(), joint_index = 0; it != joint_data.end(); it++, joint_index++) { const char *name = "Group"; // skip joints that have invalid UID if ((*it).joint_uid == COLLADAFW::UniqueId::INVALID) continue; // name group by joint node name if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) { name = bc_get_joint_name(joint_by_uid[(*it).joint_uid]); } ED_vgroup_add_name(ob, (char *)name); } // <vcount> - number of joints per vertex - joints_per_vertex // <v> - [[bone index, weight index] * joints per vertex] * vertices - weight indices // ^ bone index can be -1 meaning weight toward bind shape, how to express this in Blender? // for each vertex in weight indices // for each bone index in vertex // add vertex to group at group index // treat group index -1 specially // get def group by index with BLI_findlink for (unsigned int vertex = 0, weight = 0; vertex < joints_per_vertex.getCount(); vertex++) { unsigned int limit = weight + joints_per_vertex[vertex]; for (; weight < limit; weight++) { int joint = joint_indices[weight], joint_weight = weight_indices[weight]; // -1 means "weight towards the bind shape", we just don't assign it to any group if (joint != -1) { bDeformGroup *def = (bDeformGroup *)BLI_findlink(&ob->defbase, joint); ED_vgroup_vert_add(ob, def, vertex, weights[joint_weight], WEIGHT_REPLACE); } } } }
/* use for updating while a python script runs - in case of file load */ void bpy_context_update(bContext *C) { BPy_SetContext(C); bpy_import_main_set(CTX_data_main(C)); BPY_modules_update(C); /* can give really bad results if this isnt here */ }
/* separate selected bones into their armature */ static int separate_armature_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); Object *oldob, *newob; Base *oldbase, *newbase; /* sanity checks */ if (obedit == NULL) return OPERATOR_CANCELLED; /* set wait cursor in case this takes a while */ WM_cursor_wait(1); /* we are going to do this as follows (unlike every other instance of separate): * 1. exit editmode +posemode for active armature/base. Take note of what this is. * 2. duplicate base - BASACT is the new one now * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc * 4. fix constraint links * 5. make original armature active and enter editmode */ /* 1) only edit-base selected */ /* TODO: use context iterators for this? */ CTX_DATA_BEGIN(C, Base *, base, visible_bases) { if (base->object == obedit) base->flag |= SELECT; else base->flag &= ~SELECT; } CTX_DATA_END; /* 1) store starting settings and exit editmode */ oldob = obedit; oldbase = BASACT; oldob->mode &= ~OB_MODE_POSE; //oldbase->flag &= ~OB_POSEMODE; ED_armature_from_edit(obedit->data); ED_armature_edit_free(obedit->data); /* 2) duplicate base */ newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */ DAG_relations_tag_update(bmain); newob = newbase->object; newbase->flag &= ~SELECT; /* 3) remove bones that shouldn't still be around on both armatures */ separate_armature_bones(oldob, 1); separate_armature_bones(newob, 0); /* 4) fix links before depsgraph flushes */ // err... or after? separated_armature_fix_links(oldob, newob); DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */ DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */ /* 5) restore original conditions */ obedit = oldob; ED_armature_to_edit(obedit->data); BKE_report(op->reports, RPT_INFO, "Separated bones"); /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); /* recalc/redraw + cleanup */ WM_cursor_wait(0); return OPERATOR_FINISHED; }
static int load_file(int UNUSED(argc), const char **argv, void *data) { bContext *C = data; /* Make the path absolute because its needed for relative linked blends to be found */ char filename[FILE_MAX]; /* note, we could skip these, but so far we always tried to load these files */ if (argv[0][0] == '-') { fprintf(stderr, "unknown argument, loading as file: %s\n", argv[0]); } BLI_strncpy(filename, argv[0], sizeof(filename)); BLI_path_cwd(filename); if (G.background) { int retval; BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE); retval = BKE_read_file(C, filename, NULL); /* we successfully loaded a blend file, get sure that * pointcache works */ if (retval != BKE_READ_FILE_FAIL) { wmWindowManager *wm = CTX_wm_manager(C); Main *bmain = CTX_data_main(C); /* special case, 2.4x files */ if (wm == NULL && BLI_listbase_is_empty(&bmain->wm)) { extern void wm_add_default(bContext *C); /* wm_add_default() needs the screen to be set. */ CTX_wm_screen_set(C, bmain->screen.first); wm_add_default(C); } CTX_wm_manager_set(C, NULL); /* remove wm to force check */ WM_check(C); G.relbase_valid = 1; if (CTX_wm_manager(C) == NULL) CTX_wm_manager_set(C, wm); /* reset wm */ /* WM_file_read would call normally */ ED_editors_init(C); DAG_on_visible_update(bmain, true); BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C)); } else { /* failed to load file, stop processing arguments */ return -1; } /* WM_file_read() runs normally but since we're in background mode do here */ #ifdef WITH_PYTHON /* run any texts that were loaded in and flagged as modules */ BPY_python_reset(C); #endif BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); /* happens for the UI on file reading too (huh? (ton))*/ // XXX BKE_reset_undo(); // BKE_write_undo("original"); /* save current state */ } else { /* we are not running in background mode here, but start blender in UI mode with * a file - this should do everything a 'load file' does */ ReportList reports; BKE_reports_init(&reports, RPT_PRINT); WM_file_autoexec_init(filename); WM_file_read(C, filename, &reports); BKE_reports_clear(&reports); } G.file_loaded = 1; return 0; }
static int ED_object_shape_key_remove(bContext *C, Object *ob) { Main *bmain= CTX_data_main(C); KeyBlock *kb, *rkb; Key *key; //IpoCurve *icu; key= ob_get_key(ob); if(key==NULL) return 0; kb= BLI_findlink(&key->block, ob->shapenr-1); if(kb) { for(rkb= key->block.first; rkb; rkb= rkb->next) if(rkb->relative == ob->shapenr-1) rkb->relative= 0; BLI_remlink(&key->block, kb); key->totkey--; if(key->refkey== kb) { key->refkey= key->block.first; if(key->refkey) { /* apply new basis key on original data */ switch(ob->type) { case OB_MESH: key_to_mesh(key->refkey, ob->data); break; case OB_CURVE: case OB_SURF: key_to_curve(key->refkey, ob->data, BKE_curve_nurbs(ob->data)); break; case OB_LATTICE: key_to_latt(key->refkey, ob->data); break; } } } if(kb->data) MEM_freeN(kb->data); MEM_freeN(kb); for(kb= key->block.first; kb; kb= kb->next) if(kb->adrcode>=ob->shapenr) kb->adrcode--; #if 0 // XXX old animation system if(key->ipo) { for(icu= key->ipo->curve.first; icu; icu= icu->next) { if(icu->adrcode==ob->shapenr-1) { BLI_remlink(&key->ipo->curve, icu); free_ipo_curve(icu); break; } } for(icu= key->ipo->curve.first; icu; icu= icu->next) if(icu->adrcode>=ob->shapenr) icu->adrcode--; } #endif // XXX old animation system if(ob->shapenr>1) ob->shapenr--; } if(key->totkey==0) { if(GS(key->from->name)==ID_ME) ((Mesh *)key->from)->key= NULL; else if(GS(key->from->name)==ID_CU) ((Curve *)key->from)->key= NULL; else if(GS(key->from->name)==ID_LT) ((Lattice *)key->from)->key= NULL; free_libblock_us(&(bmain->key), key); } DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); return 1; }
bool WM_init_game(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; ScrArea *sa; ARegion *ar = NULL; Scene *scene = CTX_data_scene(C); if (!scene) { /* XXX, this should not be needed. */ Main *bmain = CTX_data_main(C); scene = bmain->scene.first; } win = wm->windows.first; /* first to get a valid window */ if (win) CTX_wm_window_set(C, win); sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0); ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); /* if we have a valid 3D view */ if (sa && ar) { ARegion *arhide; CTX_wm_area_set(C, sa); CTX_wm_region_set(C, ar); /* disable quad view */ if (ar->alignment == RGN_ALIGN_QSPLIT) WM_operator_name_call(C, "SCREEN_OT_region_quadview", WM_OP_EXEC_DEFAULT, NULL); /* toolbox, properties panel and header are hidden */ for (arhide = sa->regionbase.first; arhide; arhide = arhide->next) { if (arhide->regiontype != RGN_TYPE_WINDOW) { if (!(arhide->flag & RGN_FLAG_HIDDEN)) { ED_region_toggle_hidden(C, arhide); } } } /* full screen the area */ if (!sa->full) { ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED); } /* Fullscreen */ if ((scene->gm.playerflag & GAME_PLAYER_FULLSCREEN)) { WM_operator_name_call(C, "WM_OT_window_fullscreen_toggle", WM_OP_EXEC_DEFAULT, NULL); wm_get_screensize(&ar->winrct.xmax, &ar->winrct.ymax); ar->winx = ar->winrct.xmax + 1; ar->winy = ar->winrct.ymax + 1; } else { GHOST_RectangleHandle rect = GHOST_GetClientBounds(win->ghostwin); ar->winrct.ymax = GHOST_GetHeightRectangle(rect); ar->winrct.xmax = GHOST_GetWidthRectangle(rect); ar->winx = ar->winrct.xmax + 1; ar->winy = ar->winrct.ymax + 1; GHOST_DisposeRectangle(rect); } WM_operator_name_call(C, "VIEW3D_OT_game_start", WM_OP_EXEC_DEFAULT, NULL); BKE_sound_exit(); return true; } else { ReportTimerInfo *rti; BKE_report(&wm->reports, RPT_ERROR, "No valid 3D View found, game auto start is not possible"); /* After adding the report to the global list, reset the report timer. */ WM_event_remove_timer(wm, NULL, wm->reports.reporttimer); /* Records time since last report was added */ wm->reports.reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER, 0.02); rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); wm->reports.reporttimer->customdata = rti; return false; } }