Logo Search packages:      
Sourcecode: blender version File versions

pixelshading.c

/**
 *
 * ***** 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 *****
 * Shading of pixels
 *
 * 11-09-2000 nzc
 *
 * $Id: pixelshading.c,v 1.18 2004/12/08 15:29:47 ton Exp $
 *
 */

#include <math.h>
#include "BLI_arithb.h"

/* External modules: */
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "MTC_matrixops.h"
#include "MTC_vectorops.h"

#include "DNA_camera_types.h"
#include "DNA_object_types.h"
#include "DNA_image_types.h"
#include "DNA_texture_types.h"
#include "DNA_lamp_types.h"

#include "BKE_global.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"

#include "render.h"
#include "texture.h"
#include "render_intern.h"

#include "vanillaRenderPipe_types.h"
#include "pixelblending.h"
#include "rendercore.h" /* for some shading functions... */
#include "zbufferdatastruct.h"

#include "renderHelp.h"

#include "gammaCorrectionTables.h"
#include "errorHandler.h"
#include "pixelshading.h"

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


/* The collector is the communication channel with the render pipe.          */
extern RE_COLBUFTYPE  collector[4];  /* used throughout as pixel colour accu */

/* ton: 
  - unified render now uses face render routines from rendercore.c
  - todo still: shalo render and sky routines */

/* ------------------------------------------------------------------------- */

void *renderPixel(float x, float y, int *obdata, int mask)
{
    void* data = NULL;
    
    if (obdata[3] & RE_POLY) {
        /* face pixels aren't rendered in floats yet, so we wrap it here */
            data = shadepixel(x, y, obdata[1], mask, collector);
    }
    else if (obdata[3] & RE_HALO) {
        data = renderHaloPixel(x, y, obdata[1]);
    }
      else if( obdata[1] == 0 ) {   
            /* for lamphalo, but doesn't seem to be called? Actually it is, and  */
            /* it returns NULL pointers. */
        data = shadepixel(x, y, obdata[1], mask, collector);
      }
    return data;
   
} /* end of void renderPixel(float x, float y, int *obdata) */

/* ------------------------------------------------------------------------- */

void renderSpotHaloPixel(float x, float y, float* target)
{
      shadepixel(x, y, 0, 0, target);
}


/* ------------------------------------------------------------------------- */
static unsigned int calcHaloZ(HaloRen *har, unsigned int zz)
{

      if(har->type & HA_ONLYSKY) {
            if(zz!=0x7FFFFFFF) zz= 0;
      }
      else {
            zz= (zz>>8);
            if(zz<0x800000) zz= (zz+0x7FFFFF);
            else zz= (zz-0x800000);
      }
      return zz;
}

void *renderHaloPixel(float x, float y, int haloNr) 
{
    HaloRen *har = NULL;
    float dist = 0.0;
    unsigned int zz = 0;

    /* Find har to go with haloNr */
    har = RE_findOrAddHalo(haloNr);
                    
    /* zz is a strange number... This call should effect that halo's are  */
    /* never cut? Seems a bit strange to me now...                        */
    /* This might be the zbuffer depth                                    */
    zz = calcHaloZ(har, 0x7FFFFFFF);

    /* distance of this point wrt. the halo center. Maybe xcor is also needed? */
    dist = ((x - har->xs) * (x - har->xs)) 
        +  ((y - har->ys) * (y - har->ys) * R.ycor * R.ycor) ;

    collector[0] = RE_ZERO_COLOUR_FLOAT; collector[1] = RE_ZERO_COLOUR_FLOAT; 
    collector[2] = RE_ZERO_COLOUR_FLOAT; collector[3] = RE_ZERO_COLOUR_FLOAT;

    if (dist < har->radsq) {
        shadeHaloFloat(har, collector, zz, dist, 
                                (x - har->xs), (y - har->ys) * R.ycor, har->flarec);
    }; /* else: this pixel is not rendered for this halo: no colour */

    return (void*) har;

} /* end of void* renderHaloPixel(float x, float y, int haloNr) */

/* ------------------------------------------------------------------------- */

extern float hashvectf[];
void shadeHaloFloat(HaloRen *har, 
                              float *col, unsigned int zz, 
                              float dist, float xn, 
                              float yn, short flarec)
{
      /* fill in col */
      /* migrate: fill collector */
      float t, zn, radist, ringf=0.0, linef=0.0, alpha, si, co, colf[4];
      int a;
   
      if(R.wrld.mode & WO_MIST) {
       if(har->type & HA_ONLYSKY) {
           /* stars but no mist */
           alpha= har->alfa;
       }
       else {
           /* a but patchy... */
           R.zcor= -har->co[2];
           alpha= mistfactor(har->co)*har->alfa;
       }
      }
      else alpha= har->alfa;
      
      if(alpha==0.0) {
            col[0] = 0.0;
            col[1] = 0.0;
            col[2] = 0.0;
            col[3] = 0.0;
            return;
      }

      radist= sqrt(dist);

      /* watch it: not used nicely: flarec is set at zero in pixstruct */
      if(flarec) har->pixels+= (int)(har->rad-radist);

      if(har->ringc) {
            float *rc, fac;
            int ofs;
            
            /* per ring an antialised circle */
            ofs= har->seed;
            
            for(a= har->ringc; a>0; a--, ofs+=2) {
                  
                  rc= hashvectf + (ofs % 768);
                  
                  fac= fabs( rc[1]*(har->rad*fabs(rc[0]) - radist) );
                  
                  if(fac< 1.0) {
                        ringf+= (1.0-fac);
                  }
            }
      }

      if(har->type & HA_VECT) {
            dist= fabs( har->cos*(yn) - har->sin*(xn) )/har->rad;
            if(dist>1.0) dist= 1.0;
            if(har->tex) {
                  zn= har->sin*xn - har->cos*yn;
                  yn= har->cos*xn + har->sin*yn;
                  xn= zn;
            }
      }
      else dist= dist/har->radsq;

      if(har->type & HA_FLARECIRC) {
            
            dist= 0.5+fabs(dist-0.5);
            
      }

      if(har->hard>=30) {
            dist= sqrt(dist);
            if(har->hard>=40) {
                  dist= sin(dist*M_PI_2);
                  if(har->hard>=50) {
                        dist= sqrt(dist);
                  }
            }
      }
      else if(har->hard<20) dist*=dist;

      dist=(1.0-dist);
      
      if(har->linec) {
            float *rc, fac;
            int ofs;
            
            /* per starpoint an antialiased line */
            ofs= har->seed;
            
            for(a= har->linec; a>0; a--, ofs+=3) {
                  
                  rc= hashvectf + (ofs % 768);
                  
                  fac= fabs( (xn)*rc[0]+(yn)*rc[1]);
                  
                  if(fac< 1.0 ) {
                        linef+= (1.0-fac);
                  }
            }
            
            linef*= dist;
            
      }

      if(har->starpoints) {
            float ster, hoek;
            /* rotation */
            hoek= atan2(yn, xn);
            hoek*= (1.0+0.25*har->starpoints);
            
            co= cos(hoek);
            si= sin(hoek);
            
            hoek= (co*xn+si*yn)*(co*yn-si*xn);
            
            ster= fabs(hoek);
            if(ster>1.0) {
                  ster= (har->rad)/(ster);
                  
                  if(ster<1.0) dist*= sqrt(ster);
            }
      }
      
      /* halo being intersected? */
      if(har->zs> zz-har->zd) {
            t= ((float)(zz-har->zs))/(float)har->zd;
            alpha*= sqrt(sqrt(t));
      }

      dist*= alpha;
      ringf*= dist;
      linef*= alpha;
      
      if(dist<0.003) {
            col[0] = 0.0;
            col[1] = 0.0;
            col[2] = 0.0;
            col[3] = 0.0;
            return;
      }

      /* The colour is either the rgb spec-ed by the user, or extracted from   */
      /* the texture                                                           */
      if(har->tex) {
            colf[0]= har->r; colf[1]= har->g; colf[2]= har->b;
            colf[3]= dist;
            do_halo_tex(har, xn, yn, colf);
            colf[0]*= colf[3];
            colf[1]*= colf[3];
            colf[2]*= colf[3];
            
      }
      else {
            colf[0]= dist*har->r;
            colf[1]= dist*har->g;
            colf[2]= dist*har->b;
            if(har->type & HA_XALPHA) colf[3]= dist*dist;
            else colf[3]= dist;
      }

      if(har->mat && har->mat->mode & MA_HALO_SHADE) {
            /* we test for lights because of preview... */
            if(R.totlamp) render_lighting_halo(har, colf);
      }

      /* Next, we do the line and ring factor modifications. It seems we do    */
      /* uchar calculations, but it's basically doing float arith with a 255   */
      /* scale factor.                                                         */
      if(linef!=0.0) {
            Material *ma= har->mat;
            
            colf[0]+= 255.0*linef * ma->specr;
            colf[1]+= 255.0*linef * ma->specg;
            colf[2]+= 255.0*linef * ma->specb;
            
            if(har->type & HA_XALPHA) colf[3]+= linef*linef;
            else colf[3]+= linef;
      }
      if(ringf!=0.0) {
            Material *ma= har->mat;

            colf[0]+= 255.0*ringf * ma->mirr;
            colf[1]+= 255.0*ringf * ma->mirg;
            colf[2]+= 255.0*ringf * ma->mirb;
            
            if(har->type & HA_XALPHA) colf[3]+= ringf*ringf;
            else colf[3]+= ringf;
      }

      /* convert to [0.0; 1.0] range */
      col[0] = colf[0] / 255.0;
      col[1] = colf[1] / 255.0;
      col[2] = colf[2] / 255.0;
      col[3] = colf[3];

} /* end of shadeHaloFloat() */


/* ------------------------------------------------------------------------- */
/*
  
  There are three different modes for blending sky behind a picture:       
  1. sky    = blend in sky directly                                        
  2. premul = don't do sky, but apply alpha (so pretend the picture ends   
     exactly at it's boundaries)                                  
  3. key    = don't do anything                                            
  Now the stupid thing is that premul means do nothing for us, and key     
  we have to adjust a bit...

*/

/* Sky vars. */
enum RE_SkyAlphaBlendingType keyingType = RE_ALPHA_SKY; /* The blending type    */

void setSkyBlendingMode(enum RE_SkyAlphaBlendingType mode) {
      if ((RE_ALPHA_NODEF < mode) && (mode < RE_ALPHA_MAX) ) {
            keyingType = mode;
      } else {
            /* error: false mode received */
            keyingType = RE_ALPHA_SKY;
      }
}

enum RE_SkyAlphaBlendingType getSkyBlendingMode() {
      return keyingType;
}

/* This one renders into collector, as always.                               */
void renderSkyPixelFloat(float x, float y)
{

      switch (keyingType) {
      case RE_ALPHA_PREMUL:
            /* Premul: don't fill, and don't change the values! */
            collector[0] = 0.0; 
            collector[1] = 0.0; 
            collector[2] = 0.0; 
            collector[3] = 0.0; 
            break;
      case RE_ALPHA_KEY:
            /*
              Key: Leave pixels fully coloured, but retain alpha data, so you   
              can composit the picture later on.                                
              - Should operate on the stack outcome!
            */          
/*          collector[0] = 0.0; */
/*          collector[1] = 0.0; */
/*          collector[2] = 0.0; */
/*          collector[3] = 0.0; */
            collector[3]= 0.0;
            collector[0]= R.wrld.horr;
            collector[1]= R.wrld.horg;
            collector[2]= R.wrld.horb;
            break;
      case RE_ALPHA_SKY:
            /* Fill in the sky as if it were a normal face. */
            shadeSkyPixel(x, y);
            collector[3]= 0.0;
            break;
      default:
            ; /* Error: illegal alpha blending state */
      }
}



/*
  Stuff the sky colour into the collector.
 */
void shadeSkyPixel(float fx, float fy) 
{
      float view[3];
      
      /*
        The rules for sky:
        1. Draw an image, if a background image was provided. Stop
        2. get texture and colour blend, and combine these.
      */

      float fac;

      /* 1. Do a backbuffer image: */ 
      if(R.r.bufflag & 1) {
            if(R.backbuf) fillBackgroundImage(fx, fy);
            return;
      } else if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
            /*
              2. Test for these types of sky. The old renderer always had to check for
              coverage, but we don't need that anymore                                 
              - SKYBLEND or SKYTEX disabled: fill in a flat colour                     
              - otherwise, do the appropriate mapping (tex or colour blend)            
              There used to be cached chars here, but they are not useful anymore
            */
            collector[0] = R.wrld.horr;
            collector[1] = R.wrld.horg;
            collector[2] = R.wrld.horb;
            collector[3] = RE_UNITY_COLOUR_FLOAT;
      } else {
            /*
              3. Which type(s) is(are) this (these)? This has to be done when no simple
              way of determining the colour exists.
            */

            /* This one true because of the context of this routine  */
/*          if(rect[3] < 254) {  */
            if(R.wrld.skytype & WO_SKYPAPER) {
                  view[0]= (fx+(R.xstart))/(float)R.afmx;
                  view[1]= (fy+(R.ystart))/(float)R.afmy;
                  view[2]= 0.0;
            }
            else {
                  /* Wasn't this some pano stuff? */
                  view[0]= (fx+(R.xstart)+1.0);
                  
                  if(R.flag & R_SEC_FIELD) {
                        if(R.r.mode & R_ODDFIELD) view[1]= (fy+R.ystart+0.5)*R.ycor;
                        else view[1]= (fy+R.ystart+1.5)*R.ycor;
                  }
                  else view[1]= (fy+R.ystart+1.0)*R.ycor;
                  
                  view[2]= -R.viewfac;
                  
                  fac= Normalise(view);
                  if(R.wrld.skytype & WO_SKYTEX) {
                        O.dxview= 1.0/fac;
                        O.dyview= R.ycor/fac;
                  }
            }
            
            if(R.r.mode & R_PANORAMA) {
                  float panoco, panosi;
                  float u, v;
                  
                  panoco = getPanovCo();
                  panosi = getPanovSi();
                  u= view[0]; v= view[2];
                  
                  view[0]= panoco*u + panosi*v;
                  view[2]= -panosi*u + panoco*v;
            }
      
            /* get sky colour in the collector */
            shadeSkyPixelFloat(fy, view);
      }

      
}

/* Only line number is important here. Result goes to collector[4] */
void shadeSkyPixelFloat(float y, float *view)
{
      float lo[3];
      
      /* Why is this setting forced? Seems silly to me. It is tested in the texture unit. */
      R.wrld.skytype |= WO_ZENUP;
      
      /* Some view vector stuff. */
      if(R.wrld.skytype & WO_SKYREAL) {
      
            R.inprz= view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2];

            if(R.inprz<0.0) R.wrld.skytype-= WO_ZENUP;
            R.inprz= fabs(R.inprz);
      }
      else if(R.wrld.skytype & WO_SKYPAPER) {
            R.inprz= 0.5+ 0.5*view[1];
      }
      else {
            /* the fraction of how far we are above the bottom of the screen */
            R.inprz= fabs(0.5+ view[1]);
      }

      /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If           */
      /* SKYBLEND is active, the texture and colour blend are added.           */
      if(R.wrld.skytype & WO_SKYTEX) {
            VECCOPY(lo, view);
            if(R.wrld.skytype & WO_SKYREAL) {
                  
                  MTC_Mat3MulVecfl(R.imat, lo);

                  SWAP(float, lo[1],  lo[2]);
                  
            }

            /* sky texture? I wonder how this manages to work... */
            /* Does this communicate with R.wrld.hor{rgb}? Yes.  */
            do_sky_tex(lo);
            /* internally, T{rgb} are used for communicating colours in the      */
            /* texture pipe, externally, this particular routine uses the        */
            /* R.wrld.hor{rgb} thingies.                                         */
            
      }

      /* Why are this R. members? because textures need it (ton) */
      if(R.inprz>1.0) R.inprz= 1.0;
      R.inprh= 1.0-R.inprz;

      /* No clipping, no conversion! */
      if(R.wrld.skytype & WO_SKYBLEND) {
            collector[0] = (R.inprh*R.wrld.horr + R.inprz*R.wrld.zenr);
            collector[1] = (R.inprh*R.wrld.horg + R.inprz*R.wrld.zeng);
            collector[2] = (R.inprh*R.wrld.horb + R.inprz*R.wrld.zenb);
      } else {
            /* Done when a texture was grabbed. */
            collector[0]= R.wrld.horr;
            collector[1]= R.wrld.horg;
            collector[2]= R.wrld.horb;
      }

      collector[3]= RE_UNITY_COLOUR_FLOAT;
}


/*
  Render pixel (x,y) from the backbuffer into the collector
        
  backbuf is type Image, backbuf->ibuf is an ImBuf.  ibuf->rect is the
  rgba data (32 bit total), in ibuf->x by ibuf->y pixels. Copying
  should be really easy. I hope I understand the way ImBuf works
  correctly. (nzc)
*/
void fillBackgroundImage(float x, float y)
{

      int iy, ix;
      unsigned int* imBufPtr;
      char *colSource;
      
      /* This double check is bad... */
      if (!(R.backbuf->ok)) {
            /* Something went sour here... bail... */
            collector[0] = 0.0;
            collector[1] = 0.0;
            collector[2] = 0.0;
            collector[3] = 1.0;
            return;
      }
      /* load image if not already done?*/
      if(R.backbuf->ibuf==0) {
            R.backbuf->ibuf= IMB_loadiffname(R.backbuf->name, IB_rect);
            if(R.backbuf->ibuf==0) {
                  /* load failed .... keep skipping */
                  R.backbuf->ok= 0;
                  return;
            }
      }

      /* Now for the real extraction: */
      /* Get the y-coordinate of the scanline? */
      iy= (int) ((y+R.afmy+R.ystart)*R.backbuf->ibuf->y)/(2*R.afmy);
      ix= (int) ((x+R.afmx+R.xstart)*R.backbuf->ibuf->x)/(2*R.afmx);
      
      /* correct in case of fields rendering: */
      if(R.flag & R_SEC_FIELD) {
            if((R.r.mode & R_ODDFIELD)==0) {
                  if( iy<R.backbuf->ibuf->y) iy++;
            }
            else {
                  if( iy>0) iy--;
            }
      }

      /* Offset into the buffer: start of scanline y: */
      imBufPtr = R.backbuf->ibuf->rect
            + (iy * R.backbuf->ibuf->x)
            + ix;

      colSource = (char*) imBufPtr;

      cpCharColV2FloatColV(colSource, collector);

}

/* eof */

Generated by  Doxygen 1.6.0   Back to index