示例#1
0
static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
{
  Object *camera = scene->camera;

  if (camera != NULL && BKE_object_movieclip_get(scene, camera, false) == clip) {
    return camera;
  }

  FOREACH_SCENE_OBJECT_BEGIN (scene, ob) {
    if (ob->type == OB_CAMERA) {
      if (BKE_object_movieclip_get(scene, ob, false) == clip) {
        camera = ob;
        break;
      }
    }
  }
  FOREACH_SCENE_OBJECT_END;

  return camera;
}
示例#2
0
static void bundle_midpoint(Scene *scene, Object *ob, float vec[3])
{
	MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
	MovieTracking *tracking;
	MovieTrackingObject *object;
	bool ok = false;
	float min[3], max[3], mat[4][4], pos[3], cammat[4][4];

	if (!clip)
		return;

	tracking = &clip->tracking;

	copy_m4_m4(cammat, ob->obmat);

	BKE_tracking_get_camera_object_matrix(scene, ob, mat);

	INIT_MINMAX(min, max);

	for (object = tracking->objects.first; object; object = object->next) {
		ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
		MovieTrackingTrack *track = tracksbase->first;
		float obmat[4][4];

		if (object->flag & TRACKING_OBJECT_CAMERA) {
			copy_m4_m4(obmat, mat);
		}
		else {
			float imat[4][4];

			BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, scene->r.cfra, imat);
			invert_m4(imat);

			mul_m4_m4m4(obmat, cammat, imat);
		}

		while (track) {
			if ((track->flag & TRACK_HAS_BUNDLE) && TRACK_SELECTED(track)) {
				ok = 1;
				mul_v3_m4v3(pos, obmat, track->bundle_pos);
				minmax_v3v3_v3(min, max, pos);
			}

			track = track->next;
		}
	}

	if (ok) {
		mid_v3_v3v3(vec, min, max);
	}
}
示例#3
0
static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
{
    Object *camera = scene->camera;

    if (camera != NULL &&
            BKE_object_movieclip_get(scene, camera, false) == clip)
    {
        return camera;
    }

    for (Base *base = scene->base.first;
            base != NULL;
            base = base->next)
    {
        if (base->object->type == OB_CAMERA) {
            if (BKE_object_movieclip_get(scene, base->object, false) == clip) {
                camera = base->object;
                break;
            }
        }
    }

    return camera;
}
示例#4
0
/* reads full rect, converts indices */
uint *ED_view3d_select_id_read(int xmin, int ymin, int xmax, int ymax, uint *r_buf_len)
{
  if (UNLIKELY((xmin > xmax) || (ymin > ymax))) {
    return NULL;
  }

  const rcti rect = {
      .xmin = xmin,
      .xmax = xmax + 1,
      .ymin = ymin,
      .ymax = ymax + 1,
  };

  uint buf_len;
  uint *buf = ED_view3d_select_id_read_rect(&rect, &buf_len);

  if (r_buf_len) {
    *r_buf_len = buf_len;
  }

  return buf;
}

/* ************************************************************* */

static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
{
  if (BKE_image_is_stereo(ima)) {
    iuser->flag |= IMA_SHOW_STEREO;

    if ((scene->r.scemode & R_MULTIVIEW) == 0) {
      iuser->multiview_eye = STEREO_LEFT_ID;
    }
    else if (v3d->stereo3d_camera != STEREO_3D_ID) {
      /* show only left or right camera */
      iuser->multiview_eye = v3d->stereo3d_camera;
    }

    BKE_image_multiview_index(ima, iuser);
  }
  else {
    iuser->flag &= ~IMA_SHOW_STEREO;
  }
}

static void view3d_draw_bgpic(Scene *scene,
                              Depsgraph *depsgraph,
                              ARegion *ar,
                              View3D *v3d,
                              const bool do_foreground,
                              const bool do_camera_frame)
{
  RegionView3D *rv3d = ar->regiondata;
  int fg_flag = do_foreground ? CAM_BGIMG_FLAG_FOREGROUND : 0;
  if (v3d->camera == NULL || v3d->camera->type != OB_CAMERA) {
    return;
  }
  Camera *cam = v3d->camera->data;

  for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
    if ((bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != fg_flag) {
      continue;
    }

    {
      float image_aspect[2];
      float x1, y1, x2, y2, centx, centy;

      void *lock;

      Image *ima = NULL;

      /* disable individual images */
      if ((bgpic->flag & CAM_BGIMG_FLAG_DISABLED)) {
        continue;
      }

      ImBuf *ibuf = NULL;
      ImBuf *freeibuf = NULL;
      ImBuf *releaseibuf = NULL;
      if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
        ima = bgpic->ima;
        if (ima == NULL) {
          continue;
        }

        ImageUser iuser = bgpic->iuser;
        iuser.scene = scene; /* Needed for render results. */
        BKE_image_user_frame_calc(&iuser, (int)DEG_get_ctime(depsgraph));
        if (ima->source == IMA_SRC_SEQUENCE && !(iuser.flag & IMA_USER_FRAME_IN_RANGE)) {
          ibuf = NULL; /* frame is out of range, dont show */
        }
        else {
          view3d_stereo_bgpic_setup(scene, v3d, ima, &iuser);
          ibuf = BKE_image_acquire_ibuf(ima, &iuser, &lock);
          releaseibuf = ibuf;
        }

        image_aspect[0] = ima->aspx;
        image_aspect[1] = ima->aspy;
      }
      else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
        /* TODO: skip drawing when out of frame range (as image sequences do above) */
        MovieClip *clip = NULL;

        if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
          if (scene->camera) {
            clip = BKE_object_movieclip_get(scene, scene->camera, true);
          }
        }
        else {
          clip = bgpic->clip;
        }

        if (clip == NULL) {
          continue;
        }

        BKE_movieclip_user_set_frame(&bgpic->cuser, (int)DEG_get_ctime(depsgraph));
        ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser);

        image_aspect[0] = clip->aspx;
        image_aspect[1] = clip->aspy;

        /* working with ibuf from image and clip has got different workflow now.
         * ibuf acquired from clip is referenced by cache system and should
         * be dereferenced after usage. */
        freeibuf = ibuf;
      }
      else {
        /* perhaps when loading future files... */
        BLI_assert(0);
        copy_v2_fl(image_aspect, 1.0f);
      }

      if (ibuf == NULL) {
        continue;
      }

      if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) {
        /* invalid image format */
        if (freeibuf) {
          IMB_freeImBuf(freeibuf);
        }
        if (releaseibuf) {
          BKE_image_release_ibuf(ima, releaseibuf, lock);
        }

        continue;
      }

      if (ibuf->rect == NULL) {
        IMB_rect_from_float(ibuf);
      }

      BLI_assert(rv3d->persp == RV3D_CAMOB);
      {
        if (do_camera_frame) {
          rctf vb;
          ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false);
          x1 = vb.xmin;
          y1 = vb.ymin;
          x2 = vb.xmax;
          y2 = vb.ymax;
        }
        else {
          x1 = ar->winrct.xmin;
          y1 = ar->winrct.ymin;
          x2 = ar->winrct.xmax;
          y2 = ar->winrct.ymax;
        }

        /* apply offset last - camera offset is different to offset in blender units */
        /* so this has some sane way of working - this matches camera's shift _exactly_ */
        {
          const float max_dim = max_ff(x2 - x1, y2 - y1);
          const float xof_scale = bgpic->offset[0] * max_dim;
          const float yof_scale = bgpic->offset[1] * max_dim;

          x1 += xof_scale;
          y1 += yof_scale;
          x2 += xof_scale;
          y2 += yof_scale;
        }

        centx = (x1 + x2) * 0.5f;
        centy = (y1 + y2) * 0.5f;

        /* aspect correction */
        if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
          /* apply aspect from clip */
          const float w_src = ibuf->x * image_aspect[0];
          const float h_src = ibuf->y * image_aspect[1];

          /* destination aspect is already applied from the camera frame */
          const float w_dst = x1 - x2;
          const float h_dst = y1 - y2;

          const float asp_src = w_src / h_src;
          const float asp_dst = w_dst / h_dst;

          if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
            if ((asp_src > asp_dst) == ((bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) != 0)) {
              /* fit X */
              const float div = asp_src / asp_dst;
              x1 = ((x1 - centx) * div) + centx;
              x2 = ((x2 - centx) * div) + centx;
            }
            else {
              /* fit Y */
              const float div = asp_dst / asp_src;
              y1 = ((y1 - centy) * div) + centy;
              y2 = ((y2 - centy) * div) + centy;
            }
          }
        }
      }

      /* complete clip? */
      rctf clip_rect;
      BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
      if (bgpic->rotation) {
        BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
      }

      if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx ||
          clip_rect.ymin > ar->winy) {
        if (freeibuf) {
          IMB_freeImBuf(freeibuf);
        }
        if (releaseibuf) {
          BKE_image_release_ibuf(ima, releaseibuf, lock);
        }

        continue;
      }

      float zoomx = (x2 - x1) / ibuf->x;
      float zoomy = (y2 - y1) / ibuf->y;

      /* For some reason; zoom-levels down refuses to use GL_ALPHA_SCALE. */
      if (zoomx < 1.0f || zoomy < 1.0f) {
        float tzoom = min_ff(zoomx, zoomy);
        int mip = 0;

        if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) {
          IMB_remakemipmap(ibuf, 0);
          ibuf->userflags &= ~IB_MIPMAP_INVALID;
        }
        else if (ibuf->mipmap[0] == NULL) {
          IMB_makemipmap(ibuf, 0);
        }

        while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) {
          tzoom *= 2.0f;
          zoomx *= 2.0f;
          zoomy *= 2.0f;
          mip++;
        }
        if (mip > 0) {
          ibuf = ibuf->mipmap[mip - 1];
        }
      }

      GPU_depth_test(!do_foreground);
      glDepthMask(GL_FALSE);

      GPU_blend(true);
      GPU_blend_set_func_separate(
          GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);

      GPU_matrix_push_projection();
      GPU_matrix_push();
      ED_region_pixelspace(ar);

      GPU_matrix_translate_2f(centx, centy);
      GPU_matrix_scale_1f(bgpic->scale);
      GPU_matrix_rotate_2d(RAD2DEGF(-bgpic->rotation));

      if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) {
        zoomx *= -1.0f;
        x1 = x2;
      }
      if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) {
        zoomy *= -1.0f;
        y1 = y2;
      }

      float col[4] = {1.0f, 1.0f, 1.0f, bgpic->alpha};
      IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
      immDrawPixelsTex(&state,
                       x1 - centx,
                       y1 - centy,
                       ibuf->x,
                       ibuf->y,
                       GL_RGBA,
                       GL_UNSIGNED_BYTE,
                       GL_LINEAR,
                       ibuf->rect,
                       zoomx,
                       zoomy,
                       col);

      GPU_matrix_pop_projection();
      GPU_matrix_pop();

      GPU_blend(false);

      glDepthMask(GL_TRUE);
      GPU_depth_test(true);

      if (freeibuf) {
        IMB_freeImBuf(freeibuf);
      }
      if (releaseibuf) {
        BKE_image_release_ibuf(ima, releaseibuf, lock);
      }
    }
  }
}
static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, bool apply_rot, bool apply_scale)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
	bool changed = true;
	
	/* first check if we can execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{
		if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) {
			ID *obdata = ob->data;
			if (ID_REAL_USERS(obdata) > 1) {
				BKE_reportf(reports, RPT_ERROR,
				            "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}

			if (obdata->lib) {
				BKE_reportf(reports, RPT_ERROR,
				            "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
		}

		if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			ID *obdata = ob->data;
			Curve *cu;

			cu = ob->data;

			if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) {
				BKE_reportf(reports, RPT_ERROR,
				            "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
			if (cu->key) {
				BKE_reportf(reports, RPT_ERROR,
				            "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
		}

		if (ob->type == OB_FONT) {
			if (apply_rot || apply_loc) {
				BKE_reportf(reports, RPT_ERROR,
				            "Font's can only have scale applied: \"%s\"",
				            ob->id.name + 2);
				changed = false;
			}
		}
	}
	CTX_DATA_END;
	
	if (!changed)
		return OPERATOR_CANCELLED;

	changed = false;

	/* now execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{

		/* calculate rotation/scale matrix */
		if (apply_scale && apply_rot)
			BKE_object_to_mat3(ob, rsmat);
		else if (apply_scale)
			BKE_object_scale_to_mat3(ob, rsmat);
		else if (apply_rot) {
			float tmat[3][3], timat[3][3];

			/* simple rotation matrix */
			BKE_object_rot_to_mat3(ob, rsmat, true);

			/* correct for scale, note mul_m3_m3m3 has swapped args! */
			BKE_object_scale_to_mat3(ob, tmat);
			invert_m3_m3(timat, tmat);
			mul_m3_m3m3(rsmat, timat, rsmat);
			mul_m3_m3m3(rsmat, rsmat, tmat);
		}
		else
			unit_m3(rsmat);

		copy_m4_m3(mat, rsmat);

		/* calculate translation */
		if (apply_loc) {
			copy_v3_v3(mat[3], ob->loc);

			if (!(apply_scale && apply_rot)) {
				float tmat[3][3];
				/* correct for scale and rotation that is still applied */
				BKE_object_to_mat3(ob, obmat);
				invert_m3_m3(iobmat, obmat);
				mul_m3_m3m3(tmat, rsmat, iobmat);
				mul_m3_v3(tmat, mat[3]);
			}
		}

		/* apply to object data */
		if (ob->type == OB_MESH) {
			Mesh *me = ob->data;

			if (apply_scale)
				multiresModifier_scale_disp(scene, ob);
			
			/* adjust data */
			BKE_mesh_transform(me, mat, true);
			
			/* update normals */
			BKE_mesh_calc_normals(me);
		}
		else if (ob->type == OB_ARMATURE) {
			ED_armature_apply_transform(ob, mat);
		}
		else if (ob->type == OB_LATTICE) {
			Lattice *lt = ob->data;

			BKE_lattice_transform(lt, mat, true);
		}
		else if (ob->type == OB_MBALL) {
			MetaBall *mb = ob->data;
			BKE_mball_transform(mb, mat);
		}
		else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			Curve *cu = ob->data;
			scale = mat3_to_scale(rsmat);
			BKE_curve_transform_ex(cu, mat, true, scale);
		}
		else if (ob->type == OB_FONT) {
			Curve *cu = ob->data;
			int i;

			scale = mat3_to_scale(rsmat);

			for (i = 0; i < cu->totbox; i++) {
				TextBox *tb = &cu->tb[i];
				tb->x *= scale;
				tb->y *= scale;
				tb->w *= scale;
				tb->h *= scale;
			}

			cu->fsize *= scale;
		}
		else if (ob->type == OB_CAMERA) {
			MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);

			/* applying scale on camera actually scales clip's reconstruction.
			 * of there's clip assigned to camera nothing to do actually.
			 */
			if (!clip)
				continue;

			if (apply_scale)
				BKE_tracking_reconstruction_scale(&clip->tracking, ob->size);
		}
		else if (ob->type == OB_EMPTY) {
			/* It's possible for empties too, even though they don't 
			 * really have obdata, since we can simply apply the maximum
			 * scaling to the empty's drawsize.
			 *
			 * Core Assumptions:
			 * 1) Most scaled empties have uniform scaling 
			 *    (i.e. for visibility reasons), AND/OR
			 * 2) Preserving non-uniform scaling is not that important,
			 *    and is something that many users would be willing to
			 *    sacrifice for having an easy way to do this.
			 */

			if ((apply_loc == false) &&
			    (apply_rot == false) &&
			    (apply_scale == true))
			{
				float max_scale = max_fff(fabsf(ob->size[0]), fabsf(ob->size[1]), fabsf(ob->size[2]));
				ob->empty_drawsize *= max_scale;
			}
		}
		else {
			continue;
		}

		if (apply_loc)
			zero_v3(ob->loc);
		if (apply_scale)
			ob->size[0] = ob->size[1] = ob->size[2] = 1.0f;
		if (apply_rot) {
			zero_v3(ob->rot);
			unit_qt(ob->quat);
			unit_axis_angle(ob->rotAxis, &ob->rotAngle);
		}

		BKE_object_where_is_calc(scene, ob);
		if (ob->type == OB_ARMATURE) {
			BKE_pose_where_is(scene, ob); /* needed for bone parents */
		}

		ignore_parent_tx(bmain, scene, ob);

		DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);

		changed = true;
	}
	CTX_DATA_END;

	if (!changed) {
		BKE_report(reports, RPT_WARNING, "Objects have no data to transform");
		return OPERATOR_CANCELLED;
	}

	WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
	return OPERATOR_FINISHED;
}
示例#6
0
static int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
	int change = 1;
	
	/* first check if we can execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{

		if (ob->type == OB_MESH) {
			if (ID_REAL_USERS(ob->data) > 1) {
				BKE_report(reports, RPT_ERROR, "Cannot apply to a multi user mesh, doing nothing");
				change = 0;
			}
		}
		else if (ob->type == OB_ARMATURE) {
			if (ID_REAL_USERS(ob->data) > 1) {
				BKE_report(reports, RPT_ERROR, "Cannot apply to a multi user armature, doing nothing");
				change = 0;
			}
		}
		else if (ob->type == OB_LATTICE) {
			if (ID_REAL_USERS(ob->data) > 1) {
				BKE_report(reports, RPT_ERROR, "Cannot apply to a multi user lattice, doing nothing");
				change = 0;
			}
		}
		else if (ob->type == OB_MBALL) {
			if (ID_REAL_USERS(ob->data) > 1) {
				BKE_report(reports, RPT_ERROR, "Cannot apply to a multi user metaball, doing nothing");
				change = 0;
			}
		}
		else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			Curve *cu;

			if (ID_REAL_USERS(ob->data) > 1) {
				BKE_report(reports, RPT_ERROR, "Cannot apply to a multi user curve, doing nothing");
				change = 0;
			}

			cu = ob->data;

			if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) {
				BKE_report(reports, RPT_ERROR,
				           "Neither rotation nor location could be applied to a 2D curve, doing nothing");
				change = 0;
			}
			if (cu->key) {
				BKE_report(reports, RPT_ERROR, "Cannot apply to a curve with vertex keys, doing nothing");
				change = 0;
			}
		}
	}
	CTX_DATA_END;
	
	if (!change)
		return OPERATOR_CANCELLED;

	change = 0;

	/* now execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{

		/* calculate rotation/scale matrix */
		if (apply_scale && apply_rot)
			BKE_object_to_mat3(ob, rsmat);
		else if (apply_scale)
			BKE_object_scale_to_mat3(ob, rsmat);
		else if (apply_rot) {
			float tmat[3][3], timat[3][3];

			/* simple rotation matrix */
			BKE_object_rot_to_mat3(ob, rsmat, TRUE);

			/* correct for scale, note mul_m3_m3m3 has swapped args! */
			BKE_object_scale_to_mat3(ob, tmat);
			invert_m3_m3(timat, tmat);
			mul_m3_m3m3(rsmat, timat, rsmat);
			mul_m3_m3m3(rsmat, rsmat, tmat);
		}
		else
			unit_m3(rsmat);

		copy_m4_m3(mat, rsmat);

		/* calculate translation */
		if (apply_loc) {
			copy_v3_v3(mat[3], ob->loc);

			if (!(apply_scale && apply_rot)) {
				float tmat[3][3];
				/* correct for scale and rotation that is still applied */
				BKE_object_to_mat3(ob, obmat);
				invert_m3_m3(iobmat, obmat);
				mul_m3_m3m3(tmat, rsmat, iobmat);
				mul_m3_v3(tmat, mat[3]);
			}
		}

		/* apply to object data */
		if (ob->type == OB_MESH) {
			Mesh *me = ob->data;
			MVert *mvert;
			int a;

			if (apply_scale)
				multiresModifier_scale_disp(scene, ob);
			
			/* adjust data */
			mvert = me->mvert;
			for (a = 0; a < me->totvert; a++, mvert++)
				mul_m4_v3(mat, mvert->co);
			
			if (me->key) {
				KeyBlock *kb;
				
				for (kb = me->key->block.first; kb; kb = kb->next) {
					float *fp = kb->data;
					
					for (a = 0; a < kb->totelem; a++, fp += 3)
						mul_m4_v3(mat, fp);
				}
			}
			
			/* update normals */
			BKE_mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
		}
		else if (ob->type == OB_ARMATURE) {
			ED_armature_apply_transform(ob, mat);
		}
		else if (ob->type == OB_LATTICE) {
			Lattice *lt = ob->data;
			BPoint *bp = lt->def;
			int a = lt->pntsu * lt->pntsv * lt->pntsw;
			
			while (a--) {
				mul_m4_v3(mat, bp->vec);
				bp++;
			}
		}
		else if (ob->type == OB_MBALL) {
			MetaBall *mb = ob->data;
			ED_mball_transform(mb, (float *)mat);
		}
		else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			Curve *cu = ob->data;

			Nurb *nu;
			BPoint *bp;
			BezTriple *bezt;
			int a;

			scale = mat3_to_scale(rsmat);

			for (nu = cu->nurb.first; nu; nu = nu->next) {
				if (nu->type == CU_BEZIER) {
					a = nu->pntsu;
					for (bezt = nu->bezt; a--; bezt++) {
						mul_m4_v3(mat, bezt->vec[0]);
						mul_m4_v3(mat, bezt->vec[1]);
						mul_m4_v3(mat, bezt->vec[2]);
						bezt->radius *= scale;
					}
					BKE_nurb_handles_calc(nu);
				}
				else {
					a = nu->pntsu * nu->pntsv;
					for (bp = nu->bp; a--; bp++)
						mul_m4_v3(mat, bp->vec);
				}
			}
		}
		else if (ob->type == OB_CAMERA) {
			MovieClip *clip = BKE_object_movieclip_get(scene, ob, FALSE);

			/* applying scale on camera actually scales clip's reconstruction.
			 * of there's clip assigned to camera nothing to do actually.
			 */
			if (!clip)
				continue;

			if (apply_scale)
				BKE_tracking_reconstruction_scale(&clip->tracking, ob->size);
		}
		else {
			continue;
		}

		if (apply_loc)
			zero_v3(ob->loc);
		if (apply_scale)
			ob->size[0] = ob->size[1] = ob->size[2] = 1.0f;
		if (apply_rot) {
			zero_v3(ob->rot);
			unit_qt(ob->quat);
			unit_axis_angle(ob->rotAxis, &ob->rotAngle);
		}

		BKE_object_where_is_calc(scene, ob);
		if (ob->type == OB_ARMATURE) {
			BKE_pose_where_is(scene, ob); /* needed for bone parents */
		}

		ignore_parent_tx(bmain, scene, ob);

		DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);

		change = 1;
	}
	CTX_DATA_END;

	if (!change)
		return OPERATOR_CANCELLED;

	WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
	return OPERATOR_FINISHED;
}
static int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
	bool changed = true;
	
	/* first check if we can execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{
		if (ELEM6(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) {
			ID *obdata = ob->data;
			if (ID_REAL_USERS(obdata) > 1) {
				BKE_reportf(reports, RPT_ERROR,
				            "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}

			if (obdata->lib) {
				BKE_reportf(reports, RPT_ERROR,
				            "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
		}

		if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			ID *obdata = ob->data;
			Curve *cu;

			cu = ob->data;

			if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) {
				BKE_reportf(reports, RPT_ERROR,
				            "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
			if (cu->key) {
				BKE_reportf(reports, RPT_ERROR,
				            "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
		}
	}
	CTX_DATA_END;
	
	if (!changed)
		return OPERATOR_CANCELLED;

	changed = false;

	/* now execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{

		/* calculate rotation/scale matrix */
		if (apply_scale && apply_rot)
			BKE_object_to_mat3(ob, rsmat);
		else if (apply_scale)
			BKE_object_scale_to_mat3(ob, rsmat);
		else if (apply_rot) {
			float tmat[3][3], timat[3][3];

			/* simple rotation matrix */
			BKE_object_rot_to_mat3(ob, rsmat, TRUE);

			/* correct for scale, note mul_m3_m3m3 has swapped args! */
			BKE_object_scale_to_mat3(ob, tmat);
			invert_m3_m3(timat, tmat);
			mul_m3_m3m3(rsmat, timat, rsmat);
			mul_m3_m3m3(rsmat, rsmat, tmat);
		}
		else
			unit_m3(rsmat);

		copy_m4_m3(mat, rsmat);

		/* calculate translation */
		if (apply_loc) {
			copy_v3_v3(mat[3], ob->loc);

			if (!(apply_scale && apply_rot)) {
				float tmat[3][3];
				/* correct for scale and rotation that is still applied */
				BKE_object_to_mat3(ob, obmat);
				invert_m3_m3(iobmat, obmat);
				mul_m3_m3m3(tmat, rsmat, iobmat);
				mul_m3_v3(tmat, mat[3]);
			}
		}

		/* apply to object data */
		if (ob->type == OB_MESH) {
			Mesh *me = ob->data;
			MVert *mvert;
			int a;

			if (apply_scale)
				multiresModifier_scale_disp(scene, ob);
			
			/* adjust data */
			mvert = me->mvert;
			for (a = 0; a < me->totvert; a++, mvert++)
				mul_m4_v3(mat, mvert->co);
			
			if (me->key) {
				KeyBlock *kb;
				
				for (kb = me->key->block.first; kb; kb = kb->next) {
					float *fp = kb->data;
					
					for (a = 0; a < kb->totelem; a++, fp += 3)
						mul_m4_v3(mat, fp);
				}
			}
			
			/* update normals */
			BKE_mesh_calc_normals(me);
		}
		else if (ob->type == OB_ARMATURE) {
			ED_armature_apply_transform(ob, mat);
		}
		else if (ob->type == OB_LATTICE) {
			Lattice *lt = ob->data;
			BPoint *bp = lt->def;
			int a = lt->pntsu * lt->pntsv * lt->pntsw;
			
			while (a--) {
				mul_m4_v3(mat, bp->vec);
				bp++;
			}
		}
		else if (ob->type == OB_MBALL) {
			MetaBall *mb = ob->data;
			ED_mball_transform(mb, mat);
		}
		else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			Curve *cu = ob->data;

			Nurb *nu;
			BPoint *bp;
			BezTriple *bezt;
			int a;

			scale = mat3_to_scale(rsmat);

			for (nu = cu->nurb.first; nu; nu = nu->next) {
				if (nu->type == CU_BEZIER) {
					a = nu->pntsu;
					for (bezt = nu->bezt; a--; bezt++) {
						mul_m4_v3(mat, bezt->vec[0]);
						mul_m4_v3(mat, bezt->vec[1]);
						mul_m4_v3(mat, bezt->vec[2]);
						bezt->radius *= scale;
					}
					BKE_nurb_handles_calc(nu);
				}
				else {
					a = nu->pntsu * nu->pntsv;
					for (bp = nu->bp; a--; bp++)
						mul_m4_v3(mat, bp->vec);
				}
			}
		}
		else if (ob->type == OB_CAMERA) {
			MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);

			/* applying scale on camera actually scales clip's reconstruction.
			 * of there's clip assigned to camera nothing to do actually.
			 */
			if (!clip)
				continue;

			if (apply_scale)
				BKE_tracking_reconstruction_scale(&clip->tracking, ob->size);
		}
		else if (ob->type == OB_EMPTY) {
			/* It's possible for empties too, even though they don't 
			 * really have obdata, since we can simply apply the maximum
			 * scaling to the empty's drawsize.
			 *
			 * Core Assumptions:
			 * 1) Most scaled empties have uniform scaling 
			 *    (i.e. for visibility reasons), AND/OR
			 * 2) Preserving non-uniform scaling is not that important,
			 *    and is something that many users would be willing to
			 *    sacrifice for having an easy way to do this.
			 */
			 float max_scale = MAX3(ob->size[0], ob->size[1], ob->size[2]);
			 ob->empty_drawsize *= max_scale;
		}
		else {
			continue;
		}

		if (apply_loc)
			zero_v3(ob->loc);
		if (apply_scale)
			ob->size[0] = ob->size[1] = ob->size[2] = 1.0f;
		if (apply_rot) {
			zero_v3(ob->rot);
			unit_qt(ob->quat);
			unit_axis_angle(ob->rotAxis, &ob->rotAngle);
		}

		BKE_object_where_is_calc(scene, ob);
		if (ob->type == OB_ARMATURE) {
			BKE_pose_where_is(scene, ob); /* needed for bone parents */
		}

		ignore_parent_tx(bmain, scene, ob);

		DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);

		changed = true;
	}
	CTX_DATA_END;

	if (!changed) {
		BKE_report(reports, RPT_WARNING, "Objects have no data to transform");
		return OPERATOR_CANCELLED;
	}

	WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
	return OPERATOR_FINISHED;
}