/* 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();
}
Exemple #2
0
/* 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;
}
Exemple #3
0
int join_mesh_exec(bContext *C, wmOperator *op)
{
    Main *bmain= CTX_data_main(C);
    Scene *scene= CTX_data_scene(C);
    Object *ob= CTX_data_active_object(C);
    Material **matar, *ma;
    Mesh *me;
    MVert *mvert, *mv;
    MEdge *medge = NULL;
    MFace *mface = NULL;
    Key *key, *nkey=NULL;
    KeyBlock *kb, *okb, *kbn;
    float imat[4][4], cmat[4][4], *fp1, *fp2, curpos;
    int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0;
    int vertofs, *matmap=NULL;
    int	i, j, index, haskey=0, edgeofs, faceofs;
    bDeformGroup *dg, *odg;
    MDeformVert *dvert;
    CustomData vdata, edata, fdata;

    if(scene->obedit) {
        BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode");
        return OPERATOR_CANCELLED;
    }

    /* ob is the object we are adding geometry to */
    if(!ob || ob->type!=OB_MESH) {
        BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh");
        return OPERATOR_CANCELLED;
    }

    /* count & check */
    CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
        if(base->object->type==OB_MESH) {
            me= base->object->data;

            totvert+= me->totvert;
            totedge+= me->totedge;
            totface+= me->totface;
            totmat+= base->object->totcol;

            if(base->object == ob)
                ok= 1;

            /* check for shapekeys */
            if(me->key)
                haskey++;
        }
    }
    CTX_DATA_END;

    /* that way the active object is always selected */
    if(ok==0) {
        BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh");
        return OPERATOR_CANCELLED;
    }

    /* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */
    me= (Mesh *)ob->data;
    key= me->key;

    if(totvert==0 || totvert==me->totvert) {
        BKE_report(op->reports, RPT_WARNING, "No mesh data to join");
        return OPERATOR_CANCELLED;
    }

    if(totvert > MESH_MAX_VERTS) {
        BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is " STRINGIFY(MESH_MAX_VERTS), totvert);
        return OPERATOR_CANCELLED;
    }

    /* new material indices and material array */
    matar= MEM_callocN(sizeof(void*)*totmat, "join_mesh matar");
    if (totmat) matmap= MEM_callocN(sizeof(int)*totmat, "join_mesh matmap");
    totcol= ob->totcol;

    /* obact materials in new main array, is nicer start! */
    for(a=0; a<ob->totcol; a++) {
        matar[a]= give_current_material(ob, a+1);
        id_us_plus((ID *)matar[a]);
        /* increase id->us : will be lowered later */
    }

    /* - if destination mesh had shapekeys, move them somewhere safe, and set up placeholders
     * 	with arrays that are large enough to hold shapekey data for all meshes
     * -	if destination mesh didn't have shapekeys, but we encountered some in the meshes we're
     *	joining, set up a new keyblock and assign to the mesh
     */
    if(key) {
        /* make a duplicate copy that will only be used here... (must remember to free it!) */
        nkey= copy_key(key);

        /* for all keys in old block, clear data-arrays */
        for(kb= key->block.first; kb; kb= kb->next) {
            if(kb->data) MEM_freeN(kb->data);
            kb->data= MEM_callocN(sizeof(float)*3*totvert, "join_shapekey");
            kb->totelem= totvert;
            kb->weights= NULL;
        }
    }
    else if(haskey) {
        /* add a new key-block and add to the mesh */
        key= me->key= add_key((ID *)me);
        key->type = KEY_RELATIVE;
    }

    /* first pass over objects - copying materials and vertexgroups across */
    CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
        /* only act if a mesh, and not the one we're joining to */
        if((ob!=base->object) && (base->object->type==OB_MESH)) {
            me= base->object->data;

            /* Join this object's vertex groups to the base one's */
            for(dg=base->object->defbase.first; dg; dg=dg->next) {
                /* See if this group exists in the object (if it doesn't, add it to the end) */
                if(!defgroup_find_name(ob, dg->name)) {
                    odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup");
                    memcpy(odg, dg, sizeof(bDeformGroup));
                    BLI_addtail(&ob->defbase, odg);
                }
            }
            if(ob->defbase.first && ob->actdef==0)
                ob->actdef=1;


            if(me->totvert) {
                /* Add this object's materials to the base one's if they don't exist already (but only if limits not exceeded yet) */
                if(totcol < MAXMAT-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;
}
Exemple #4
0
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;
}
Exemple #6
0
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);
}
Exemple #7
0
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;
}
Exemple #8
0
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;
}
Exemple #9
0
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));
}
Exemple #10
0
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);

}
Exemple #13
0
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;
}
Exemple #14
0
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;
}
Exemple #15
0
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);
}
Exemple #16
0
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;
}
Exemple #18
0
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;
}
Exemple #19
0
/* 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);
			}
		}
	}
}
Exemple #20
0
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;
}
Exemple #22
0
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);
}
Exemple #24
0
/* 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;
}
Exemple #25
0
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);
			}
		}
	}
}
Exemple #26
0
/* 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 */
}
Exemple #27
0
/* 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;
}
Exemple #28
0
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;
}
Exemple #29
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;
    }
}