Ejemplo n.º 1
0
void ntreeCompositExecTree(Scene *scene, bNodeTree *ntree, RenderData *rd, int rendering, int do_preview,
                           const ColorManagedViewSettings *view_settings,
                           const ColorManagedDisplaySettings *display_settings)
{
#ifdef WITH_COMPOSITOR
	COM_execute(rd, scene, ntree, rendering, view_settings, display_settings);
#else
	UNUSED_VARS(scene, ntree, rd, rendering, view_settings, display_settings);
#endif

	UNUSED_VARS(do_preview);
}
Ejemplo n.º 2
0
/* Init Textures, Framebuffers, Storage and Shaders.
 * It is called for every frames.
 * (Optional) */
static void EDIT_TEXT_engine_init(void *vedata)
{
  EDIT_TEXT_TextureList *txl = ((EDIT_TEXT_Data *)vedata)->txl;
  EDIT_TEXT_FramebufferList *fbl = ((EDIT_TEXT_Data *)vedata)->fbl;
  EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;

  UNUSED_VARS(txl, fbl, stl);

  /* Init Framebuffers like this: order is attachment order (for color texs) */
  /*
   * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
   *                         {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
   */

  /* DRW_framebuffer_init takes care of checking if
   * the framebuffer is valid and has the right size*/
  /*
   * float *viewport_size = DRW_viewport_size_get();
   * DRW_framebuffer_init(&fbl->occlude_wire_fb,
   *                     (int)viewport_size[0], (int)viewport_size[1],
   *                     tex, 2);
   */

  if (!e_data.wire_sh) {
    e_data.wire_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
  }

  if (!e_data.overlay_select_sh) {
    e_data.overlay_select_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
  }

  if (!e_data.overlay_cursor_sh) {
    e_data.overlay_cursor_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
  }
}
Ejemplo n.º 3
0
/* Add geometry to shadingGroups. Execute for each objects */
static void EDIT_TEXT_cache_populate(void *vedata, Object *ob)
{
  EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
  EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
  const DRWContextState *draw_ctx = DRW_context_state_get();

  UNUSED_VARS(psl, stl);

  if (ob->type == OB_FONT) {
    if (ob == draw_ctx->object_edit) {
      const Curve *cu = ob->data;
      /* Get geometry cache */
      struct GPUBatch *geom;

      bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f || cu->ext2 != 0.0f;
      if ((cu->flag & CU_FAST) || !has_surface) {
        geom = DRW_cache_text_edge_wire_get(ob);
        if (geom) {
          DRW_shgroup_call(stl->g_data->wire_shgrp, geom, ob);
        }
      }
      else {
        /* object mode draws */
      }

      edit_text_cache_populate_select(vedata, ob);
      edit_text_cache_populate_cursor(vedata, ob);
      edit_text_cache_populate_boxes(vedata, ob);
    }
  }
}
Ejemplo n.º 4
0
bool IMB_anim_get_fps(struct anim *anim,
                     short *frs_sec, float *frs_sec_base, bool no_av_base)
{
	double frs_sec_base_double;
	if (anim->frs_sec) {
		if (anim->frs_sec > SHRT_MAX) {
			/* We cannot store original rational in our short/float format,
			 * we need to approximate it as best as we can... */
			*frs_sec = SHRT_MAX;
			frs_sec_base_double = anim->frs_sec_base * (double)SHRT_MAX / (double)anim->frs_sec;
		}
		else {
			*frs_sec = anim->frs_sec;
			frs_sec_base_double = anim->frs_sec_base;
		}
#ifdef WITH_FFMPEG
		if (no_av_base) {
			*frs_sec_base = (float)(frs_sec_base_double / AV_TIME_BASE);
		}
		else {
			*frs_sec_base = (float)frs_sec_base_double;
		}
#else
		UNUSED_VARS(no_av_base);
		*frs_sec_base = (float)frs_sec_base_double;
#endif
		BLI_assert(*frs_sec > 0);
		BLI_assert(*frs_sec_base > 0.0f);

		return true;
	}
	return false;
}
Ejemplo n.º 5
0
static void rna_SmokeModifier_velocity_grid_get(PointerRNA *ptr, float *values)
{
#ifdef WITH_SMOKE
	SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
	int length[RNA_MAX_ARRAY_DIMENSION];
	int size = rna_SmokeModifier_velocity_grid_get_length(ptr, length);
	float *vx, *vy, *vz;
	int i;

	BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);

	vx = smoke_get_velocity_x(sds->fluid);
	vy = smoke_get_velocity_y(sds->fluid);
	vz = smoke_get_velocity_z(sds->fluid);

	for (i = 0; i < size; i += 3) {
		*(values++) = *(vx++);
		*(values++) = *(vy++);
		*(values++) = *(vz++);
	}

	BLI_rw_mutex_unlock(sds->fluid_mutex);
#else
	UNUSED_VARS(ptr, values);
#endif
}
Ejemplo n.º 6
0
static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
	RNA_boolean_set(op->ptr, "init_scene_frame_range", true);

	if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
		Main *bmain = CTX_data_main(C);
		char filepath[FILE_MAX];

		if (bmain->name[0] == '\0') {
			BLI_strncpy(filepath, "untitled", sizeof(filepath));
		}
		else {
			BLI_strncpy(filepath, bmain->name, sizeof(filepath));
		}

		BLI_replace_extension(filepath, sizeof(filepath), ".abc");
		RNA_string_set(op->ptr, "filepath", filepath);
	}

	WM_event_add_fileselect(C, op);

	return OPERATOR_RUNNING_MODAL;

	UNUSED_VARS(event);
}
Ejemplo n.º 7
0
static void rna_SmokeModifier_color_grid_get(PointerRNA *ptr, float *values)
{
#ifdef WITH_SMOKE
	SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;

	BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);

	if (sds->flags & MOD_SMOKE_HIGHRES) {
		if (smoke_turbulence_has_colors(sds->wt))
			smoke_turbulence_get_rgba(sds->wt, values, 0);
		else
			smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, values, 0);
	}
	else {
		if (smoke_has_colors(sds->fluid))
			smoke_get_rgba(sds->fluid, values, 0);
		else
			smoke_get_rgba_from_density(sds->fluid, sds->active_color, values, 0);
	}

	BLI_rw_mutex_unlock(sds->fluid_mutex);
#else
	UNUSED_VARS(ptr, values);
#endif
}
Ejemplo n.º 8
0
static void rna_SmokeModifier_flame_grid_get(PointerRNA *ptr, float *values)
{
#ifdef WITH_SMOKE
	SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
	int length[RNA_MAX_ARRAY_DIMENSION];
	int size = rna_SmokeModifier_grid_get_length(ptr, length);
	float *flame;

	BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
	
	if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt)
		flame = smoke_turbulence_get_flame(sds->wt);
	else
		flame = smoke_get_flame(sds->fluid);
	
	if (flame)
		memcpy(values, flame, size * sizeof(float));
	else
		memset(values, 0, size * sizeof(float));

	BLI_rw_mutex_unlock(sds->fluid_mutex);
#else
	UNUSED_VARS(ptr, values);
#endif
}
Ejemplo n.º 9
0
static void rna_SmokeModifier_heat_grid_get(PointerRNA *ptr, float *values)
{
#ifdef WITH_SMOKE
	SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
	int length[RNA_MAX_ARRAY_DIMENSION];
	int size = rna_SmokeModifier_heat_grid_get_length(ptr, length);
	float *heat;

	BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);

	heat = smoke_get_heat(sds->fluid);

	if (heat != NULL) {
		/* scale heat values from -2.0-2.0 to -1.0-1.0. */
		for (int i = 0; i < size; i++) {
			values[i] = heat[i] * 0.5f;
		}
	}
	else {
		memset(values, 0, size * sizeof(float));
	}

	BLI_rw_mutex_unlock(sds->fluid_mutex);
#else
	UNUSED_VARS(ptr, values);
#endif
}
Ejemplo n.º 10
0
static int wm_exit_handler(bContext *C, const wmEvent *event, void *userdata)
{
	WM_exit(C);

	UNUSED_VARS(event, userdata);
	return WM_UI_HANDLER_BREAK;
}
Ejemplo n.º 11
0
static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
	BVHCallbackUserData *data = (struct BVHCallbackUserData *)userdata;
	const MLoopTri *lt = &data->sys->heat.mlooptri[index];
	const MLoop *mloop = data->sys->heat.mloop;
	float (*verts)[3] = data->sys->heat.verts;
	const float *vtri_co[3];
	float dist_test;

	vtri_co[0] = verts[mloop[lt->tri[0]].v];
	vtri_co[1] = verts[mloop[lt->tri[1]].v];
	vtri_co[2] = verts[mloop[lt->tri[2]].v];

#ifdef USE_KDOPBVH_WATERTIGHT
	if (isect_ray_tri_watertight_v3(data->start, ray->isect_precalc, UNPACK3(vtri_co), &dist_test, NULL))
#else
	UNUSED_VARS(ray);
	if (isect_ray_tri_v3(data->start, data->vec, UNPACK3(vtri_co), &dist_test, NULL))
#endif
	{
		if (dist_test < hit->dist) {
			float n[3];
			normal_tri_v3(n, UNPACK3(vtri_co));
			if (dot_v3v3(n, data->vec) < -1e-5f) {
				hit->index = index;
				hit->dist = dist_test;
			}
		}
	}
}
Ejemplo n.º 12
0
/* Draw time ! Control rendering pipeline from here */
static void EDIT_TEXT_draw_scene(void *vedata)
{
  EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
  EDIT_TEXT_FramebufferList *fbl = ((EDIT_TEXT_Data *)vedata)->fbl;

  /* Default framebuffer and texture */
  DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
  DefaultTextureList *dtxl = DRW_viewport_texture_list_get();

  UNUSED_VARS(fbl, dfbl, dtxl);

  /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
  /*
   * DRW_framebuffer_texture_detach(dtxl->depth);
   * DRW_framebuffer_bind(fbl->custom_fb);
   * DRW_draw_pass(psl->pass);
   * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
   * DRW_framebuffer_bind(dfbl->default_fb);
   */

  DRW_draw_pass(psl->wire_pass);

  if (!DRW_pass_is_empty(psl->text_box_pass)) {
    DRW_draw_pass(psl->text_box_pass);
  }

  set_inverted_drawing(1);
  DRW_draw_pass(psl->overlay_select_pass);
  DRW_draw_pass(psl->overlay_cursor_pass);
  set_inverted_drawing(0);

  /* If you changed framebuffer, double check you rebind
   * the default one with its textures attached before finishing */
}
Ejemplo n.º 13
0
/* Optional: Post-cache_populate callback */
static void EDIT_TEXT_cache_finish(void *vedata)
{
  EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
  EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;

  /* Do something here! dependent on the objects gathered */
  UNUSED_VARS(psl, stl);
}
Ejemplo n.º 14
0
static void rna_CacheFile_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
	CacheFile *cache_file = (CacheFile *)ptr->data;

	DAG_id_tag_update(&cache_file->id, 0);
	WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);

	UNUSED_VARS(bmain, scene);
}
Ejemplo n.º 15
0
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH],
                                        bool use_opensubdiv,
										bool use_instancing,
                                        bool use_new_shading)
{
	/* some useful defines to detect GPU type */
	if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
		strcat(defines, "#define GPU_ATI\n");
		if (GLEW_VERSION_3_0) {
			/* TODO(merwin): revisit this version check; GLEW_VERSION_3_0 means GL 3.0 or newer */
			strcat(defines, "#define CLIP_WORKAROUND\n");
		}
	}
	else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY))
		strcat(defines, "#define GPU_NVIDIA\n");
	else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY))
		strcat(defines, "#define GPU_INTEL\n");

	if (GPU_bicubic_bump_support())
		strcat(defines, "#define BUMP_BICUBIC\n");

	if (GLEW_VERSION_3_0) {
		strcat(defines, "#define BIT_OPERATIONS\n");
	}

#ifdef WITH_OPENSUBDIV
	/* TODO(sergey): Check whether we actually compiling shader for
	 * the OpenSubdiv mesh.
	 */
	if (use_opensubdiv) {
		strcat(defines, "#define USE_OPENSUBDIV\n");

		/* TODO(sergey): not strictly speaking a define, but this is
		 * a global typedef which we don't have better place to define
		 * in yet.
		 */
		strcat(defines, "struct VertexData {\n"
		                "  vec4 position;\n"
		                "  vec3 normal;\n"
		                "  vec2 uv;"
		                "};\n");
	}
#else
	UNUSED_VARS(use_opensubdiv);
#endif

	if (use_instancing) {
		strcat(defines, "#define USE_INSTANCING\n");
	}

	if (use_new_shading) {
		strcat(defines, "#define USE_NEW_SHADING\n");
	}

	return;
}
Ejemplo n.º 16
0
/**
 * \note \a viewdist is only for ortho at the moment.
 */
void bglPolygonOffset(float viewdist, float dist)
{
	static float winmat[16], offset = 0.0f;
	
	if (dist != 0.0f) {
		float offs;
		
		// glEnable(GL_POLYGON_OFFSET_FILL);
		// glPolygonOffset(-1.0, -1.0);

		/* hack below is to mimic polygon offset */
		glMatrixMode(GL_PROJECTION);
		glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat);
		
		/* dist is from camera to center point */
		
		if (winmat[15] > 0.5f) {
#if 1
			offs = 0.00001f * dist * viewdist;  // ortho tweaking
#else
			static float depth_fac = 0.0f;
			if (depth_fac == 0.0f) {
				int depthbits;
				glGetIntegerv(GL_DEPTH_BITS, &depthbits);
				depth_fac = 1.0f / (float)((1 << depthbits) - 1);
			}
			offs = (-1.0 / winmat[10]) * dist * depth_fac;

			UNUSED_VARS(viewdist);
#endif
		}
		else {
			/* This adjustment effectively results in reducing the Z value by 0.25%.
			 *
			 * winmat[14] actually evaluates to `-2 * far * near / (far - near)`,
			 * is very close to -0.2 with default clip range, and is used as the coefficient multiplied by `w / z`,
			 * thus controlling the z dependent part of the depth value.
			 */
			offs = winmat[14] * -0.0025f * dist;
		}
		
		winmat[14] -= offs;
		offset += offs;
		
		glLoadMatrixf(winmat);
		glMatrixMode(GL_MODELVIEW);
	}
	else {
		glMatrixMode(GL_PROJECTION);
		winmat[14] += offset;
		offset = 0.0;
		glLoadMatrixf(winmat);
		glMatrixMode(GL_MODELVIEW);
	}
}
Ejemplo n.º 17
0
static int rna_DomainFluidSettings_memory_estimate_length(PointerRNA *ptr)
{
#  ifndef WITH_MOD_FLUID
  UNUSED_VARS(ptr);
  return 0;
#  else
  char value[32];

  rna_DomainFluidSettings_memory_estimate_get(ptr, value);
  return strlen(value);
#  endif
}
Ejemplo n.º 18
0
static bool dependsOnNormals(ModifierData *md)
{
#ifdef WITH_OPENSUBDIV
	SubsurfModifierData *smd = (SubsurfModifierData *) md;
	if (smd->use_opensubdiv && md->next == NULL) {
		return true;
	}
#else
	UNUSED_VARS(md);
#endif
	return false;
}
Ejemplo n.º 19
0
CameraSettings::CameraSettings(CamTypes type, float x, float y, float z)
{
	UNUSED_VARS(x, y, z);

	switch(type)
	{
	case FIXED_POS:
		setDefault();
		break;
	default:
		break;
	}
}
static void updateDepsgraph(ModifierData *md,
                            struct Main *bmain,
                            struct Scene *scene,
                            Object *ob,
                            struct DepsNodeHandle *node)
{
	MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;

	if (mcmd->cache_file != NULL) {
		DEG_add_object_cache_relation(node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File");
	}

	UNUSED_VARS(bmain, scene, ob);
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *dm,
                                  ModifierApplyFlag flag)
{
#ifdef WITH_ALEMBIC
	MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;

	Scene *scene = md->scene;
	const float frame = BKE_scene_frame_get(scene);
	const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS);

	const char *err_str = NULL;

	CacheFile *cache_file = mcmd->cache_file;

	BKE_cachefile_ensure_handle(G.main, cache_file);

	DerivedMesh *result = ABC_read_mesh(cache_file->handle,
	                                    ob,
	                                    dm,
	                                    mcmd->object_path,
	                                    time,
	                                    &err_str,
	                                    mcmd->read_flag);

	if (err_str) {
		modifier_setError(md, "%s", err_str);
	}

	return result ? result : dm;
	UNUSED_VARS(flag);
#else
	return dm;
	UNUSED_VARS(md, ob, flag);
#endif
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
                           struct Main *bmain,
                           struct Scene *scene,
                           Object *ob, DagNode *obNode)
{
	MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;

	if (mcmd->cache_file != NULL) {
		DagNode *curNode = dag_get_node(forest, mcmd->cache_file);

		dag_add_relation(forest, curNode, obNode,
		                 DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Cache File Modifier");
	}

	UNUSED_VARS(bmain, scene, ob);
}
Ejemplo n.º 23
0
bool IMB_anim_get_fps(struct anim *anim,
                      short *frs_sec, float *frs_sec_base, bool no_av_base)
{
    if (anim->frs_sec) {
        *frs_sec = anim->frs_sec;
        *frs_sec_base = anim->frs_sec_base;
#ifdef WITH_FFMPEG
        if (no_av_base) {
            *frs_sec_base /= AV_TIME_BASE;
        }
#else
        UNUSED_VARS(no_av_base);
#endif
        return true;
    }
    return false;
}
Ejemplo n.º 24
0
/**
 * Changes the object mode (if needed) to the one set in \a workspace_new.
 * Object mode is still stored on object level. In future it should all be workspace level instead.
 */
static void workspace_change_update(WorkSpace *workspace_new,
                                    const WorkSpace *workspace_old,
                                    bContext *C,
                                    wmWindowManager *wm)
{
  /* needs to be done before changing mode! (to ensure right context) */
  UNUSED_VARS(workspace_old, workspace_new, C, wm);
#if 0
  Object *ob_act = CTX_data_active_object(C) eObjectMode mode_old = workspace_old->object_mode;
  eObjectMode mode_new = workspace_new->object_mode;

  if (mode_old != mode_new) {
    ED_object_mode_compat_set(C, ob_act, mode_new, &wm->reports);
    ED_object_mode_toggle(C, mode_new);
  }
#endif
}
Ejemplo n.º 25
0
void IMB_anim_index_rebuild(struct IndexBuildContext *context,
                            short *stop, short *do_update, float *progress)
{
	switch (context->anim_type) {
#ifdef WITH_FFMPEG
		case ANIM_FFMPEG:
			index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
			break;
#endif
#ifdef WITH_AVI
		default:
			index_rebuild_fallback((FallbackIndexBuilderContext *)context, stop, do_update, progress);
			break;
#endif
	}

	UNUSED_VARS(stop, do_update, progress);
}
Ejemplo n.º 26
0
void IMB_anim_index_rebuild_finish(IndexBuildContext *context, short stop)
{
	switch (context->anim_type) {
#ifdef WITH_FFMPEG
		case ANIM_FFMPEG:
			index_rebuild_ffmpeg_finish((FFmpegIndexBuilderContext *)context, stop);
			break;
#endif
#ifdef WITH_AVI
		default:
			index_rebuild_fallback_finish((FallbackIndexBuilderContext *)context, stop);
			break;
#endif
	}

	/* static defined at top of the file */
	UNUSED_VARS(stop, proxy_sizes);
}
Ejemplo n.º 27
0
static void face_edges_split(
        BMesh *bm, BMFace *f, struct LinkBase *e_ls_base,
        bool use_island_connect,
        MemArena *mem_arena_edgenet)
{
	unsigned int i;
	unsigned int edge_arr_len = e_ls_base->list_len;
	BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len);
	LinkNode *node;
	BLI_assert(f->head.htype == BM_FACE);

	for (i = 0, node = e_ls_base->list; i < e_ls_base->list_len; i++, node = node->next) {
		edge_arr[i] = node->link;
	}
	BLI_assert(node == NULL);

#ifdef USE_DUMP
	printf("# %s: %d %u\n", __func__, BM_elem_index_get(f), e_ls_base->list_len);
#endif

#ifdef USE_NET_ISLAND_CONNECT
	if (use_island_connect) {
		unsigned int edge_arr_holes_len;
		BMEdge **edge_arr_holes;
		if (BM_face_split_edgenet_connect_islands(
		        bm, f,
		        edge_arr, edge_arr_len,
		        false,
		        mem_arena_edgenet,
		        &edge_arr_holes, &edge_arr_holes_len))
		{
			edge_arr_len = edge_arr_holes_len;
			edge_arr = edge_arr_holes;  /* owned by the arena */
		}
	}
#else
	UNUSED_VARS(use_island_connect, mem_arena_edgenet);
#endif

	BM_face_split_edgenet(bm, f, edge_arr, (int)edge_arr_len, NULL, NULL);
}
Ejemplo n.º 28
0
/**
 * Logic shared between #WM_file_read & #wm_homefile_read,
 * updates to make after reading a file.
 */
static void wm_file_read_post(bContext *C, bool is_startup_file)
{
	bool addons_loaded = false;
	wmWindowManager *wm = CTX_wm_manager(C);

	if (!G.background) {
		/* remove windows which failed to be added via WM_check */
		wm_window_ghostwindows_remove_invalid(C, wm);
	}

	CTX_wm_window_set(C, wm->windows.first);

	ED_editors_init(C);
	DAG_on_visible_update(CTX_data_main(C), true);

#ifdef WITH_PYTHON
	if (is_startup_file) {
		/* possible python hasn't been initialized */
		if (CTX_py_init_get(C)) {
			/* sync addons, these may have changed from the defaults */
			BPY_execute_string(C, "__import__('addon_utils').reset_all()");

			BPY_python_reset(C);
			addons_loaded = true;
		}
	}
	else {
		/* run any texts that were loaded in and flagged as modules */
		BPY_python_reset(C);
		addons_loaded = true;
	}
#else
	UNUSED_VARS(is_startup_file);
#endif  /* WITH_PYTHON */

	WM_operatortype_last_properties_clear_all();

	/* important to do before NULL'ing the context */
	BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
	BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);

	/* would otherwise be handled by event loop */
	if (G.background) {
		Main *bmain = CTX_data_main(C);
		BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C));
	}

	WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);

	/* report any errors.
	 * currently disabled if addons aren't yet loaded */
	if (addons_loaded) {
		wm_file_read_report(C);
	}

	if (!G.background) {
		/* in background mode this makes it hard to load
		 * a blend file and do anything since the screen
		 * won't be set to a valid value again */
		CTX_wm_window_set(C, NULL); /* exits queues */
	}

	if (!G.background) {
//		undo_editmode_clear();
		BKE_undo_reset();
		BKE_undo_write(C, "original");  /* save current state */
	}
}
Ejemplo n.º 29
0
GPUShader *GPU_shader_create_ex(const char *vertexcode,
                                const char *fragcode,
                                const char *geocode,
                                const char *libcode,
                                const char *defines,
                                int input,
                                int output,
                                int number,
                                const int flags)
{
#ifdef WITH_OPENSUBDIV
	/* TODO(sergey): used to add #version 150 to the geometry shader.
	 * Could safely be renamed to "use_geometry_code" since it's very
	 * likely any of geometry code will want to use GLSL 1.5.
	 */
	bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0;
#else
	UNUSED_VARS(flags);
	bool use_opensubdiv = false;
#endif
	GLint status;
	GLchar log[5000];
	GLsizei length = 0;
	GPUShader *shader;
	char standard_defines[MAX_DEFINE_LENGTH] = "";
	char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";

	if (geocode && !GPU_geometry_shader_support())
		return NULL;

	shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
	gpu_dump_shaders(NULL, 0, DEBUG_SHADER_NONE);

	if (vertexcode)
		shader->vertex = glCreateShader(GL_VERTEX_SHADER);
	if (fragcode)
		shader->fragment = glCreateShader(GL_FRAGMENT_SHADER);
	if (geocode)
		shader->geometry = glCreateShader(GL_GEOMETRY_SHADER_EXT);

	shader->program = glCreateProgram();

	if (!shader->program ||
	    (vertexcode && !shader->vertex) ||
	    (fragcode && !shader->fragment) ||
	    (geocode && !shader->geometry))
	{
		fprintf(stderr, "GPUShader, object creation failed.\n");
		GPU_shader_free(shader);
		return NULL;
	}

	gpu_shader_standard_defines(standard_defines,
	                            use_opensubdiv,
	                            (flags & GPU_SHADER_FLAGS_NEW_SHADING) != 0);
	gpu_shader_standard_extensions(standard_extensions, geocode != NULL);

	if (vertexcode) {
		const char *source[5];
		/* custom limit, may be too small, beware */
		int num_source = 0;

		source[num_source++] = gpu_shader_version();
		source[num_source++] = standard_extensions;
		source[num_source++] = standard_defines;

		if (defines) source[num_source++] = defines;
		source[num_source++] = vertexcode;

		gpu_dump_shaders(source, num_source, DEBUG_SHADER_VERTEX);

		glAttachShader(shader->program, shader->vertex);
		glShaderSource(shader->vertex, num_source, source, NULL);

		glCompileShader(shader->vertex);
		glGetShaderiv(shader->vertex, GL_COMPILE_STATUS, &status);

		if (!status) {
			glGetShaderInfoLog(shader->vertex, sizeof(log), &length, log);
			shader_print_errors("compile", log, source, num_source);

			GPU_shader_free(shader);
			return NULL;
		}
	}

	if (fragcode) {
		const char *source[7];
		int num_source = 0;

		source[num_source++] = gpu_shader_version();
		source[num_source++] = standard_extensions;
		source[num_source++] = standard_defines;

#ifdef WITH_OPENSUBDIV
		/* TODO(sergey): Move to fragment shader source code generation. */
		if (use_opensubdiv) {
			source[num_source++] =
			        "#ifdef USE_OPENSUBDIV\n"
			        "in block {\n"
			        "	VertexData v;\n"
			        "} inpt;\n"
			        "#endif\n";
		}
#endif

		if (defines) source[num_source++] = defines;
		if (libcode) source[num_source++] = libcode;
		source[num_source++] = fragcode;

		gpu_dump_shaders(source, num_source, DEBUG_SHADER_FRAGMENT);

		glAttachShader(shader->program, shader->fragment);
		glShaderSource(shader->fragment, num_source, source, NULL);

		glCompileShader(shader->fragment);
		glGetShaderiv(shader->fragment, GL_COMPILE_STATUS, &status);

		if (!status) {
			glGetShaderInfoLog(shader->fragment, sizeof(log), &length, log);
			shader_print_errors("compile", log, source, num_source);

			GPU_shader_free(shader);
			return NULL;
		}
	}

	if (geocode) {
		const char *source[6];
		int num_source = 0;

		source[num_source++] = gpu_shader_version();
		source[num_source++] = standard_extensions;
		source[num_source++] = standard_defines;

		if (defines) source[num_source++] = defines;
		source[num_source++] = geocode;

		gpu_dump_shaders(source, num_source, DEBUG_SHADER_GEOMETRY);

		glAttachShader(shader->program, shader->geometry);
		glShaderSource(shader->geometry, num_source, source, NULL);

		glCompileShader(shader->geometry);
		glGetShaderiv(shader->geometry, GL_COMPILE_STATUS, &status);

		if (!status) {
			glGetShaderInfoLog(shader->geometry, sizeof(log), &length, log);
			shader_print_errors("compile", log, source, num_source);

			GPU_shader_free(shader);
			return NULL;
		}

		if (!use_opensubdiv) {
			GPU_shader_geometry_stage_primitive_io(shader, input, output, number);
		}
	}

#ifdef WITH_OPENSUBDIV
	if (use_opensubdiv) {
		glBindAttribLocation(shader->program, 0, "position");
		glBindAttribLocation(shader->program, 1, "normal");
		GPU_shader_geometry_stage_primitive_io(shader,
		                                       GL_LINES_ADJACENCY_EXT,
		                                       GL_TRIANGLE_STRIP,
		                                       4);
	}
#endif

	glLinkProgram(shader->program);
	glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
	if (!status) {
		glGetProgramInfoLog(shader->program, sizeof(log), &length, log);
		/* print attached shaders in pipeline order */
		if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1);
		if (geocode) shader_print_errors("linking", log, &geocode, 1);
		if (libcode) shader_print_errors("linking", log, &libcode, 1);
		if (fragcode) shader_print_errors("linking", log, &fragcode, 1);

		GPU_shader_free(shader);
		return NULL;
	}

#ifdef WITH_OPENSUBDIV
	/* TODO(sergey): Find a better place for this. */
	if (use_opensubdiv && GLEW_VERSION_4_1) {
		glProgramUniform1i(shader->program,
		                   glGetUniformLocation(shader->program, "FVarDataOffsetBuffer"),
		                   30);  /* GL_TEXTURE30 */

		glProgramUniform1i(shader->program,
		                   glGetUniformLocation(shader->program, "FVarDataBuffer"),
		                   31);  /* GL_TEXTURE31 */
	}
#endif

	return shader;
}
/**
 * This method computes the Laplacian Matrix and Differential Coordinates for all vertex in the mesh.
 * The Linear system is LV = d
 * Where L is Laplacian Matrix, V as the vertexes in Mesh, d is the differential coordinates
 * The Laplacian Matrix is computes as a
 * Lij = sum(Wij) (if i == j)
 * Lij = Wij (if i != j)
 * Wij is weight between vertex Vi and vertex Vj, we use cotangent weight
 *
 * The Differential Coordinate is computes as a
 * di = Vi * sum(Wij) - sum(Wij * Vj)
 * Where :
 * di is the Differential Coordinate i
 * sum (Wij) is the sum of all weights between vertex Vi and its vertexes neighbors (Vj)
 * sum (Wij * Vj) is the sum of the product between vertex neighbor Vj and weight Wij for all neighborhood.
 *
 * This Laplacian Matrix is described in the paper:
 * Desbrun M. et.al, Implicit fairing of irregular meshes using diffusion and curvature flow, SIGGRAPH '99, pag 317-324,
 * New York, USA
 *
 * The computation of Laplace Beltrami operator on Hybrid Triangle/Quad Meshes is described in the paper:
 * Pinzon A., Romero E., Shape Inflation With an Adapted Laplacian Operator For Hybrid Quad/Triangle Meshes,
 * Conference on Graphics Patterns and Images, SIBGRAPI, 2013
 *
 * The computation of Differential Coordinates is described in the paper:
 * Sorkine, O. Laplacian Surface Editing. Proceedings of the EUROGRAPHICS/ACM SIGGRAPH Symposium on Geometry Processing,
 * 2004. p. 179-188.
 */
static void initLaplacianMatrix(LaplacianSystem *sys)
{
	float no[3];
	float w2, w3;
	int i = 3, j, ti;
	int idv[3];

	for (ti = 0; ti < sys->total_tris; ti++) {
		const unsigned int *vidt = sys->tris[ti];
		const float *co[3];

		co[0] = sys->co[vidt[0]];
		co[1] = sys->co[vidt[1]];
		co[2] = sys->co[vidt[2]];

		normal_tri_v3(no, UNPACK3(co));
		add_v3_v3(sys->no[vidt[0]], no);
		add_v3_v3(sys->no[vidt[1]], no);
		add_v3_v3(sys->no[vidt[2]], no);

		for (j = 0; j < 3; j++) {
			const float *v1, *v2, *v3;

			idv[0] = vidt[j];
			idv[1] = vidt[(j + 1) % i];
			idv[2] = vidt[(j + 2) % i];

			v1 = sys->co[idv[0]];
			v2 = sys->co[idv[1]];
			v3 = sys->co[idv[2]];

			w2 = cotangent_tri_weight_v3(v3, v1, v2);
			w3 = cotangent_tri_weight_v3(v2, v3, v1);

			sys->delta[idv[0]][0] += v1[0] * (w2 + w3);
			sys->delta[idv[0]][1] += v1[1] * (w2 + w3);
			sys->delta[idv[0]][2] += v1[2] * (w2 + w3);

			sys->delta[idv[0]][0] -= v2[0] * w2;
			sys->delta[idv[0]][1] -= v2[1] * w2;
			sys->delta[idv[0]][2] -= v2[2] * w2;

			sys->delta[idv[0]][0] -= v3[0] * w3;
			sys->delta[idv[0]][1] -= v3[1] * w3;
			sys->delta[idv[0]][2] -= v3[2] * w3;

			nlMatrixAdd(idv[0], idv[1], -w2);
			nlMatrixAdd(idv[0], idv[2], -w3);
			nlMatrixAdd(idv[0], idv[0], w2 + w3);
		}
	}
}

static void computeImplictRotations(LaplacianSystem *sys)
{
	int vid, *vidn = NULL;
	float minj, mjt, qj[3], vj[3];
	int i, j, ln;

	for (i = 0; i < sys->total_verts; i++) {
		normalize_v3(sys->no[i]);
		vidn = sys->ringv_map[i].indices;
		ln = sys->ringv_map[i].count;
		minj = 1000000.0f;
		for (j = 0; j < ln; j++) {
			vid = vidn[j];
			copy_v3_v3(qj, sys->co[vid]);
			sub_v3_v3v3(vj, qj, sys->co[i]);
			normalize_v3(vj);
			mjt = fabsf(dot_v3v3(vj, sys->no[i]));
			if (mjt < minj) {
				minj = mjt;
				sys->unit_verts[i] = vidn[j];
			}
		}
	}
}

static void rotateDifferentialCoordinates(LaplacianSystem *sys)
{
	float alpha, beta, gamma;
	float pj[3], ni[3], di[3];
	float uij[3], dun[3], e2[3], pi[3], fni[3], vn[3][3];
	int i, j, num_fni, k, fi;
	int *fidn;

	for (i = 0; i < sys->total_verts; i++) {
		copy_v3_v3(pi, sys->co[i]);
		copy_v3_v3(ni, sys->no[i]);
		k = sys->unit_verts[i];
		copy_v3_v3(pj, sys->co[k]);
		sub_v3_v3v3(uij, pj, pi);
		mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
		sub_v3_v3(uij, dun);
		normalize_v3(uij);
		cross_v3_v3v3(e2, ni, uij);
		copy_v3_v3(di, sys->delta[i]);
		alpha = dot_v3v3(ni, di);
		beta = dot_v3v3(uij, di);
		gamma = dot_v3v3(e2, di);

		pi[0] = nlGetVariable(0, i);
		pi[1] = nlGetVariable(1, i);
		pi[2] = nlGetVariable(2, i);
		zero_v3(ni);
		num_fni = 0;
		num_fni = sys->ringf_map[i].count;
		for (fi = 0; fi < num_fni; fi++) {
			const unsigned int *vin;
			fidn = sys->ringf_map[i].indices;
			vin = sys->tris[fidn[fi]];
			for (j = 0; j < 3; j++) {
				vn[j][0] = nlGetVariable(0, vin[j]);
				vn[j][1] = nlGetVariable(1, vin[j]);
				vn[j][2] = nlGetVariable(2, vin[j]);
				if (vin[j] == sys->unit_verts[i]) {
					copy_v3_v3(pj, vn[j]);
				}
			}

			normal_tri_v3(fni, UNPACK3(vn));
			add_v3_v3(ni, fni);
		}

		normalize_v3(ni);
		sub_v3_v3v3(uij, pj, pi);
		mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
		sub_v3_v3(uij, dun);
		normalize_v3(uij);
		cross_v3_v3v3(e2, ni, uij);
		fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0];
		fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1];
		fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2];

		if (len_squared_v3(fni) > FLT_EPSILON) {
			nlRightHandSideSet(0, i, fni[0]);
			nlRightHandSideSet(1, i, fni[1]);
			nlRightHandSideSet(2, i, fni[2]);
		}
		else {
			nlRightHandSideSet(0, i, sys->delta[i][0]);
			nlRightHandSideSet(1, i, sys->delta[i][1]);
			nlRightHandSideSet(2, i, sys->delta[i][2]);
		}
	}
}

static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
{
	int vid, i, j, n, na;
	n = sys->total_verts;
	na = sys->total_anchors;

#ifdef OPENNL_THREADING_HACK
	modifier_opennl_lock();
#endif

	if (!sys->is_matrix_computed) {
		nlNewContext();
		sys->context = nlGetCurrent();

		nlSolverParameteri(NL_NB_VARIABLES, n);
		nlSolverParameteri(NL_SYMMETRIC, NL_FALSE);
		nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
		nlSolverParameteri(NL_NB_ROWS, n + na);
		nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 3);
		nlBegin(NL_SYSTEM);
		for (i = 0; i < n; i++) {
			nlSetVariable(0, i, sys->co[i][0]);
			nlSetVariable(1, i, sys->co[i][1]);
			nlSetVariable(2, i, sys->co[i][2]);
		}
		for (i = 0; i < na; i++) {
			vid = sys->index_anchors[i];
			nlSetVariable(0, vid, vertexCos[vid][0]);
			nlSetVariable(1, vid, vertexCos[vid][1]);
			nlSetVariable(2, vid, vertexCos[vid][2]);
		}
		nlBegin(NL_MATRIX);

		initLaplacianMatrix(sys);
		computeImplictRotations(sys);

		for (i = 0; i < n; i++) {
			nlRightHandSideSet(0, i, sys->delta[i][0]);
			nlRightHandSideSet(1, i, sys->delta[i][1]);
			nlRightHandSideSet(2, i, sys->delta[i][2]);
		}
		for (i = 0; i < na; i++) {
			vid = sys->index_anchors[i];
			nlRightHandSideSet(0, n + i, vertexCos[vid][0]);
			nlRightHandSideSet(1, n + i, vertexCos[vid][1]);
			nlRightHandSideSet(2, n + i, vertexCos[vid][2]);
			nlMatrixAdd(n + i, vid, 1.0f);
		}
		nlEnd(NL_MATRIX);
		nlEnd(NL_SYSTEM);
		if (nlSolveAdvanced(NULL, NL_TRUE)) {
			sys->has_solution = true;

			for (j = 1; j <= sys->repeat; j++) {
				nlBegin(NL_SYSTEM);
				nlBegin(NL_MATRIX);
				rotateDifferentialCoordinates(sys);

				for (i = 0; i < na; i++) {
					vid = sys->index_anchors[i];
					nlRightHandSideSet(0, n + i, vertexCos[vid][0]);
					nlRightHandSideSet(1, n + i, vertexCos[vid][1]);
					nlRightHandSideSet(2, n + i, vertexCos[vid][2]);
				}

				nlEnd(NL_MATRIX);
				nlEnd(NL_SYSTEM);
				if (!nlSolveAdvanced(NULL, NL_FALSE)) {
					sys->has_solution = false;
					break;
				}
			}
			if (sys->has_solution) {
				for (vid = 0; vid < sys->total_verts; vid++) {
					vertexCos[vid][0] = nlGetVariable(0, vid);
					vertexCos[vid][1] = nlGetVariable(1, vid);
					vertexCos[vid][2] = nlGetVariable(2, vid);
				}
			}
			else {
				sys->has_solution = false;
			}

		}
		else {
			sys->has_solution = false;
		}
		sys->is_matrix_computed = true;

	}
	else if (sys->has_solution) {
		nlMakeCurrent(sys->context);

		nlBegin(NL_SYSTEM);
		nlBegin(NL_MATRIX);

		for (i = 0; i < n; i++) {
			nlRightHandSideSet(0, i, sys->delta[i][0]);
			nlRightHandSideSet(1, i, sys->delta[i][1]);
			nlRightHandSideSet(2, i, sys->delta[i][2]);
		}
		for (i = 0; i < na; i++) {
			vid = sys->index_anchors[i];
			nlRightHandSideSet(0, n + i, vertexCos[vid][0]);
			nlRightHandSideSet(1, n + i, vertexCos[vid][1]);
			nlRightHandSideSet(2, n + i, vertexCos[vid][2]);
			nlMatrixAdd(n + i, vid, 1.0f);
		}

		nlEnd(NL_MATRIX);
		nlEnd(NL_SYSTEM);
		if (nlSolveAdvanced(NULL, NL_FALSE)) {
			sys->has_solution = true;
			for (j = 1; j <= sys->repeat; j++) {
				nlBegin(NL_SYSTEM);
				nlBegin(NL_MATRIX);
				rotateDifferentialCoordinates(sys);

				for (i = 0; i < na; i++) {
					vid = sys->index_anchors[i];
					nlRightHandSideSet(0, n + i, vertexCos[vid][0]);
					nlRightHandSideSet(1, n + i, vertexCos[vid][1]);
					nlRightHandSideSet(2, n + i, vertexCos[vid][2]);
				}
				nlEnd(NL_MATRIX);
				nlEnd(NL_SYSTEM);
				if (!nlSolveAdvanced(NULL, NL_FALSE)) {
					sys->has_solution = false;
					break;
				}
			}
			if (sys->has_solution) {
				for (vid = 0; vid < sys->total_verts; vid++) {
					vertexCos[vid][0] = nlGetVariable(0, vid);
					vertexCos[vid][1] = nlGetVariable(1, vid);
					vertexCos[vid][2] = nlGetVariable(2, vid);
				}
			}
			else {
				sys->has_solution = false;
			}
		}
		else {
			sys->has_solution = false;
		}
	}

#ifdef OPENNL_THREADING_HACK
	modifier_opennl_unlock();
#endif
}

static bool isValidVertexGroup(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm)
{
	int defgrp_index;
	MDeformVert *dvert = NULL;

	modifier_get_vgroup(ob, dm, lmd->anchor_grp_name, &dvert, &defgrp_index);

	return  (dvert != NULL);
}

static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm,
                       float (*vertexCos)[3], int numVerts)
{
	int i;
	int defgrp_index;
	int total_anchors;
	float wpaint;
	MDeformVert *dvert = NULL;
	MDeformVert *dv = NULL;
	LaplacianSystem *sys;

	if (isValidVertexGroup(lmd, ob, dm)) {
		int *index_anchors = MEM_mallocN(sizeof(int) * numVerts, __func__);  /* over-alloc */
		const MLoopTri *mlooptri;
		const MLoop *mloop;

		STACK_DECLARE(index_anchors);

		STACK_INIT(index_anchors, numVerts);

		modifier_get_vgroup(ob, dm, lmd->anchor_grp_name, &dvert, &defgrp_index);
		BLI_assert(dvert != NULL);
		dv = dvert;
		for (i = 0; i < numVerts; i++) {
			wpaint = defvert_find_weight(dv, defgrp_index);
			dv++;
			if (wpaint > 0.0f) {
				STACK_PUSH(index_anchors, i);
			}
		}
		DM_ensure_looptri(dm);
		total_anchors = STACK_SIZE(index_anchors);
		lmd->cache_system = initLaplacianSystem(numVerts, dm->getNumEdges(dm), dm->getNumLoopTri(dm),
		                                       total_anchors, lmd->anchor_grp_name, lmd->repeat);
		sys = (LaplacianSystem *)lmd->cache_system;
		memcpy(sys->index_anchors, index_anchors, sizeof(int) * total_anchors);
		memcpy(sys->co, vertexCos, sizeof(float[3]) * numVerts);
		MEM_freeN(index_anchors);
		lmd->vertexco = MEM_mallocN(sizeof(float[3]) * numVerts, "ModDeformCoordinates");
		memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * numVerts);
		lmd->total_verts = numVerts;

		createFaceRingMap(
		            dm->getNumVerts(dm), dm->getLoopTriArray(dm), dm->getNumLoopTri(dm),
		            dm->getLoopArray(dm), &sys->ringf_map, &sys->ringf_indices);
		createVertRingMap(
		            dm->getNumVerts(dm), dm->getEdgeArray(dm), dm->getNumEdges(dm),
		            &sys->ringv_map, &sys->ringv_indices);


		mlooptri = dm->getLoopTriArray(dm);
		mloop = dm->getLoopArray(dm);

		for (i = 0; i < sys->total_tris; i++) {
			sys->tris[i][0] = mloop[mlooptri[i].tri[0]].v;
			sys->tris[i][1] = mloop[mlooptri[i].tri[1]].v;
			sys->tris[i][2] = mloop[mlooptri[i].tri[2]].v;
		}
	}
}

static int isSystemDifferent(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm, int numVerts)
{
	int i;
	int defgrp_index;
	int total_anchors = 0;
	float wpaint;
	MDeformVert *dvert = NULL;
	MDeformVert *dv = NULL;
	LaplacianSystem *sys = (LaplacianSystem *)lmd->cache_system;

	if (sys->total_verts != numVerts) {
		return LAPDEFORM_SYSTEM_CHANGE_VERTEXES;
	}
	if (sys->total_edges != dm->getNumEdges(dm)) {
		return LAPDEFORM_SYSTEM_CHANGE_EDGES;
	}
	if (!STREQ(lmd->anchor_grp_name, sys->anchor_grp_name)) {
		return LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP;
	}
	modifier_get_vgroup(ob, dm, lmd->anchor_grp_name, &dvert, &defgrp_index);
	if (!dvert) {
		return LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP;
	}
	dv = dvert;
	for (i = 0; i < numVerts; i++) {
		wpaint = defvert_find_weight(dv, defgrp_index);
		dv++;
		if (wpaint > 0.0f) {
			total_anchors++;
		}
	}
	if (sys->total_anchors != total_anchors) {
		return LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS;
	}

	return LAPDEFORM_SYSTEM_NOT_CHANGE;
}

static void LaplacianDeformModifier_do(
        LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], int numVerts)
{
	float (*filevertexCos)[3];
	int sysdif;
	LaplacianSystem *sys = NULL;
	filevertexCos = NULL;
	if (!(lmd->flag & MOD_LAPLACIANDEFORM_BIND)) {
		if (lmd->cache_system) {
			sys = lmd->cache_system;
			deleteLaplacianSystem(sys);
			lmd->cache_system = NULL;
		}
		lmd->total_verts = 0;
		MEM_SAFE_FREE(lmd->vertexco);
		return;
	}
	if (lmd->cache_system) {
		sysdif = isSystemDifferent(lmd, ob, dm, numVerts);
		sys = lmd->cache_system;
		if (sysdif) {
			if (sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS || sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP) {
				filevertexCos = MEM_mallocN(sizeof(float[3]) * numVerts, "TempModDeformCoordinates");
				memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts);
				MEM_SAFE_FREE(lmd->vertexco);
				lmd->total_verts = 0;
				deleteLaplacianSystem(sys);
				lmd->cache_system = NULL;
				initSystem(lmd, ob, dm, filevertexCos, numVerts);
				sys = lmd->cache_system; /* may have been reallocated */
				MEM_SAFE_FREE(filevertexCos);
				if (sys) {
					laplacianDeformPreview(sys, vertexCos);
				}
			}
			else {
				if (sysdif == LAPDEFORM_SYSTEM_CHANGE_VERTEXES) {
					modifier_setError(&lmd->modifier, "Vertices changed from %d to %d", lmd->total_verts, numVerts);
				}
				else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_EDGES) {
					modifier_setError(&lmd->modifier, "Edges changed from %d to %d", sys->total_edges, dm->getNumEdges(dm));
				}
				else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP) {
					modifier_setError(&lmd->modifier, "Vertex group '%s' is not valid", sys->anchor_grp_name);
				}
			}
		}
		else {
			sys->repeat = lmd->repeat;
			laplacianDeformPreview(sys, vertexCos);
		}
	}
	else {
		if (!isValidVertexGroup(lmd, ob, dm)) {
			modifier_setError(&lmd->modifier, "Vertex group '%s' is not valid", lmd->anchor_grp_name);
			lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND;
		}
		else if (lmd->total_verts > 0 && lmd->total_verts == numVerts) {
			filevertexCos = MEM_mallocN(sizeof(float[3]) * numVerts, "TempDeformCoordinates");
			memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts);
			MEM_SAFE_FREE(lmd->vertexco);
			lmd->total_verts = 0;
			initSystem(lmd, ob, dm, filevertexCos, numVerts);
			sys = lmd->cache_system;
			MEM_SAFE_FREE(filevertexCos);
			laplacianDeformPreview(sys, vertexCos);
		}
		else {
			initSystem(lmd, ob, dm, vertexCos, numVerts);
			sys = lmd->cache_system;
			laplacianDeformPreview(sys, vertexCos);
		}
	}
	if (sys && sys->is_matrix_computed && !sys->has_solution) {
		modifier_setError(&lmd->modifier, "The system did not find a solution");
	}
}

#else  /* WITH_OPENNL */
static void LaplacianDeformModifier_do(
        LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], int numVerts)
{
	UNUSED_VARS(lmd, ob, dm, vertexCos, numVerts);
}