Blender  V2.59
uvproject.c
Go to the documentation of this file.
00001 /*
00002  * $Id: uvproject.c 38054 2011-07-03 10:48:18Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * ***** END GPL LICENSE BLOCK *****
00021  */
00022 
00028 #include <math.h>
00029 
00030 #include "MEM_guardedalloc.h"
00031 
00032 #include "DNA_camera_types.h"
00033 #include "DNA_object_types.h"
00034 
00035 #include "BLI_math.h"
00036 #include "BLI_uvproject.h"
00037 
00038 typedef struct UvCameraInfo {
00039         float camangle;
00040         float camsize;
00041         float xasp, yasp;
00042         float shiftx, shifty;
00043         float rotmat[4][4];
00044         float caminv[4][4];
00045         short do_persp, do_pano, do_rotmat;
00046 } UvCameraInfo;
00047 
00048 void project_from_camera(float target[2], float source[3], UvCameraInfo *uci)
00049 {
00050         float pv4[4];
00051 
00052         copy_v3_v3(pv4, source);
00053         pv4[3]= 1.0;
00054 
00055         /* rotmat is the object matrix in this case */
00056         if(uci->do_rotmat)
00057                 mul_m4_v4(uci->rotmat, pv4);
00058 
00059         /* caminv is the inverse camera matrix */
00060         mul_m4_v4(uci->caminv, pv4);
00061 
00062         if(uci->do_pano) {
00063                 float angle= atan2f(pv4[0], -pv4[2]) / ((float)M_PI * 2.0f); /* angle around the camera */
00064                 if (uci->do_persp==0) {
00065                         target[0]= angle; /* no correct method here, just map to  0-1 */
00066                         target[1]= pv4[1] / uci->camsize;
00067                 }
00068                 else {
00069                         float vec2d[2]; /* 2D position from the camera */
00070                         vec2d[0]= pv4[0];
00071                         vec2d[1]= pv4[2];
00072                         target[0]= angle * ((float)M_PI / uci->camangle);
00073                         target[1]= pv4[1] / (len_v2(vec2d) * (uci->camsize * 2.0f));
00074                 }
00075         }
00076         else {
00077                 if (pv4[2]==0.0f) pv4[2]= 0.00001f; /* don't allow div by 0 */
00078 
00079                 if (uci->do_persp==0) {
00080                         target[0]= (pv4[0]/uci->camsize);
00081                         target[1]= (pv4[1]/uci->camsize);
00082                 }
00083                 else {
00084                         target[0]= (-pv4[0]*((1.0f/uci->camsize)/pv4[2])) / 2.0f;
00085                         target[1]= (-pv4[1]*((1.0f/uci->camsize)/pv4[2])) / 2.0f;
00086                 }
00087         }
00088 
00089         target[0] *= uci->xasp;
00090         target[1] *= uci->yasp;
00091         
00092         /* adds camera shift + 0.5 */
00093         target[0] += uci->shiftx;
00094         target[1] += uci->shifty;
00095 }
00096 
00097 /* could rv3d->persmat */
00098 void project_from_view(float target[2], float source[3], float persmat[4][4], float rotmat[4][4], float winx, float winy)
00099 {
00100         float pv[3], pv4[4], x= 0.0, y= 0.0;
00101 
00102         mul_v3_m4v3(pv, rotmat, source);
00103 
00104         copy_v3_v3(pv4, source);
00105         pv4[3]= 1.0;
00106 
00107         /* rotmat is the object matrix in this case */
00108         mul_m4_v4(rotmat, pv4); 
00109 
00110         /* almost project_short */
00111         mul_m4_v4(persmat, pv4);
00112         if(fabsf(pv4[3]) > 0.00001f) { /* avoid division by zero */
00113                 target[0] = winx/2.0f + (winx/2.0f) * pv4[0] / pv4[3];
00114                 target[1] = winy/2.0f + (winy/2.0f) * pv4[1] / pv4[3];
00115         }
00116         else {
00117                 /* scaling is lost but give a valid result */
00118                 target[0] = winx/2.0f + (winx/2.0f) * pv4[0];
00119                 target[1] = winy/2.0f + (winy/2.0f) * pv4[1];
00120         }
00121 
00122         /* v3d->persmat seems to do this funky scaling */ 
00123         if(winx > winy) {
00124                 y= (winx - winy)/2.0f;
00125                 winy = winx;
00126         }
00127         else {
00128                 x= (winy - winx)/2.0f;
00129                 winx = winy;
00130         }
00131 
00132         target[0]= (x + target[0]) / winx;
00133         target[1]= (y + target[1]) / winy;
00134 }
00135 
00136 /* 'rotmat' can be obedit->obmat when uv project is used.
00137  * 'winx' and 'winy' can be from scene->r.xsch/ysch */ 
00138 UvCameraInfo *project_camera_info(Object *ob, float (*rotmat)[4], float winx, float winy)
00139 {
00140         UvCameraInfo uci;
00141         Camera *camera= ob->data;
00142 
00143         uci.do_pano = (camera->flag & CAM_PANORAMA);
00144         uci.do_persp = (camera->type==CAM_PERSP);
00145 
00146         uci.camangle= lens_to_angle(camera->lens) / 2.0f;
00147         uci.camsize= uci.do_persp ? tanf(uci.camangle) : camera->ortho_scale;
00148 
00149         /* account for scaled cameras */
00150         copy_m4_m4(uci.caminv, ob->obmat);
00151         normalize_m4(uci.caminv);
00152 
00153         if (invert_m4(uci.caminv)) {
00154                 UvCameraInfo *uci_pt;
00155 
00156                 /* normal projection */
00157                 if(rotmat) {
00158                         copy_m4_m4(uci.rotmat, rotmat);
00159                         uci.do_rotmat= 1;
00160                 }
00161                 else {
00162                         uci.do_rotmat= 0;
00163                 }
00164 
00165                 /* also make aspect ratio adjustment factors */
00166                 if (winx > winy) {
00167                         uci.xasp= 1.0f;
00168                         uci.yasp= winx / winy;
00169                 }
00170                 else {
00171                         uci.xasp= winy / winx;
00172                         uci.yasp= 1.0f;
00173                 }
00174                 
00175                 /* include 0.5f here to move the UVs into the center */
00176                 uci.shiftx = 0.5f - (camera->shiftx * uci.xasp);
00177                 uci.shifty = 0.5f - (camera->shifty * uci.yasp);
00178                 
00179                 uci_pt= MEM_mallocN(sizeof(UvCameraInfo), "UvCameraInfo");
00180                 *uci_pt= uci;
00181                 return uci_pt;
00182         }
00183 
00184         return NULL;
00185 }
00186 
00187 void project_from_view_ortho(float target[2], float source[3], float rotmat[4][4])
00188 {
00189         float pv[3];
00190 
00191         mul_v3_m4v3(pv, rotmat, source);
00192 
00193         /* ortho projection */
00194         target[0] = -pv[0];
00195         target[1] = pv[2];
00196 }
00197 
00198 
00199 void project_camera_info_scale(UvCameraInfo *uci, float scale_x, float scale_y)
00200 {
00201         uci->xasp *= scale_x;
00202         uci->yasp *= scale_y;
00203 }