Logo Search packages:      
Sourcecode: blender version File versions

previewrender.c

/* previewrender.c            GRAPHICS
 * 
 * maart 95
 * 
 * $Id: previewrender.c,v 1.44 2004/12/06 18:05:42 ton Exp $
 *
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

/* global includes */

#include <stdlib.h>
#include <math.h>
#include <string.h>

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#endif   
#include "MEM_guardedalloc.h"
#include "BLI_arithb.h"
#include "BKE_utildefines.h"

#include "MTC_matrixops.h"

#include "render.h"
#include "mydevice.h"

#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "DNA_camera_types.h"
#include "DNA_image_types.h"
#include "DNA_object_types.h"
#include "DNA_lamp_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"

#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_texture.h"
#include "BKE_material.h"
#include "BKE_world.h"
#include "BKE_texture.h"

#include "BSE_headerbuttons.h"

#include "BIF_gl.h"
#include "BIF_screen.h"
#include "BIF_space.h"        /* allqueue */
#include "BIF_butspace.h"     
#include "BIF_drawimage.h"    /* rectwrite_part */
#include "BIF_mywindow.h"
#include "BIF_interface.h"
#include "BIF_glutil.h"

#include "PIL_time.h"

#include "RE_renderconverter.h"

#include "blendef.h"    /* CLAMP */

#define PR_RECTX  141
#define PR_RECTY  141
#define PR_XMIN         10
#define PR_YMIN         5
#define PR_XMAX         200
#define PR_YMAX         195

#define PR_FACY         (PR_YMAX-PR_YMIN-4)/(PR_RECTY)

static rcti prerect;
static int pr_sizex, pr_sizey;
static float pr_facx, pr_facy;


/* implementation */

static short snijpunt(float *v1,   float *v2,  float *v3,  float *rtlabda, float *ray1, float *ray2)
{
      float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22;
      float m0,m1,m2,deeldet,det1,det2,det3;
      float rtu, rtv;
      
      t00= v3[0]-v1[0];
      t01= v3[1]-v1[1];
      t02= v3[2]-v1[2];
      t10= v3[0]-v2[0];
      t11= v3[1]-v2[1];
      t12= v3[2]-v2[2];
      t20= ray1[0]-ray2[0];
      t21= ray1[1]-ray2[1];
      t22= ray1[2]-ray2[2];
      
      x0= t11*t22-t12*t21;
      x1= t12*t20-t10*t22;
      x2= t10*t21-t11*t20;

      deeldet= t00*x0+t01*x1+t02*x2;
      if(deeldet!=0.0) {
            m0= ray1[0]-v3[0];
            m1= ray1[1]-v3[1];
            m2= ray1[2]-v3[2];
            det1= m0*x0+m1*x1+m2*x2;
            rtu= det1/deeldet;
            if(rtu<=0.0) {
                  det2= t00*(m1*t22-m2*t21);
                  det2+= t01*(m2*t20-m0*t22);
                  det2+= t02*(m0*t21-m1*t20);
                  rtv= det2/deeldet;
                  if(rtv<=0.0) {
                        if(rtu+rtv>= -1.0) {
                              
                              det3=  m0*(t12*t01-t11*t02);
                              det3+= m1*(t10*t02-t12*t00);
                              det3+= m2*(t11*t00-t10*t01);
                              *rtlabda= det3/deeldet;
                              
                              if(*rtlabda>=0.0 && *rtlabda<=1.0) {
                                    return 1;
                              }
                        }
                  }
            }
      }
      return 0;
}

static float rcubev[7][3]= {
      {-0.002055,  6.627364, -3.369742}, 
      {-6.031684, -3.750204, -1.992980}, 
      {-6.049086,  3.817431,  1.969788}, 
      { 6.031685,  3.833064,  1.992979}, 
      { 6.049086, -3.734571, -1.969787}, 
      { 0.002054, -6.544502,  3.369744}, 
      {-0.015348,  1.023131,  7.332510} };

static int rcubi[3][4]= {
      {3,  6,  5,  4},
      {1,  5,  6,  2},  
      {3,  0,  2,  6} };


static int ray_previewrender(int x,  int y,  float *vec, float *vn)
{
      float scalef= 10.0/100.0;
      float ray1[3], ray2[3];
      float minlabda, labda;
      int totface= 3, hitface= -1;
      int a;

      ray1[0]= ray2[0]= x*scalef;
      ray1[1]= ray2[1]= y*scalef;
      ray1[2]= -10.0;
      ray2[2]= 10.0;
      
      minlabda= 1.0;
      for(a=0; a<totface; a++) {
            if(snijpunt( rcubev[rcubi[a][0]], rcubev[rcubi[a][1]], rcubev[rcubi[a][2]], &labda, ray1, ray2)) {
                  if( labda < minlabda) {
                        minlabda= labda;
                        hitface= a;
                  }
            }
            if(snijpunt( rcubev[rcubi[a][0]], rcubev[rcubi[a][2]], rcubev[rcubi[a][3]], &labda, ray1, ray2)) {
                  if( labda < minlabda) {
                        minlabda= labda;
                        hitface= a;
                  }
            }
      }
      
      if(hitface > -1) {
            
            CalcNormFloat(rcubev[rcubi[hitface][0]], rcubev[rcubi[hitface][1]], rcubev[rcubi[hitface][2]], vn);
            
            vec[0]= (minlabda*(ray1[0]-ray2[0])+ray2[0])/3.7;
            vec[1]= (minlabda*(ray1[1]-ray2[1])+ray2[1])/3.7;
            vec[2]= (minlabda*(ray1[2]-ray2[2])+ray2[2])/3.7;
            
            return 1;
      }
      return 0;
}


static unsigned int previewback(int type, int x, int y)
{
      
      /* checkerboard, for later
      x+= PR_RECTX/2;
      y+= PR_RECTX/2;
      if( ((x/24) + (y/24)) & 1) return 0x40404040;
      else return 0xa0a0a0a0;
      */
      
      if(type & MA_DARK) {
            if(abs(x)>abs(y)) return 0;
            else return 0x40404040;
      }
      else {
            if(abs(x)>abs(y)) return 0x40404040;
            else return 0xa0a0a0a0;
      }
}

static void view2d_to_window(int win, int *x_r, int *y_r)
{
      int x= *x_r, y= *y_r;
      int size[2], origin[2];
      float winmat[4][4];

      bwin_getsinglematrix(win, winmat);
      bwin_getsize(win, &size[0], &size[1]);
      bwin_getsuborigin(win, &origin[0], &origin[1]);
      
      *x_r= origin[0] + (size[0]*(0.5 + 0.5*(x*winmat[0][0] + y*winmat[1][0] + winmat[3][0])));
      *y_r= origin[1] + (size[1]*(0.5 + 0.5*(x*winmat[0][1] + y*winmat[1][1] + winmat[3][1])));
}

static void set_previewrect(int win, int xmin, int ymin, int xmax, int ymax)
{
      prerect.xmin= xmin;
      prerect.ymin= ymin;
      prerect.xmax= xmax;
      prerect.ymax= ymax;

      view2d_to_window(win, &prerect.xmin, &prerect.ymin);
      view2d_to_window(win, &prerect.xmax, &prerect.ymax);
      
      pr_sizex= (prerect.xmax-prerect.xmin);
      pr_sizey= (prerect.ymax-prerect.ymin);

      pr_facx= ( (float)pr_sizex-1)/PR_RECTX;
      pr_facy= ( (float)pr_sizey-1)/PR_RECTY;
}

static void display_pr_scanline(unsigned int *rect, int recty)
{
      static double lasttime= 0;
      /* we display 3 new scanlines, one old, the overlap is for wacky 3d cards that cant handle zoom proper */

      if(recty % 2) return;
      if(recty<2) return;
      
      rect+= (recty-2)*PR_RECTX;

      /* enlarge a bit in the y direction, to avoid GL/mesa bug */
      glPixelZoom(pr_facx, pr_facy);

      glRasterPos2f( (float)PR_XMIN+0.5, 1.0+(float)PR_YMIN + (recty*PR_FACY) );
      glDrawPixels(PR_RECTX, 3, GL_RGBA, GL_UNSIGNED_BYTE,  rect);

      //glaDrawPixelsTex((float)PR_XMIN, (float)PR_YMIN + (recty*PR_FACY), PR_RECTX, 3, rect);

      glPixelZoom(1.0, 1.0);
      
      /* flush opengl for cards with frontbuffer slowness */
      if(recty==PR_RECTY-1 || (PIL_check_seconds_timer() - lasttime > 0.05)) {
            lasttime= PIL_check_seconds_timer();
            glFlush();
      }
}

static void draw_tex_crop(Tex *tex)
{
      rcti rct;
      int ret= 0;
      
      if(tex==0) return;
      
      if(tex->type==TEX_IMAGE) {
            if(tex->cropxmin==0.0) ret++;
            if(tex->cropymin==0.0) ret++;
            if(tex->cropxmax==1.0) ret++;
            if(tex->cropymax==1.0) ret++;
            if(ret==4) return;
            
            rct.xmin= PR_XMIN+2+tex->cropxmin*(PR_XMAX-PR_XMIN-4);
            rct.xmax= PR_XMIN+2+tex->cropxmax*(PR_XMAX-PR_XMIN-4);
            rct.ymin= PR_YMIN+2+tex->cropymin*(PR_YMAX-PR_YMIN-4);
            rct.ymax= PR_YMIN+2+tex->cropymax*(PR_YMAX-PR_YMIN-4);

            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 

            glColor3ub(0, 0, 0);
            glRecti(rct.xmin+1,  rct.ymin-1,  rct.xmax+1,  rct.ymax-1); 

            glColor3ub(255, 255, 255);
            glRecti(rct.xmin,  rct.ymin,  rct.xmax,  rct.ymax);

            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);                  
      }
      
}

void BIF_all_preview_changed(void)
{
      ScrArea *sa;
      SpaceButs *sbuts;
      
      sa= G.curscreen->areabase.first;
      while(sa) {
            if(sa->spacetype==SPACE_BUTS) {
                  sbuts= sa->spacedata.first;
                  sbuts->cury= 0;
                  addafterqueue(sa->win, RENDERPREVIEW, 1);
            }
            sa= sa->next;
      }
}

/* signal all previews in current screen of current type */
void BIF_preview_changed(SpaceButs *sbuts)
{

      /* can be called when no buttonswindow visible */
      if(sbuts) {
            ScrArea *sa;
            short mainb= sbuts->mainb;
            short tab= sbuts->tab[mainb];
            
            sa= G.curscreen->areabase.first;
            while(sa) {
                  if(sa->spacetype==SPACE_BUTS) {
                        sbuts= sa->spacedata.first;
                        if(sbuts->mainb==mainb && sbuts->tab[mainb]==tab) {
                              sbuts->cury= 0;
                              addafterqueue(sbuts->area->win, RENDERPREVIEW, 1);
                        }
                  }
                  sa= sa->next;
            }
      }
}

/* is panel callback, supposed to be called with correct panel offset matrix */
void BIF_previewdraw(void)
{
      SpaceButs *sbuts= curarea->spacedata.first;
      
      set_previewrect(sbuts->area->win, PR_XMIN, PR_YMIN, PR_XMAX, PR_YMAX);

      if (sbuts->rect==0) BIF_preview_changed(sbuts);
      else {
            int y;

            for (y=0; y<PR_RECTY; y++) {
                  display_pr_scanline(sbuts->rect, y);
            }

            if (sbuts->mainb==CONTEXT_SHADING && sbuts->tab[CONTEXT_SHADING]==TAB_SHADING_TEX) {
                  draw_tex_crop(sbuts->lockpoin);
            }
      }
      if(sbuts->cury==0) BIF_preview_changed(sbuts);
}

static void sky_preview_pixel(float lens, int x, int y, char *rect)
{
      float view[3];
      
      if(R.wrld.skytype & WO_SKYPAPER) {
            view[0]= (2*x)/(float)PR_RECTX;
            view[1]= (2*y)/(float)PR_RECTY;
            view[2]= 0.0;
      }
      else {
            view[0]= x;
            view[1]= y;
            view[2]= -lens*PR_RECTX/32.0;
            Normalise(view);
      }
      RE_sky_char(view, rect);
}

static void lamp_preview_pixel(ShadeInput *shi, LampRen *la, int x, int y, char *rect)
{
      float inpr, i, t, dist, distkw, vec[3];
      int col;
      
      shi->co[0]= (float)x/(PR_RECTX/4);
      shi->co[1]= (float)y/(PR_RECTX/4);
      shi->co[2]= 0;
      
      vec[0]= 0.02*x;
      vec[1]= 0.02*y;
      vec[2]= 0.005*PR_RECTX;
      VECCOPY(shi->view, vec);
      dist= Normalise(shi->view);

      if(la->mode & LA_TEXTURE) do_lamp_tex(la, vec, shi);

      if(la->type==LA_SUN || la->type==LA_HEMI) {
            dist= 1.0;
      }
      else {
            
            if(la->mode & LA_QUAD) {
                  
                  t= 1.0;
                  if(la->ld1>0.0)
                        t= la->dist/(la->dist+la->ld1*dist);
                  if(la->ld2>0.0) {
                        distkw= la->dist*la->dist;
                        t= t*distkw/(t*distkw+la->ld2*dist*dist);
                  }
                  dist= t;
            }
            else {
                  dist= (la->dist/(la->dist+dist));
            }
      }

      /* yafray: preview shade as spot, sufficient */
      if ((la->type==LA_SPOT) || (la->type==LA_YF_PHOTON)) {

            
            if(la->mode & LA_SQUARE) {
                  /* slightly smaller... */
                  inpr= 1.7*cos(MAX2(fabs(shi->view[0]/shi->view[2]) , fabs(shi->view[1]/shi->view[2]) ));
            }
            else {
                  inpr= shi->view[2];
            }
            
            t= la->spotsi;
            if(inpr<t) dist= 0.0;
            else {
                  t= inpr-t;
                  if(t<la->spotbl && la->spotbl!=0.0) {
                        /* soft area */
                        i= t/la->spotbl;
                        t= i*i;
                        i= t*i;
                        inpr*=(3.0*t-2.0*i);
                  }
            }
            dist*=inpr;
      }
      else if ELEM(la->type, LA_LOCAL, LA_AREA) dist*= shi->view[2];
      
      col= 255.0*dist*la->r;
      if(col<=0) rect[0]= 0; else if(col>=255) rect[0]= 255; else rect[0]= col;

      col= 255.0*dist*la->g;
      if(col<=0) rect[1]= 0; else if(col>=255) rect[1]= 255; else rect[1]= col;

      col= 255.0*dist*la->b;
      if(col<=0) rect[2]= 0; else if(col>=255) rect[2]= 255; else rect[2]= col;
}

static void init_previewhalo(HaloRen *har, Material *mat)
{
      
      har->type= 0;
      if(mat->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
      har->mat= mat;
      har->hard= mat->har;
      har->rad= PR_RECTX/2.0;
      har->radsq= PR_RECTX*PR_RECTX/4.0;
      har->alfa= mat->alpha;
      har->add= 255.0*mat->add;
      har->r= 255.0*mat->r;
      har->g= 255.0*mat->g; 
      har->b= 255.0*mat->b;
      har->xs= PR_RECTX/2.0;
      har->ys= PR_RECTX/2.0;
      har->zs= har->zd= 0;
      har->seed= (mat->seed1 % 256);
      
      if( (mat->mode & MA_HALOTEX) && mat->mtex[0] ) har->tex= 1; else har->tex=0;

      if(mat->mode & MA_STAR) har->starpoints= mat->starc; else har->starpoints= 0;
      if(mat->mode & MA_HALO_LINES) har->linec= mat->linec; else har->linec= 0;
      if(mat->mode & MA_HALO_RINGS) har->ringc= mat->ringc; else har->ringc= 0;
      if(mat->mode & MA_HALO_FLARE) har->flarec= mat->flarec; else har->flarec= 0;
      
      if(har->flarec) {
            har->xs-= PR_RECTX/3;
            har->ys+= PR_RECTX/3;
            
            har->rad*= 0.3;
            har->radsq= har->rad*har->rad;
            
            har->pixels= har->rad*har->rad*har->rad;
      }
}     

static void halo_preview_pixel(HaloRen *har, int startx, int endx, int y, char *rect)
{
      float dist, xn, yn, xsq, ysq;
      int x;
      char front[4];
      
      if(har->flarec) yn= y-PR_RECTX/3;
      else yn= y;
      ysq= yn*yn;
      
      for(x=startx; x<endx; x++) {
            
            if(har->flarec) xn= x+PR_RECTX/3;
            else xn= x;
            
            xsq= xn*xn;
            dist= xsq+ysq;

            
            
            if(dist<har->radsq) {
                  RE_shadehalo(har, front, 0, dist, xn, yn, har->flarec);
                  RE_addalphaAddfac(rect, front, har->add);
            }
            rect+= 4;
      }
}

static void previewflare(SpaceButs *sbuts, HaloRen *har, unsigned int *rect)
{
      uiBlock *block;
      float ycor;
      unsigned int *rectot;
      int afmx, afmy, rectx, recty;
      
      block= uiFindOpenPanelBlockName(&curarea->uiblocks, "Preview");
      if(block==NULL) return;

      /* temps */
      ycor= R.ycor;
      rectx= R.rectx;
      recty= R.recty;
      afmx= R.afmx;
      afmy= R.afmy;
      rectot= R.rectot;

      R.ycor= 1.0;
      R.rectx= PR_RECTX;      
      R.recty= PR_RECTY;
      R.afmx= PR_RECTX/2;
      R.afmy= PR_RECTY/2;
      R.rectot= rect;

      waitcursor(1);
      RE_renderflare(har);
      waitcursor(0);
      // not sure why, either waitcursor or renderflare screws up
      areawinset(curarea->win);
      
      uiPanelPush(block);
      BIF_previewdraw();
      uiPanelPop(block);
      
      
      /* temps */
      R.ycor= ycor;
      R.rectx= rectx;
      R.recty= recty;
      R.afmx= afmx;
      R.afmy= afmy;
      R.rectot= rectot;
}

extern float Tin, Tr, Tg, Tb, Ta; /* texture.c */
static void texture_preview_pixel(Tex *tex, int x, int y, char *rect)
{
      float i, v1, xsq, ysq, texvec[3], dummy[3];
      int rgbnor, tracol, skip=0;
            
      if(tex->type==TEX_IMAGE) {
            v1= 1.0/PR_RECTX;
            
            texvec[0]= 0.5+v1*x;
            texvec[1]= 0.5+v1*y;
            
            /* no coordinate mapping, exception: repeat */
            if(tex->extend==TEX_REPEAT) {
                  if(tex->xrepeat>1) {
                        texvec[0] *= tex->xrepeat;
                        if(texvec[0]>1.0) texvec[0] -= (int)(texvec[0]);
                  }
                  if(tex->yrepeat>1) {
                        texvec[1] *= tex->yrepeat;
                        if(texvec[1]>1.0) texvec[1] -= (int)(texvec[1]);
                  }
            }
            else if(tex->extend==TEX_CHECKER) {
                  texvec[0]= 0.5+1.6*v1*x;
                  texvec[1]= 0.5+1.6*v1*y;
            }
      }
      else if(tex->type==TEX_ENVMAP) {
            if(tex->env) {
                  ysq= y*y;
                  xsq= x*x;
                  if(xsq+ysq < (PR_RECTX/2)*(PR_RECTY/2)) {
                        texvec[2]= sqrt( (float)((PR_RECTX/2)*(PR_RECTY/2)-xsq-ysq) );
                        texvec[0]= -x;
                        texvec[1]= -y;
                        Normalise(texvec);

                        i= 2.0*(texvec[2]);
                        texvec[0]= (i*texvec[0]);
                        texvec[1]= (i*texvec[1]);
                        texvec[2]= (-1.0+i*texvec[2]);

                  }
                  else {
                        skip= 1;
                        Ta= 0.0;
                  }
            }
            else {
                  skip= 1;
                  Ta= 0.0;
            }
      }
      else {
            v1= 2.0/PR_RECTX;
      
            texvec[0]= v1*x;
            texvec[1]= v1*y;
            texvec[2]= 0.0;
      }
      
      /* does not return Tin */
      if(tex->type==TEX_STUCCI) {
            tex->nor= dummy;
            dummy[0]= 1.0;
            dummy[1]= dummy[2]= 0.0;
      }
      
      if(skip==0) rgbnor= multitex(tex, texvec, NULL, NULL, 0);
      else rgbnor= 1;
      
      if(rgbnor & 1) {
            
            v1= 255.0*Tr;
            rect[0]= CLAMPIS(v1, 0, 255);
            v1= 255.0*Tg;
            rect[1]= CLAMPIS(v1, 0, 255);
            v1= 255.0*Tb;
            rect[2]= CLAMPIS(v1, 0, 255);
            
            if(Ta!=1.0) {
                  tracol=  64+100*(abs(x)>abs(y));
                  tracol= (1.0-Ta)*tracol;
                  
                  rect[0]= tracol+ (rect[0]*Ta) ;
                  rect[1]= tracol+ (rect[1]*Ta) ;
                  rect[2]= tracol+ (rect[2]*Ta) ;
                              
            }
      }
      else {
      
            if(tex->type==TEX_STUCCI) {
                  Tin= 0.5 + 0.7*tex->nor[0];
                  CLAMP(Tin, 0.0, 1.0);
            }
            rect[0]= 255.0*Tin;
            rect[1]= 255.0*Tin;
            rect[2]= 255.0*Tin;
      }
}

static float pr1_lamp[3]= {2.3, -2.4, -4.6};
static float pr2_lamp[3]= {-8.8, -5.6, -1.5};
static float pr1_col[3]= {0.8, 0.8, 0.8};
static float pr2_col[3]= {0.5, 0.6, 0.7};

static void refraction_prv(int *x, int *y, float *n, float index)
{
      float dot, fac, view[3], len;

      index= 1.0/index;
      
      view[0]= index*(float)*x;
      view[1]= ((float)*y)/index;
      view[2]= 20.0;
      len= Normalise(view);
      
      dot= view[0]*n[0] + view[1]*n[1] + view[2]*n[2];

      if(dot>0.0) {
            fac= 1.0 - (1.0 - dot*dot)*index*index;
            if(fac<= 0.0) return;
            fac= -dot*index + sqrt(fac);
      }
      else {
            index = 1.0/index;
            fac= 1.0 - (1.0 - dot*dot)*index*index;
            if(fac<= 0.0) return;
            fac= -dot*index - sqrt(fac);
      }

      *x= (int)(len*(index*view[0] + fac*n[0]));
      *y= (int)(len*(index*view[1] + fac*n[1]));
}


static void shade_preview_pixel(ShadeInput *shi, float *vec, int x, int y,char *rect, int smooth)
{
      extern float fresnel_fac(float *view, float *vn, float ior, float fac);
      Material *mat;
      float v1,inp, is, inprspec=0, isr=0.0, isb=0.0, isg=0.0;
      float diff[3]={0.0, 0.0, 0.0};
      float lv[3], *la, alpha;
      float eul[3], tmat[3][3], imat[3][3];
      int temp, a;
      char tracol;
            
      mat= shi->matren;

      v1= 1.0/PR_RECTX;
      shi->view[0]= v1*x;
      shi->view[1]= v1*y;
      shi->view[2]= 1.0;
      Normalise(shi->view);
      
      shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0;

      /* texture handling */
      if(mat->texco) {
            
            VECCOPY(shi->lo, vec);
            
            if(mat->pr_type==MA_CUBE) {
                  
                  eul[0]= (297)*M_PI/180.0;
                  eul[1]= 0.0;
                  eul[2]= (45)*M_PI/180.0;
                  EulToMat3(eul, tmat);

                  MTC_Mat3MulVecfl(tmat, shi->lo);
                  MTC_Mat3MulVecfl(tmat, shi->vn);
                  /* hack for cubemap, why!!! */
                  SWAP(float, shi->vn[0], shi->vn[1]);
            }
            /* textures otherwise upside down */
            if(mat->pr_type==MA_CUBE || mat->pr_type==MA_SPHERE) 
                  shi->lo[2]= -shi->lo[2];

            if(mat->texco & TEXCO_GLOB) {
                  VECCOPY(shi->gl, shi->lo);
            }
            if(mat->texco & TEXCO_WINDOW) {
                  VECCOPY(shi->winco, shi->lo);
            }
            if(mat->texco & TEXCO_STICKY) {
                  VECCOPY(shi->sticky, shi->lo);
            }
            if(mat->texco & TEXCO_UV) {
                  VECCOPY(shi->uv, shi->lo);
            }
            if(mat->texco & TEXCO_OBJECT) {
                  VECCOPY(shi->co, shi->lo);
            }
            if(mat->texco & (TEXCO_NORM)) {
                  shi->orn[0]= shi->vn[0];
                  shi->orn[1]= shi->vn[1];
                  shi->orn[2]= shi->vn[2];
            }
            if(mat->texco & TEXCO_REFL) {
                  
                  inp= -2.0*(shi->vn[0]*shi->view[0]+shi->vn[1]*shi->view[1]+shi->vn[2]*shi->view[2]);
                  shi->ref[0]= (shi->view[0]+inp*shi->vn[0]);
                  shi->ref[1]= (shi->view[1]+inp*shi->vn[1]);
                  shi->ref[2]= (shi->view[2]+inp*shi->vn[2]);
            }

            /* Clear displase vec for preview */
            shi->displace[0]= shi->displace[1]= shi->displace[2]= 0.0;
            
            /* normals flipped in render for smooth... */
            if( (mat->mapto & MAP_NORM)) VecMulf(shi->vn, -1.0);
            
            do_material_tex(shi);

            /* normals flipped in render... */
            if( (mat->mapto & MAP_NORM)) VecMulf(shi->vn, -1.0);
      
            if(mat->texco & TEXCO_REFL) {
                  /* normals in render are pointing different... rhm */
                  if(smooth) shi->ref[1]= -shi->ref[1];
            }

            if(mat->pr_type==MA_CUBE) {
                  /* rotate normal back for normals texture */
                  SWAP(float, shi->vn[0], shi->vn[1]);
                  MTC_Mat3Inv(imat, tmat);
                  MTC_Mat3MulVecfl(imat, shi->vn);
            }
            
      }
      /* set it here, because ray_mirror will affect it */
      alpha= mat->alpha;

      if(mat->mapto & MAP_DISPLACE) { /* Quick hack of fake displacement preview */
            shi->vn[0]-=2.0*shi->displace[2];
            shi->vn[1]-=2.0*shi->displace[0];
            shi->vn[2]+=2.0*shi->displace[1];
            Normalise(shi->vn);
      }
            
      if(mat->mode & (MA_ZTRA|MA_RAYTRANSP)) 
            if(mat->fresnel_tra!=0.0) 
                  alpha*= fresnel_fac(shi->view, shi->vn, mat->fresnel_tra_i, mat->fresnel_tra);

      if(mat->mode & MA_SHLESS) {
            temp= 255.0*(mat->r);
            if(temp>255) rect[0]= 255; else if(temp<0) rect[0]= 0; else rect[0]= temp;

            temp= 255.0*(mat->g);
            if(temp>255) rect[1]= 255; else if(temp<0) rect[1]= 0; else rect[1]= temp;

            temp= 255.0*(mat->b);
            if(temp>255) rect[2]= 255; else if(temp<0) rect[2]= 0; else rect[2]= temp;
      }
      else {
            
            for(a=0; a<2; a++) {
                  
                  if((mat->pr_lamp & (1<<a))==0) continue;
                  
                  if(a==0) la= pr1_lamp;
                  else la= pr2_lamp;
                  
                  lv[0]= vec[0]-la[0];
                  lv[1]= vec[1]-la[1];
                  lv[2]= vec[2]-la[2];
                  Normalise(lv);
                  
                  is= shi->vn[0]*lv[0]+shi->vn[1]*lv[1]+shi->vn[2]*lv[2];
                  if(is<0.0) is= 0.0;
                  
                  if(mat->spec)  {
                        
                        if(is>0.0) {
                              /* specular shaders */
                              float specfac;
                              
                              if(mat->spec_shader==MA_SPEC_PHONG) 
                                    specfac= Phong_Spec(shi->vn, lv, shi->view, mat->har);
                              else if(mat->spec_shader==MA_SPEC_COOKTORR) 
                                    specfac= CookTorr_Spec(shi->vn, lv, shi->view, mat->har);
                              else if(mat->spec_shader==MA_SPEC_BLINN) 
                                    specfac= Blinn_Spec(shi->vn, lv, shi->view, mat->refrac, (float)mat->har);
                              else 
                                    specfac= Toon_Spec(shi->vn, lv, shi->view, mat->param[2], mat->param[3]);
                        
                              inprspec= specfac*mat->spec;
                              
                              if(mat->mode & MA_RAMP_SPEC) {
                                    float spec[3];
                                    do_specular_ramp(shi, specfac, inprspec, spec);
                                    isr+= inprspec*spec[0];
                                    isg+= inprspec*spec[1];
                                    isb+= inprspec*spec[2];
                              }
                              else {      
                                    isr+= inprspec*mat->specr;
                                    isg+= inprspec*mat->specg;
                                    isb+= inprspec*mat->specb;
                              }
                        }
                  }
                  /* diffuse shaders */
                  if(mat->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(shi->vn, lv, shi->view, mat->roughness);
                  else if(mat->diff_shader==MA_DIFF_TOON) is= Toon_Diff(shi->vn, lv, shi->view, mat->param[0], mat->param[1]);
                  // else Lambert
                  
                  inp= (mat->ref*is + mat->emit);
                  
                  if(a==0) la= pr1_col;
                  else la= pr2_col;

                  add_to_diffuse(diff, shi, is, inp*la[0], inp*la[1], inp*la[2]);
                  //ir+= inp*la[0];
                  //ig+= inp*la[1];
                  //ib+= inp*la[2];
            }
            
            /* drawing checkerboard and sky */
            if(mat->mode & MA_RAYMIRROR) {
                  float col, div, y, z;
                  int fac;
                  
                  /* rotate a bit in x */
                  y= shi->ref[1]; z= shi->ref[2];
                  shi->ref[1]= 0.98*y - 0.17*z;
                  shi->ref[2]= 0.17*y + 0.98*z;
                  
                  /* scale */
                  div= (0.85*shi->ref[1]);
                  
                  shi->refcol[0]= mat->ray_mirror*fresnel_fac(shi->view, shi->vn, mat->fresnel_mir_i, mat->fresnel_mir);
                  /* not real 'alpha', but mirror overriding transparency */
                  if(mat->mode & MA_RAYTRANSP) {
                        float fac= sqrt(shi->refcol[0]);
                        alpha= alpha*(1.0-fac) + fac;
                  }
                  else alpha= alpha*(1.0-shi->refcol[0]) + shi->refcol[0];
                  
                  if(div<0.0) {
                        /* minus 0.5 prevents too many small tiles in distance */
                        fac= (int)(shi->ref[0]/(div-0.1) ) + (int)(shi->ref[2]/(div-0.1) );
                        if(fac & 1) col= 0.8;
                        else col= 0.3;

                        shi->refcol[1]= shi->refcol[0]*col;
                        shi->refcol[2]= shi->refcol[1];
                        shi->refcol[3]= shi->refcol[2];
                  }
                  else {
                        shi->refcol[1]= 0.0;
                        shi->refcol[2]= shi->refcol[0]*0.3*div;
                        shi->refcol[3]= shi->refcol[0]*0.8*div;
                  }
            }
            
            if(mat->mode & MA_RAMP_COL) ramp_diffuse_result(diff, shi);
            if(mat->mode & MA_RAMP_SPEC) ramp_spec_result(&isr, &isg, &isb, shi);
            
            if(shi->refcol[0]==0.0) {
                  a= 255.0*(diff[0] +mat->ambr +isr);
                  if(a>255) a=255; else if(a<0) a= 0;
                  rect[0]= a;
                  a= 255.0*(diff[1] +mat->ambg +isg);
                  if(a>255) a=255; else if(a<0) a= 0;
                  rect[1]= a;
                  a= 255*(diff[2] +mat->ambb +isb);
                  if(a>255) a=255; else if(a<0) a= 0;
                  rect[2]= a;
            }
            else {
                  a= 255.0*( mat->mirr*shi->refcol[1] + (1.0 - mat->mirr*shi->refcol[0])*(diff[0] +mat->ambr) +isr);
                  if(a>255) a=255; else if(a<0) a= 0;
                  rect[0]= a;
                  a= 255.0*( mat->mirg*shi->refcol[2] + (1.0 - mat->mirg*shi->refcol[0])*(diff[1] +mat->ambg) +isg);
                  if(a>255) a=255; else if(a<0) a= 0;
                  rect[1]= a;
                  a= 255.0*( mat->mirb*shi->refcol[3] + (1.0 - mat->mirb*shi->refcol[0])*(diff[2] +mat->ambb) +isb);
                  if(a>255) a=255; else if(a<0) a= 0;
                  rect[2]= a;
            }
      }

            /* ztra shade */
      if(mat->spectra!=0.0) {
            inp = MAX3(isr, isg, isb);
            inp *= mat->spectra;
            if(inp>1.0) inp= 1.0;
            alpha= (1.0-inp)*alpha+inp;
      }

      if(alpha!=1.0) {
            if(mat->mode & MA_RAYTRANSP) {
                  refraction_prv(&x, &y, shi->vn, mat->ang);
            }
            
            tracol=  previewback(mat->pr_back, x, y) & 255;
            
            tracol= (1.0-alpha)*tracol;
            
            rect[0]= tracol+ (rect[0]*alpha) ;
            rect[1]= tracol+ (rect[1]*alpha) ;
            rect[2]= tracol+ (rect[2]*alpha) ;
      }
}


void BIF_previewrender(SpaceButs *sbuts)
{
      ID *id, *idfrom;
      Material *mat= NULL;
      Tex *tex= NULL;
      Lamp *la= NULL;
      World *wrld= NULL;
      LampRen *lar= NULL;
      Image *ima;
      HaloRen har;
      Object *ob;
      uiBlock *block;
      ShadeInput shi;
      float lens = 0.0, vec[3];
      int x, y, starty, startx, endy, endx, radsq, xsq, ysq, last = 0;
      unsigned int *rect;

      if(sbuts->cury>=PR_RECTY) return;
      
      /* we safely assume curarea has panel "preview" */
      /* quick hack for now, later on preview should become uiBlock itself */
      
      block= uiFindOpenPanelBlockName(&curarea->uiblocks, "Preview");
      if(block==NULL) return;

      ob= ((G.scene->basact)? (G.scene->basact)->object: 0);
      
      /* we cant trust this global lockpoin.. for example with headerless window */
      buttons_active_id(&id, &idfrom);
      G.buts->lockpoin= id;

      if(sbuts->mainb==CONTEXT_SHADING) {
            int tab= sbuts->tab[CONTEXT_SHADING];
            
            if(tab==TAB_SHADING_MAT) 
                  mat= sbuts->lockpoin;
            else if(tab==TAB_SHADING_TEX) 
                  tex= sbuts->lockpoin;
            else if(tab==TAB_SHADING_LAMP) {
                  if(ob && ob->type==OB_LAMP) la= ob->data;
            }
            else if(tab==TAB_SHADING_WORLD)
                  wrld= sbuts->lockpoin;
      }
      else if(sbuts->mainb==CONTEXT_OBJECT) {
            if(ob && ob->type==OB_LAMP) la= ob->data;
      }
      
      /* return: when no active block to render. but we do draw black if possible */
      if(mat==NULL && tex==NULL && la==NULL && wrld==NULL) {
            if(sbuts->rect) {
                  memset(sbuts->rect, 0, sizeof(int)*PR_RECTX*PR_RECTY);
                  sbuts->cury= PR_RECTY;
                  addqueue(curarea->win, REDRAW, 1);
            }
            return;
      }
      
      har.flarec= 0;    /* below is a test for postrender flare */
      
      if(qtest()) {
            addafterqueue(curarea->win, RENDERPREVIEW, 1);
            return;
      }

      MTC_Mat4One(R.viewmat);
      MTC_Mat4One(R.viewinv);
      
      shi.osatex= 0;
      
      if(mat) {
            /* rendervars */
            init_render_world();
            init_render_material(mat);
            
            /* clear imats, flip normal... (hack because everything is inverted here) */
            for(x=0; x<MAX_MTEX; x++) {
                  if(mat->mtex[x]) {
                        if(mat->mtex[x]->tex) {
                              init_render_texture(mat->mtex[x]->tex);
                              
                              if(mat->mtex[x]->tex->env && mat->mtex[x]->tex->env->object) 
                                    MTC_Mat4One(mat->mtex[x]->tex->env->object->imat);
                              
                              mat->mtex[x]->maptoneg ^= MAP_NORM;
                        }
                        if(mat->mtex[x]->object) MTC_Mat4One(mat->mtex[x]->object->imat);
                        if(mat->mtex[x]->object) MTC_Mat4One(mat->mtex[x]->object->imat);
                  }
            }
            shi.vlr= 0;
            shi.mat= mat;
            shi.matren= mat->ren;
            
            if(mat->mode & MA_HALO) init_previewhalo(&har, mat);
      }
      else if(tex) {

            ima= tex->ima;
            if(ima) last= ima->lastframe;
            init_render_texture(tex);
            free_unused_animimages();
            if(tex->ima) {
                  if(tex->ima!=ima) allqueue(REDRAWBUTSSHADING, 0);
                  else if(last!=ima->lastframe) allqueue(REDRAWBUTSSHADING, 0);
            }
            if(tex->env && tex->env->object) 
                  MTC_Mat4Invert(tex->env->object->imat, tex->env->object->obmat);
      }
      else if(la) {

            init_render_world();
            init_render_textures(); /* do not do it twice!! (brightness) */
            R.totlamp= 0;
            RE_add_render_lamp(ob, 0);    /* 0=no shadbuf */
            lar= R.la[0];
            
            /* exceptions: */
            lar->spottexfac= 1.0;
            lar->spotsi= cos( M_PI/3.0 );
            lar->spotbl= (1.0-lar->spotsi)*la->spotblend;
            
            MTC_Mat3One(lar->imat);
      }
      else if(wrld) {
            
            lens= 35.0;
            if(G.scene->camera) {
                  lens= ( (Camera *)G.scene->camera->data)->lens;

                  /* needed for init_render_world */
                  MTC_Mat4CpyMat4(R.viewinv, G.scene->camera->obmat);
                  MTC_Mat4Ortho(R.viewinv);
                  MTC_Mat4Invert(R.viewmat, R.viewinv);
            }
            init_render_world();
            init_render_textures(); /* dont do it twice!! (brightness) */
      }

      set_previewrect(sbuts->area->win, PR_XMIN, PR_YMIN, PR_XMAX, PR_YMAX);

      if(sbuts->rect==NULL) {
            sbuts->rect= MEM_callocN(sizeof(int)*PR_RECTX*PR_RECTY, "butsrect");
            
            /* built in emboss */
            rect= sbuts->rect;
            for(y=0; y<PR_RECTY; y++, rect++) *rect= 0xFFFFFFFF;
            
            rect= sbuts->rect + PR_RECTX-1;
            for(y=0; y<PR_RECTY; y++, rect+=PR_RECTX) *rect= 0xFFFFFFFF;
      }
      
      starty= -PR_RECTY/2;
      endy= starty+PR_RECTY;
      starty+= sbuts->cury;
      
      /* offset +1 for emboss */
      startx= -PR_RECTX/2 +1;
      endx= startx+PR_RECTX -2;

      radsq= (PR_RECTX/2)*(PR_RECTY/2);
      
      if(mat) {
            if(mat->pr_type==MA_SPHERE) {
                  pr1_lamp[0]= 2.3; pr1_lamp[1]= -2.4; pr1_lamp[2]= -4.6;
                  pr2_lamp[0]= -8.8; pr2_lamp[1]= -5.6; pr2_lamp[2]= -1.5;
            }
            else {
                  pr1_lamp[0]= 1.9; pr1_lamp[1]= 3.1; pr1_lamp[2]= -8.5;
                  pr2_lamp[0]= 1.2; pr2_lamp[1]= -18; pr2_lamp[2]= 3.2;
            }
      }

      /* here it starts! */
      glDrawBuffer(GL_FRONT);
      uiPanelPush(block);

      for(y=starty; y<endy; y++) {
            
            rect= sbuts->rect + 1 + PR_RECTX*sbuts->cury;
            
            if(y== -PR_RECTY/2 || y==endy-1);         /* emboss */
            else if(mat) {
                  
                  if(mat->mode & MA_HALO) {
                        for(x=startx; x<endx; x++, rect++) {
                              rect[0]= previewback(mat->pr_back, x, y);
                        }

                        if(har.flarec) {
                              if(y==endy-2) previewflare(sbuts, &har, sbuts->rect);
                        }
                        else {
                              halo_preview_pixel(&har, startx, endx, y, (char *) (rect-PR_RECTX));
                        }
                  }
                  else {
                        ysq= y*y;
                        for(x=startx; x<endx; x++, rect++) {
                              xsq= x*x;
                              if(mat->pr_type==MA_SPHERE) {
                              
                                    if(xsq+ysq <= radsq) {
                                          shi.vn[0]= x;
                                          shi.vn[1]= y;
                                          shi.vn[2]= sqrt( (float)(radsq-xsq-ysq) );
                                          Normalise(shi.vn);
                                          
                                          vec[0]= shi.vn[0];
                                          vec[1]= shi.vn[2];
                                          vec[2]= -shi.vn[1];
                                          
                                          shade_preview_pixel(&shi, vec, x, y, (char *)rect, 1);
                                    }
                                    else {
                                          rect[0]= previewback(mat->pr_back, x, y);
                                    }
                              }
                              else if(mat->pr_type==MA_CUBE) {
                                    if( ray_previewrender(x, y, vec, shi.vn) ) {
                                          
                                          shade_preview_pixel(&shi, vec, x, y, (char *)rect, 0);
                                    }
                                    else {
                                          rect[0]= previewback(mat->pr_back, x, y);
                                    }
                              }
                              else {
                                    vec[0]= x*(2.0/PR_RECTX);
                                    vec[1]= y*(2.0/PR_RECTX);
                                    vec[2]= 0.0;
                                    
                                    shi.vn[0]= shi.vn[1]= 0.0;
                                    shi.vn[2]= 1.0;
                                    
                                    shade_preview_pixel(&shi, vec, x, y, (char *)rect, 0);
                              }
                        }
                  }
            }
            else if(tex) {
                  for(x=startx; x<endx; x++, rect++) {
                        texture_preview_pixel(tex, x, y, (char *)rect);
                  }
            }
            else if(la) {
                  for(x=startx; x<endx; x++, rect++) {
                        lamp_preview_pixel(&shi, lar, x, y, (char *)rect);
                  }
            }
            else  {
                  for(x=startx; x<endx; x++, rect++) {                        
                        sky_preview_pixel(lens, x, y, (char *)rect);
                  }
            }
            
            if(y<endy-2) {

                  if(qtest()) {
                        addafterqueue(curarea->win, RENDERPREVIEW, 1);
                        break;
                  }
            }

            display_pr_scanline(sbuts->rect, sbuts->cury);
            
            sbuts->cury++;
      }

      if(sbuts->cury>=PR_RECTY && tex) 
            if (sbuts->tab[CONTEXT_SHADING]==TAB_SHADING_TEX) 
                  draw_tex_crop(sbuts->lockpoin);
      
      glDrawBuffer(GL_BACK);
      /* draw again for clean swapbufers */
      BIF_previewdraw();

      uiPanelPop(block);
      
      if(mat) {
            end_render_material(mat);
            for(x=0; x<MAX_MTEX; x++) {
                  if(mat->mtex[x] && mat->mtex[x]->tex) {
                        end_render_texture(mat->mtex[x]->tex);
                        mat->mtex[x]->maptoneg ^= MAP_NORM;
                  }     
            }
      }
      else if(tex) {
            end_render_texture(tex);
      }
      else if(la) {
            if(R.totlamp) {
                  if(R.la[0]->org) MEM_freeN(R.la[0]->org);
                  MEM_freeN(R.la[0]);
            }
            R.totlamp= 0;
            end_render_textures();
      }
      else if(wrld) {
            end_render_textures();
      }
}


Generated by  Doxygen 1.6.0   Back to index