fix [#27839] UV 'Project from view' ignores camera lens shift
[blender.git] / source / blender / blenlib / intern / uvproject.c
index d6ba2d7da948acd2c53f4cc99437b9a2b7f0e16e..ecb42315ee3a4c33a3007dad76138784915fdcf7 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/blenlib/intern/uvproject.c
+ *  \ingroup bli
+ */
+
+
 #include <math.h>
 
 #include "MEM_guardedalloc.h"
@@ -28,6 +33,7 @@
 #include "DNA_object_types.h"
 
 #include "BLI_math.h"
+#include "BLI_uvproject.h"
 
 typedef struct UvCameraInfo {
        float camangle;
@@ -36,7 +42,7 @@ typedef struct UvCameraInfo {
        float shiftx, shifty;
        float rotmat[4][4];
        float caminv[4][4];
-       short do_persp, do_pano;
+       short do_persp, do_pano, do_rotmat;
 } UvCameraInfo;
 
 void project_from_camera(float target[2], float source[3], UvCameraInfo *uci)
@@ -47,36 +53,42 @@ void project_from_camera(float target[2], float source[3], UvCameraInfo *uci)
        pv4[3]= 1.0;
 
        /* rotmat is the object matrix in this case */
-       mul_m4_v4(uci->rotmat, pv4);
+       if(uci->do_rotmat)
+               mul_m4_v4(uci->rotmat, pv4);
 
        /* caminv is the inverse camera matrix */
        mul_m4_v4(uci->caminv, pv4);
 
        if(uci->do_pano) {
-               float angle= atan2f(pv4[0], -pv4[2]) / (M_PI * 2.0); /* angle around the camera */
+               float angle= atan2f(pv4[0], -pv4[2]) / ((float)M_PI * 2.0f); /* angle around the camera */
                if (uci->do_persp==0) {
-                       target[0] = angle; /* no correct method here, just map to  0-1 */
-                       target[1] = pv4[1] / uci->camsize;
+                       target[0]= angle; /* no correct method here, just map to  0-1 */
+                       target[1]= pv4[1] / uci->camsize;
                }
                else {
-                       float vec2d[2]= {pv4[0], pv4[2]}; /* 2D position from the camera */
-                       target[0] = angle * (M_PI / uci->camangle);
-                       target[1] = pv4[1] / (len_v2(vec2d) * uci->camsize);
+                       float vec2d[2]; /* 2D position from the camera */
+                       vec2d[0]= pv4[0];
+                       vec2d[1]= pv4[2];
+                       target[0]= angle * ((float)M_PI / uci->camangle);
+                       target[1]= pv4[1] / (len_v2(vec2d) * uci->camsize);
                }
        }
        else {
                if (pv4[2]==0.0f) pv4[2]= 0.00001f; /* don't allow div by 0 */
 
                if (uci->do_persp==0) {
-                       target[0]=(pv4[0]/uci->camsize) * uci->xasp;
-                       target[1]=(pv4[1]/uci->camsize) * uci->yasp;
+                       target[0]= (pv4[0]/uci->camsize);
+                       target[1]= (pv4[1]/uci->camsize);
                }
                else {
-                       target[0]=(-pv4[0]*((1.0f/uci->camsize)/pv4[2])*uci->xasp) / 2.0f;
-                       target[1]=(-pv4[1]*((1.0f/uci->camsize)/pv4[2])*uci->yasp) / 2.0f;
+                       target[0]= (-pv4[0]*((1.0f/uci->camsize)/pv4[2])) / 2.0f;
+                       target[1]= (-pv4[1]*((1.0f/uci->camsize)/pv4[2])) / 2.0f;
                }
        }
 
+       target[0] *= uci->xasp;
+       target[1] *= uci->yasp;
+       
        /* adds camera shift + 0.5 */
        target[0] += uci->shiftx;
        target[1] += uci->shifty;
@@ -87,7 +99,7 @@ void project_from_view(float target[2], float source[3], float persmat[4][4], fl
 {
        float pv[3], pv4[4], x= 0.0, y= 0.0;
 
-       mul_m4_v3(rotmat, pv);
+       mul_v3_m4v3(pv, rotmat, source);
 
        copy_v3_v3(pv4, source);
        pv4[3]= 1.0;
@@ -97,23 +109,23 @@ void project_from_view(float target[2], float source[3], float persmat[4][4], fl
 
        /* almost project_short */
        mul_m4_v4(persmat, pv4);
-       if(fabs(pv4[3]) > 0.00001) { /* avoid division by zero */
-               target[0] = winx/2.0 + (winx/2.0) * pv4[0] / pv4[3];
-               target[1] = winy/2.0 + (winy/2.0) * pv4[1] / pv4[3];
+       if(fabsf(pv4[3]) > 0.00001f) { /* avoid division by zero */
+               target[0] = winx/2.0f + (winx/2.0f) * pv4[0] / pv4[3];
+               target[1] = winy/2.0f + (winy/2.0f) * pv4[1] / pv4[3];
        }
        else {
                /* scaling is lost but give a valid result */
-               target[0] = winx/2.0 + (winx/2.0) * pv4[0];
-               target[1] = winy/2.0 + (winy/2.0) * pv4[1];
+               target[0] = winx/2.0f + (winx/2.0f) * pv4[0];
+               target[1] = winy/2.0f + (winy/2.0f) * pv4[1];
        }
 
        /* v3d->persmat seems to do this funky scaling */ 
        if(winx > winy) {
-               y= (winx - winy)/2.0;
+               y= (winx - winy)/2.0f;
                winy = winx;
        }
        else {
-               x= (winy - winx)/2.0;
+               x= (winy - winx)/2.0f;
                winx = winy;
        }
 
@@ -123,7 +135,7 @@ void project_from_view(float target[2], float source[3], float persmat[4][4], fl
 
 /* 'rotmat' can be obedit->obmat when uv project is used.
  * 'winx' and 'winy' can be from scene->r.xsch/ysch */ 
-UvCameraInfo *project_camera_info(Object *ob, float rotmat[4][4], float winx, float winy)
+UvCameraInfo *project_camera_info(Object *ob, float (*rotmat)[4], float winx, float winy)
 {
        UvCameraInfo uci;
        Camera *camera= ob->data;
@@ -131,14 +143,20 @@ UvCameraInfo *project_camera_info(Object *ob, float rotmat[4][4], float winx, fl
        uci.do_pano = (camera->flag & CAM_PANORAMA);
        uci.do_persp = (camera->type==CAM_PERSP);
 
-       uci.camangle= DEG2RAD(camera->angle)/2.0f;
-       uci.camsize=  uci.do_persp ?  uci.camsize= tanf(uci.camangle) : camera->ortho_scale;
+       uci.camangle= lens_to_angle(camera->lens) / 2.0f;
+       uci.camsize= uci.do_persp ? tanf(uci.camangle) : camera->ortho_scale;
 
        if (invert_m4_m4(uci.caminv, ob->obmat)) {
                UvCameraInfo *uci_pt;
 
                /* normal projection */
-               copy_m4_m4(uci.rotmat, rotmat);
+               if(rotmat) {
+                       copy_m4_m4(uci.rotmat, rotmat);
+                       uci.do_rotmat= 1;
+               }
+               else {
+                       uci.do_rotmat= 0;
+               }
 
                /* also make aspect ratio adjustment factors */
                if (winx > winy) {
@@ -151,8 +169,8 @@ UvCameraInfo *project_camera_info(Object *ob, float rotmat[4][4], float winx, fl
                }
                
                /* include 0.5f here to move the UVs into the center */
-               uci.shiftx = 0.5f - camera->shiftx;
-               uci.shifty = 0.5f - camera->shifty;
+               uci.shiftx = 0.5f - (camera->shiftx * uci.xasp);
+               uci.shifty = 0.5f - (camera->shifty * uci.yasp);
                
                uci_pt= MEM_mallocN(sizeof(UvCameraInfo), "UvCameraInfo");
                *uci_pt= uci;
@@ -166,9 +184,16 @@ void project_from_view_ortho(float target[2], float source[3], float rotmat[4][4
 {
        float pv[3];
 
-       mul_m4_v3(rotmat, pv);
+       mul_v3_m4v3(pv, rotmat, source);
 
        /* ortho projection */
        target[0] = -pv[0];
        target[1] = pv[2];
 }
+
+
+void project_camera_info_scale(UvCameraInfo *uci, float scale_x, float scale_y)
+{
+       uci->xasp *= scale_x;
+       uci->yasp *= scale_y;
+}