This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/render/intern/source/pixelshading.c
Kent Mein d0e346d544 updated .c files to include:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Just need to finish cpp files now :)

Kent
--
mein@cs.umn.edu
2002-11-25 12:02:15 +00:00

1922 lines
54 KiB
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$
*
* Shading hierarchy:
*
* (externally visible)
*
* renderPixel----------
* | renderHaloPixel-- shadeHaloFloat
* |
* | renderFacePixel-- shadeLampLusFloat
* | shadeSpotHaloPixelFloat-- spotHaloFloat
*
*
* renderSpotHaloPixel--(should call shadeSpotHaloPixelFloat, but there's numerical)
* ( issues there... need to iron that out still )
*/
#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_mesh_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 "render_intern.h"
#include "vanillaRenderPipe_types.h"
#include "pixelblending.h"
#include "zbuf.h"
#include "rendercore.h" /* for some shading functions... */
#include "zbufferdatastruct.h"
#include "shadbuf.h"
#include "shadowBuffer.h"
#include "renderHelp.h"
#include "gammaCorrectionTables.h"
#include "errorHandler.h"
#include "pixelshading.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* ------------------------------------------------------------------------- */
/* maybe declare local functions here? */
/* ------------------------------------------------------------------------- */
/* The collector is the communication channel with the render pipe. */
extern RE_COLBUFTYPE collector[4]; /* used throughout as pixel colour accu */
/* shortcol was the old collector */
extern float holoofs, fmask[256];
extern float Zmulx, Zmuly; /* Some kind of scale? */
unsigned int calcHaloZ(HaloRen *har, unsigned int zz);
/* ------------------------------------------------------------------------- */
/* if defined: do full error tracing and reporting here */
/* #define RE_PIXSHADE_FULL_SAFETY */
/* if defined: use fake (dummy) colours for filling pixels (all is purple) */
/* #define RE_FAKE_PIXELS */
/* if defined: use fake (dummy) colours for filling faces (all blue) */
/* #define RE_FAKE_FACE_PIXELS */
/* if defined: use fake (dummy) colours for filling halos (all red) */
/* #define RE_FAKE_HALO_PIXELS */
/* #define RE_FAKE_HALO_PIXELS_2 */
/* if defined: use fake (dummy) colours for filling spothalos (green) */
/* #define RE_FAKE_SPOTHALO_PIXELS */
/* if defined: use fake (dummy) colours for shading lighting */
/* #define RE_FAKE_LAMP_SHADE */
/* if defined: fake colours for sky pixels */
/* #define RE_FAKE_SKY_PIXELS */
/* ------------------------------------------------------------------------- */
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 *renderPixel(float x, float y, int *obdata)
{
void* data = NULL;
#ifdef RE_PIXSHADE_FULL_SAFETY
char fname[] = "renderPixel";
#endif
#ifdef RE_FAKE_PIXELS
collector[0] = RE_UNITY_COLOUR_FLOAT;
collector[1] = 0;
collector[2] = RE_UNITY_COLOUR_FLOAT;
collector[3] = RE_UNITY_COLOUR_FLOAT;
return NULL;
#endif
if (obdata[3] & RE_POLY) {
/* face pixels aren't rendered in floats yet, so we wrap it here */
data = renderFacePixel(x, y, obdata[1]);
}
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 = renderFacePixel(x, y, obdata[1]);
}
#ifdef RE_PIXSHADE_FULL_SAFETY
else RE_error(RE_BAD_FACE_TYPE, fname);
#endif /* RE_PIXSHADE_FULL_SAFETY */
return data;
} /* end of void renderPixel(float x, float y, int *obdata) */
/* ------------------------------------------------------------------------- */
void *renderFacePixel(float x, float y, int vlaknr)
/* Result goes into <collector> */
{
#ifdef RE_PIXSHADE_FULL_SAFETY
char fname[]= "renderFacePixelFloat";
#endif
static VlakRen *vlr; /* static, because we don't want to recalculate vlr */
/* when we already know it */
static VertRen *v1, *v2, *v3;
static float t00, t01, t10, t11, dvlak, n1[3], n2[3], n3[3];
static float s00, s01, s10, s11;
float *o1, *o2, *o3;
float u, v, l, dl, hox, hoy, detsh, fac, deler, alpha;
char *cp1, *cp2, *cp3;
/* RE_error(RE_TRACE_COUNTER, fname); */
#ifdef RE_FAKE_FACE_PIXELS
collector[0] = 0;
collector[1] = 0;
collector[2] = RE_UNITY_COLOUR_FLOAT;
collector[3] = RE_UNITY_COLOUR_FLOAT;
/* try to keep the rest as clean as possible... */
if( ((vlaknr & 0x7FFFFF) <= R.totvlak)
&& ! ((R.vlaknr== -1)||(vlaknr<=0)) ) {
/* a bit superfluous to do this always, but */
/* when this is switched on, it doesn't matter */
vlr= RE_findOrAddVlak( (vlaknr-1) & 0x7FFFFF);
} else vlr = NULL;
return vlr;
#endif
if(R.vlaknr== -1) { /* doet initrender */
/* also set in the pixelrender loop */
vlr= R.vlr= 0;
}
if(vlaknr<=0) { /* sky */
R.vlaknr= 0;
collector[3] = 0.0;
}
else if( (vlaknr & 0x7FFFFF) <= R.totvlak) {
/* What follows now is a large bunch of texture coordinate mappings. */
/* When this face is the same as the previous one, that means all */
/* the coordinate remapping does not need to be recomputed. */
if(vlaknr!=R.vlaknr) {
vlr= RE_findOrAddVlak( (vlaknr-1) & 0x7FFFFF);
R.mat= vlr->mat;
R.matren= R.mat->ren;
if(R.matren==0) { /* tijdelijk voor debug */
collector[3] = RE_UNITY_COLOUR_FLOAT;
collector[2] = 0.0;
collector[1] = RE_UNITY_COLOUR_FLOAT;
collector[0] = RE_UNITY_COLOUR_FLOAT;
return NULL;
}
R.vlr= vlr;
R.vno= vlr->n;
R.osatex= (R.matren->texco & TEXCO_OSA);
R.vlaknr= vlaknr;
v1= vlr->v1;
dvlak= MTC_dot3Float(v1->co, vlr->n);
if( (vlr->flag & R_SMOOTH) || (R.matren->texco & NEED_UV)) { /* uv nodig */
if(vlaknr & 0x800000) {
v2= vlr->v3;
v3= vlr->v4;
}
else {
v2= vlr->v2;
v3= vlr->v3;
}
if(vlr->snproj==0) {
t00= v3->co[0]-v1->co[0]; t01= v3->co[1]-v1->co[1];
t10= v3->co[0]-v2->co[0]; t11= v3->co[1]-v2->co[1];
}
else if(vlr->snproj==1) {
t00= v3->co[0]-v1->co[0]; t01= v3->co[2]-v1->co[2];
t10= v3->co[0]-v2->co[0]; t11= v3->co[2]-v2->co[2];
}
else {
t00= v3->co[1]-v1->co[1]; t01= v3->co[2]-v1->co[2];
t10= v3->co[1]-v2->co[1]; t11= v3->co[2]-v2->co[2];
}
detsh= t00*t11-t10*t01;
t00/= detsh; t01/=detsh;
t10/=detsh; t11/=detsh;
if(vlr->flag & R_SMOOTH) { /* puno's goedzetten */
if(vlr->puno & ME_FLIPV1) MTC_cp3FloatInv(v1->n, n1);
else MTC_cp3Float(v1->n, n1);
if(vlaknr & 0x800000) {
if(vlr->puno & ME_FLIPV3) MTC_cp3FloatInv(v2->n, n2);
else MTC_cp3Float(v2->n, n2);
if(vlr->puno & ME_FLIPV4) MTC_cp3FloatInv(v3->n, n3);
else MTC_cp3Float(v3->n, n3);
}
else {
if(vlr->puno & ME_FLIPV2) MTC_cp3FloatInv(v2->n, n2);
else MTC_cp3Float(v2->n, n2);
if(vlr->puno & ME_FLIPV3) MTC_cp3FloatInv(v3->n, n3);
else MTC_cp3Float(v3->n, n3);
}
}
if(R.matren->texco & TEXCO_STICKY) {
s00= v3->ho[0]/v3->ho[3] - v1->ho[0]/v1->ho[3];
s01= v3->ho[1]/v3->ho[3] - v1->ho[1]/v1->ho[3];
s10= v3->ho[0]/v3->ho[3] - v2->ho[0]/v2->ho[3];
s11= v3->ho[1]/v3->ho[3] - v2->ho[1]/v2->ho[3];
detsh= s00*s11-s10*s01;
s00/= detsh; s01/=detsh;
s10/=detsh; s11/=detsh;
}
}
} /* end of if vlaknr*/
/* This trafo might be migrated to a separate function. It is used */
/* quite often. */
/* COXYZ nieuwe methode */
if( (G.special1 & G_HOLO)
&& (((Camera *)G.scene->camera->data)->flag & CAM_HOLO2) ) {
R.view[0]= (x+(R.xstart)+1.0+holoofs);
}
else {
R.view[0]= (x+(R.xstart)+1.0);
}
if(R.flag & R_SEC_FIELD) {
if(R.r.mode & R_ODDFIELD) R.view[1]= (y+R.ystart+0.5)*R.ycor;
else R.view[1]= (y+R.ystart+1.5)*R.ycor;
}
else R.view[1]= (y+R.ystart+1.0)*R.ycor;
R.view[2]= -R.viewfac;
if(R.r.mode & R_PANORAMA) {
float panoco, panosi;
panoco = getPanovCo();
panosi = getPanovSi();
u= R.view[0]; v= R.view[2];
R.view[0]= panoco*u + panosi*v;
R.view[2]= -panosi*u + panoco*v;
}
deler= vlr->n[0]*R.view[0] + vlr->n[1]*R.view[1] + vlr->n[2]*R.view[2];
if (deler!=0.0) fac= R.zcor= dvlak/deler;
else fac= R.zcor= 0.0;
R.co[0]= fac*R.view[0];
R.co[1]= fac*R.view[1];
R.co[2]= fac*R.view[2];
if(R.osatex || (R.r.mode & R_SHADOW) ) {
u= dvlak/(deler-vlr->n[0]);
v= dvlak/(deler- R.ycor*vlr->n[1]);
O.dxco[0]= R.co[0]- (R.view[0]-1.0)*u;
O.dxco[1]= R.co[1]- (R.view[1])*u;
O.dxco[2]= R.co[2]- (R.view[2])*u;
O.dyco[0]= R.co[0]- (R.view[0])*v;
O.dyco[1]= R.co[1]- (R.view[1]-1.0*R.ycor)*v;
O.dyco[2]= R.co[2]- (R.view[2])*v;
}
fac= Normalise(R.view);
R.zcor*= fac; /* voor mist */
if(R.osatex) {
if( (R.matren->texco & TEXCO_REFL) ) {
O.dxview= 1.0/fac;
O.dyview= R.ycor/fac;
}
}
/* UV en TEX*/
if( (vlr->flag & R_SMOOTH) || (R.matren->texco & NEED_UV)) {
if(vlr->snproj==0) {
u= (R.co[0]-v3->co[0])*t11-(R.co[1]-v3->co[1])*t10;
v= (R.co[1]-v3->co[1])*t00-(R.co[0]-v3->co[0])*t01;
if(R.osatex) {
O.dxuv[0]= O.dxco[0]*t11- O.dxco[1]*t10;
O.dxuv[1]= O.dxco[1]*t00- O.dxco[0]*t01;
O.dyuv[0]= O.dyco[0]*t11- O.dyco[1]*t10;
O.dyuv[1]= O.dyco[1]*t00- O.dyco[0]*t01;
}
}
else if(vlr->snproj==1) {
u= (R.co[0]-v3->co[0])*t11-(R.co[2]-v3->co[2])*t10;
v= (R.co[2]-v3->co[2])*t00-(R.co[0]-v3->co[0])*t01;
if(R.osatex) {
O.dxuv[0]= O.dxco[0]*t11- O.dxco[2]*t10;
O.dxuv[1]= O.dxco[2]*t00- O.dxco[0]*t01;
O.dyuv[0]= O.dyco[0]*t11- O.dyco[2]*t10;
O.dyuv[1]= O.dyco[2]*t00- O.dyco[0]*t01;
}
}
else {
u= (R.co[1]-v3->co[1])*t11-(R.co[2]-v3->co[2])*t10;
v= (R.co[2]-v3->co[2])*t00-(R.co[1]-v3->co[1])*t01;
if(R.osatex) {
O.dxuv[0]= O.dxco[1]*t11- O.dxco[2]*t10;
O.dxuv[1]= O.dxco[2]*t00- O.dxco[1]*t01;
O.dyuv[0]= O.dyco[1]*t11- O.dyco[2]*t10;
O.dyuv[1]= O.dyco[2]*t00- O.dyco[1]*t01;
}
}
l= 1.0+u+v;
if(vlr->flag & R_SMOOTH) {
R.vn[0]= l*n3[0]-u*n1[0]-v*n2[0];
R.vn[1]= l*n3[1]-u*n1[1]-v*n2[1];
R.vn[2]= l*n3[2]-u*n1[2]-v*n2[2];
Normalise(R.vn);
if(R.osatex && (R.matren->texco & (TEXCO_NORM+TEXCO_REFL)) ) {
dl= O.dxuv[0]+O.dxuv[1];
O.dxno[0]= dl*n3[0]-O.dxuv[0]*n1[0]-O.dxuv[1]*n2[0];
O.dxno[1]= dl*n3[1]-O.dxuv[0]*n1[1]-O.dxuv[1]*n2[1];
O.dxno[2]= dl*n3[2]-O.dxuv[0]*n1[2]-O.dxuv[1]*n2[2];
dl= O.dyuv[0]+O.dyuv[1];
O.dyno[0]= dl*n3[0]-O.dyuv[0]*n1[0]-O.dyuv[1]*n2[0];
O.dyno[1]= dl*n3[1]-O.dyuv[0]*n1[1]-O.dyuv[1]*n2[1];
O.dyno[2]= dl*n3[2]-O.dyuv[0]*n1[2]-O.dyuv[1]*n2[2];
}
}
else {
VECCOPY(R.vn, vlr->n);
}
if(R.matren->mode & MA_ZINV) { /* z invert */
/* R.vn[0]= -R.vn[0]; */
/* R.vn[1]= -R.vn[1]; */
}
if(R.matren->texco & TEXCO_ORCO) {
if(v2->orco) {
o1= v1->orco;
o2= v2->orco;
o3= v3->orco;
R.lo[0]= l*o3[0]-u*o1[0]-v*o2[0];
R.lo[1]= l*o3[1]-u*o1[1]-v*o2[1];
R.lo[2]= l*o3[2]-u*o1[2]-v*o2[2];
if(R.osatex) {
dl= O.dxuv[0]+O.dxuv[1];
O.dxlo[0]= dl*o3[0]-O.dxuv[0]*o1[0]-O.dxuv[1]*o2[0];
O.dxlo[1]= dl*o3[1]-O.dxuv[0]*o1[1]-O.dxuv[1]*o2[1];
O.dxlo[2]= dl*o3[2]-O.dxuv[0]*o1[2]-O.dxuv[1]*o2[2];
dl= O.dyuv[0]+O.dyuv[1];
O.dylo[0]= dl*o3[0]-O.dyuv[0]*o1[0]-O.dyuv[1]*o2[0];
O.dylo[1]= dl*o3[1]-O.dyuv[0]*o1[1]-O.dyuv[1]*o2[1];
O.dylo[2]= dl*o3[2]-O.dyuv[0]*o1[2]-O.dyuv[1]*o2[2];
}
}
}
if(R.matren->texco & TEXCO_GLOB) {
VECCOPY(R.gl, R.co);
MTC_Mat4MulVecfl(R.viewinv, R.gl);
if(R.osatex) {
VECCOPY(O.dxgl, O.dxco);
MTC_Mat3MulVecfl(R.imat, O.dxco);
VECCOPY(O.dygl, O.dyco);
MTC_Mat3MulVecfl(R.imat, O.dyco);
}
}
if((R.matren->texco & TEXCO_UV) || (R.matren->mode & (MA_VERTEXCOL|MA_FACETEXTURE))) {
if(R.vlr->tface) {
float *uv1, *uv2, *uv3;
uv1= R.vlr->tface->uv[0];
if( (vlaknr & 0x800000) || (R.vlr->flag & R_FACE_SPLIT) ) {
uv2= R.vlr->tface->uv[2];
uv3= R.vlr->tface->uv[3];
}
else {
uv2= R.vlr->tface->uv[1];
uv3= R.vlr->tface->uv[2];
}
R.uv[0]= -1.0 + 2.0*(l*uv3[0]-u*uv1[0]-v*uv2[0]);
R.uv[1]= -1.0 + 2.0*(l*uv3[1]-u*uv1[1]-v*uv2[1]);
if(R.osatex) {
float duv[2];
dl= O.dxuv[0]+O.dxuv[1];
duv[0]= O.dxuv[0];
duv[1]= O.dxuv[1];
O.dxuv[0]= 2.0*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]);
O.dxuv[1]= 2.0*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]);
dl= O.dyuv[0]+O.dyuv[1];
duv[0]= O.dyuv[0];
duv[1]= O.dyuv[1];
O.dyuv[0]= 2.0*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]);
O.dyuv[1]= 2.0*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]);
}
}
else {
R.uv[0]= 2.0*(u+.5);
R.uv[1]= 2.0*(v+.5);
}
}
if(R.matren->texco & TEXCO_NORM) {
R.orn[0]= R.vn[0];
R.orn[1]= -R.vn[1];
R.orn[2]= R.vn[2];
}
if(R.matren->mode & MA_VERTEXCOL) {
/* some colour calculations here */
cp1= (char *)vlr->vcol;
if(cp1) {
if( (vlaknr & 0x800000) || (R.vlr->flag & R_FACE_SPLIT) ) {
cp2= (char *)(vlr->vcol+2);
cp3= (char *)(vlr->vcol+3);
}
else {
cp2= (char *)(vlr->vcol+1);
cp3= (char *)(vlr->vcol+2);
}
R.vcol[0]= (l*cp3[3]-u*cp1[3]-v*cp2[3])/255.0;
R.vcol[1]= (l*cp3[2]-u*cp1[2]-v*cp2[2])/255.0;
R.vcol[2]= (l*cp3[1]-u*cp1[1]-v*cp2[1])/255.0;
}
else {
R.vcol[0]= 0.0;
R.vcol[1]= 0.0;
R.vcol[2]= 0.0;
}
}
if(R.matren->mode & MA_FACETEXTURE) {
if((R.matren->mode & MA_VERTEXCOL)==0) {
R.vcol[0]= 1.0;
R.vcol[1]= 1.0;
R.vcol[2]= 1.0;
}
/* shading here */
if(vlr->tface) render_realtime_texture();
}
/* hierna klopt de u en v EN O.dxuv en O.dyuv niet meer */
if(R.matren->texco & TEXCO_STICKY) {
if(v2->sticky) {
/* opnieuw u en v berekenen */
hox= x/Zmulx -1.0;
hoy= y/Zmuly -1.0;
u= (hox - v3->ho[0]/v3->ho[3])*s11
- (hoy - v3->ho[1]/v3->ho[3])*s10;
v= (hoy - v3->ho[1]/v3->ho[3])*s00
- (hox - v3->ho[0]/v3->ho[3])*s01;
l= 1.0+u+v;
o1= v1->sticky;
o2= v2->sticky;
o3= v3->sticky;
R.sticky[0]= l*o3[0]-u*o1[0]-v*o2[0];
R.sticky[1]= l*o3[1]-u*o1[1]-v*o2[1];
if(R.osatex) {
O.dxuv[0]= s11/Zmulx;
O.dxuv[1]= - s01/Zmulx;
O.dyuv[0]= - s10/Zmuly;
O.dyuv[1]= s00/Zmuly;
dl= O.dxuv[0]+O.dxuv[1];
O.dxsticky[0]= dl*o3[0]-O.dxuv[0]*o1[0]-O.dxuv[1]*o2[0];
O.dxsticky[1]= dl*o3[1]-O.dxuv[0]*o1[1]-O.dxuv[1]*o2[1];
dl= O.dyuv[0]+O.dyuv[1];
O.dysticky[0]= dl*o3[0]-O.dyuv[0]*o1[0]-O.dyuv[1]*o2[0];
O.dysticky[1]= dl*o3[1]-O.dyuv[0]*o1[1]-O.dyuv[1]*o2[1];
}
}
}
}
else {
VECCOPY(R.vn, vlr->n);
}
if(R.matren->texco & TEXCO_WINDOW) {
R.winco[0]= (x+(R.xstart))/(float)R.afmx;
R.winco[1]= (y+(R.ystart))/(float)R.afmy;
}
/* After all texture coordinates are set and converted and */
/* transformed, we need to put some colour on it: */
shadeLampLusFloat();
/* MIST */
if( (R.wrld.mode & WO_MIST) && (R.matren->mode & MA_NOMIST)==0 ){
/* alpha returned in float? */
alpha= mistfactor(R.co);
}
else alpha= 1.0;
/* RAYTRACE (tijdelijk?) UITGESCHAKELD */
if(R.matren->alpha!=1.0 || alpha!=1.0) {
fac= alpha*(R.matren->alpha);
collector[0] *= fac; /* This applies to transparent faces! Even */
collector[1] *= fac; /* though it may seem to be a premul op, it */
collector[2] *= fac; /* isn't. */
collector[3] = fac; /* doesn't need scaling? */
}
else {
collector[3] = 1.0;
}
}
else {
collector[0] = 1.0;
collector[1] = 1.0;
collector[2] = 0.0;
collector[3] = 1.0;
}
/* Spothalos: do this here for covered pixels. It seems messy to place */
/* it here, structure-wise, but it's more efficient. Also, not having it */
/* here makes it difficult to do proper overlaying later on. */
/* It starts off with a coordinate transform again. */
if(R.flag & R_LAMPHALO) {
if(vlaknr<=0) { /* bereken viewvec en zet R.co op far */
/* this view vector stuff should get its own function */
if( (G.special1 & G_HOLO) &&
((Camera *)G.scene->camera->data)->flag & CAM_HOLO2) {
R.view[0]= (x+(R.xstart)+1.0+holoofs);
} else {
R.view[0]= (x+(R.xstart)+1.0);
}
if(R.flag & R_SEC_FIELD) {
if(R.r.mode & R_ODDFIELD) R.view[1]= (y+R.ystart+0.5)*R.ycor;
else R.view[1]= (y+R.ystart+1.5)*R.ycor;
} else {
R.view[1]= (y+R.ystart+1.0)*R.ycor;
}
R.view[2]= -R.viewfac;
if(R.r.mode & R_PANORAMA) {
float panoco, panosi;
panoco = getPanovCo();
panosi = getPanovSi();
u= R.view[0]; v= R.view[2];
R.view[0]= panoco*u + panosi*v;
R.view[2]= -panosi*u + panoco*v;
}
R.co[2]= 0.0;
}
shadeSpotHaloPixelFloat(collector);
/* renderspothaloFix(collector); */
}
#ifdef RE_PIXSHADE_FULL_SAFETY
if (!vlr) RE_error(RE_BAD_DATA_POINTER, fname);
#endif
return vlr;
} /* end of void renderFacePixelFloat(float x, float y, int vlaknr) */
/* ------------------------------------------------------------------------- */
/*
- uses R.view to determine which pixel, I think?
- the spothalo is dumped quite unceremoniously on top of the col vector
This function is also (sort of) implemented in shadespothalofix, but without
all the clipping stuff. Somehow, the clipping here is _quite_ critical.
*/
void shadeSpotHaloPixelFloat(float *col)
{
LampRen *lar;
float factor = 0.0;
int a;
float rescol[4];
for(a=0; a<R.totlamp; a++) {
lar= R.la[a];
if(lar->type==LA_SPOT && (lar->mode & LA_HALO) && lar->haint>0) {
if(lar->org) {
lar->r= lar->org->r;
lar->g= lar->org->g;
lar->b= lar->org->b;
}
/* determines how much spothalo we see */
spotHaloFloat(lar, R.view, &factor);
if(factor>0.0) {
/* Why is alpha clipped? */
if(factor > RE_FULL_COLOUR_FLOAT) rescol[3]= 1.0;
else rescol[3]= factor;
/* erg vervelend: gammagecorrigeerd renderen EN addalphaADD */
/* gaat niet goed samen */
/* eigenlijk moet er een aparte 'optel' gamma komen */
/*
There is a strange thing here: the spothalo seems to be
calculated in the space you would get when you go from
value space through inverse gamma! So we gamma-transform
to value-space, then integrate, blend, and gamma correct
_again_.
*/
rescol[0] = factor * lar->r; /* Lampren rgb's are floats */
rescol[1] = factor * lar->g;
rescol[2] = factor * lar->b;
/* ---->add values, disregard alpha */
/* - check for dest. alpha = 0. If so , just copy */
/* this is a slightly different approach: I do the gamma */
/* correction BEFORE the addition. What does the other */
/* approach do? */
if (col[3]< RE_EMPTY_COLOUR_FLOAT) {
col[0] = gammaCorrect(rescol[0]);
col[1] = gammaCorrect(rescol[1]);
col[2] = gammaCorrect(rescol[2]);
col[3] = rescol[3];
} else {
col[0] += gammaCorrect(rescol[0]);
col[1] += gammaCorrect(rescol[1]);
col[2] += gammaCorrect(rescol[2]);
col[3] += rescol[3];
}
/* this clipping may have to go? Actually, if it's */
/* done sooner, it may be more efficient */
if(col[0] > RE_FULL_COLOUR_FLOAT) col[0] = 1.0;
if(col[1] > RE_FULL_COLOUR_FLOAT) col[1] = 1.0;
if(col[2] > RE_FULL_COLOUR_FLOAT) col[2] = 1.0;
if(col[3] > RE_FULL_COLOUR_FLOAT) col[3] = 1.0;
if(col[0] < RE_EMPTY_COLOUR_FLOAT) col[0] = 0.0;
if(col[1] < RE_EMPTY_COLOUR_FLOAT) col[1] = 0.0;
if(col[2] < RE_EMPTY_COLOUR_FLOAT) col[2] = 0.0;
if(col[3] < RE_EMPTY_COLOUR_FLOAT) col[3] = 0.0;
}
}
}
if(col[0] < RE_EMPTY_COLOUR_FLOAT) col[0] = 0.0;
if(col[1] < RE_EMPTY_COLOUR_FLOAT) col[1] = 0.0;
if(col[2] < RE_EMPTY_COLOUR_FLOAT) col[2] = 0.0;
if(col[3] < RE_EMPTY_COLOUR_FLOAT) col[3] = 0.0;
}
/* ------------------------------------------------------------------------- */
void spotHaloFloat(struct LampRen *lar, float *view, float *intens)
{
double a, b, c, disc, nray[3], npos[3];
float t0, t1 = 0.0, t2= 0.0, t3, haint;
float p1[3], p2[3], ladist, maxz = 0.0, maxy = 0.0;
int snijp, doclip=1, use_yco=0;
int ok1=0, ok2=0;
*intens= 0.0;
haint= lar->haint;
VECCOPY(npos, lar->sh_invcampos); /* in initlamp berekend */
/* view roteren */
VECCOPY(nray, view);
MTC_Mat3MulVecd(lar->imat, nray);
if(R.wrld.mode & WO_MIST) {
/* een beetje patch... */
R.zcor= -lar->co[2];
haint *= mistfactor(lar->co);
if(haint==0.0) {
return;
}
}
/* maxz roteren */
if(R.co[2]==0) doclip= 0; /* is als halo op sky */
else {
p1[0]= R.co[0]-lar->co[0];
p1[1]= R.co[1]-lar->co[1];
p1[2]= R.co[2]-lar->co[2];
maxz= lar->imat[0][2]*p1[0]+lar->imat[1][2]*p1[1]+lar->imat[2][2]*p1[2];
maxz*= lar->sh_zfac;
maxy= lar->imat[0][1]*p1[0]+lar->imat[1][1]*p1[1]+lar->imat[2][1]*p1[2];
if( fabs(nray[2]) <0.000001 ) use_yco= 1;
}
/* z scalen zodat het volume genormaliseerd is */
nray[2]*= lar->sh_zfac;
/* nray hoeft niet genormaliseerd */
ladist= lar->sh_zfac*lar->dist;
/* oplossen */
a = nray[0] * nray[0] + nray[1] * nray[1] - nray[2]*nray[2];
b = nray[0] * npos[0] + nray[1] * npos[1] - nray[2]*npos[2];
c = npos[0] * npos[0] + npos[1] * npos[1] - npos[2]*npos[2];
snijp= 0;
if (fabs(a) < 0.00000001) {
/*
* Only one intersection point...
*/
return;
}
else {
disc = b*b - a*c;
if(disc==0.0) {
t1=t2= (-b)/ a;
snijp= 2;
}
else if (disc > 0.0) {
disc = sqrt(disc);
t1 = (-b + disc) / a;
t2 = (-b - disc) / a;
snijp= 2;
}
}
if(snijp==2) {
/* sorteren */
if(t1>t2) {
a= t1; t1= t2; t2= a;
}
/* z van snijpunten met diabolo */
p1[2]= npos[2] + t1*nray[2];
p2[2]= npos[2] + t2*nray[2];
/* beide punten evalueren */
if(p1[2]<=0.0) ok1= 1;
if(p2[2]<=0.0 && t1!=t2) ok2= 1;
/* minstens 1 punt met negatieve z */
if(ok1==0 && ok2==0) return;
/* snijpunt met -ladist, de bodem van de kegel */
if(use_yco==0) {
t3= (-ladist-npos[2])/nray[2];
/* moet 1 van de snijpunten worden vervangen? */
if(ok1) {
if(p1[2]<-ladist) t1= t3;
}
else {
ok1= 1;
t1= t3;
}
if(ok2) {
if(p2[2]<-ladist) t2= t3;
}
else {
ok2= 1;
t2= t3;
}
}
else if(ok1==0 || ok2==0) return;
/* minstens 1 zichtbaar snijpunt */
if(t1<0.0 && t2<0.0) return;
if(t1<0.0) t1= 0.0;
if(t2<0.0) t2= 0.0;
if(t1==t2) return;
/* voor zekerheid nog eens sorteren */
if(t1>t2) {
a= t1; t1= t2; t2= a;
}
/* t0 berekenen: is de maximale zichtbare z (als halo door vlak */
/* doorsneden wordt) */
if(doclip) {
if(use_yco==0) t0= (maxz-npos[2])/nray[2];
else t0= (maxy-npos[1])/nray[1];
if(t0<t1) return;
if(t0<t2) t2= t0;
}
/* bereken punten */
p1[0]= npos[0] + t1*nray[0];
p1[1]= npos[1] + t1*nray[1];
p1[2]= npos[2] + t1*nray[2];
p2[0]= npos[0] + t2*nray[0];
p2[1]= npos[1] + t2*nray[1];
p2[2]= npos[2] + t2*nray[2];
/* nu hebben we twee punten, hiermee maken we drie lengtes */
a= sqrt(p1[0]*p1[0]+p1[1]*p1[1]+p1[2]*p1[2]);
b= sqrt(p2[0]*p2[0]+p2[1]*p2[1]+p2[2]*p2[2]);
c= VecLenf(p1, p2);
a/= ladist;
a= sqrt(a);
b/= ladist;
b= sqrt(b);
c/= ladist;
*intens= c*( (1.0-a)+(1.0-b) );
/* LET OP: a,b en c NIET op 1.0 clippen, dit geeft kleine
overflowtjes op de rand (vooral bij smalle halo's) */
if(*intens<=0.0) return;
/* zachte gebied */
/* vervalt omdat t0 nu ook voor p1/p2 wordt gebruikt */
/* if(doclip && t0<t2) { */
/* *intens *= (t0-t1)/(t2-t1); */
/* } */
*intens *= haint;
if(lar->shb && lar->shb->shadhalostep) {
/* from shadbuf.c, returns float */
*intens *= shadow_halo(lar, p1, p2);
}
/* if(lar->mode & LA_TEXTURE) do_lamphalo_tex(lar, p1, p2, intens); */
}
} /* end of void spotHaloFloat(struct LampRen *, float *view, float *intens) */
/* ------------------------------------------------------------------------- */
void shadeLampLusFloat()
{
LampRen *lar;
register Material *ma;
float i, inp, inpr, t, lv[3], lampdist, ld = 0;
float ir, ig, ib;
float isr=0,isg=0,isb=0;
float lvrot[3], *vn, *view, shadfac, soft;
int a;
float shadfacvec[3] = {1.0, 1.0, 1.0};
vn= R.vn;
view= R.view;
ma= R.matren;
/* aparte lus */
if(ma->mode & MA_ONLYSHADOW) {
shadfac= ir= 0.0;
for(a=0; a<R.totlamp; a++) {
lar= R.la[a];
if(lar->mode & LA_LAYER) if((lar->lay & R.vlr->lay)==0) continue;
if(lar->shb) {
/* alleen testen binnen spotbundel */
lv[0]= R.co[0]-lar->co[0];
lv[1]= R.co[1]-lar->co[1];
lv[2]= R.co[2]-lar->co[2];
Normalise(lv);
inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
if(inpr>lar->spotsi) {
inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
RE_testshadowbuf(lar->shadowBufOb, lar->shb, inp, shadfacvec);
/* testshadowbuf(lar->shb, inp, shadfacvec); */
i= shadfacvec[0];
t= inpr - lar->spotsi;
if(t<lar->spotbl && lar->spotbl!=0.0) {
t/= lar->spotbl;
t*= t;
i= t*i+(1.0-t);
}
shadfac+= i;
ir+= 1.0;
}
else {
shadfac+= 1.0;
ir+= 1.0;
}
}
}
if(ir>0.0) shadfac/= ir;
ma->alpha= (R.mat->alpha)*(1.0-shadfac);
collector[0] = 0.0;
collector[1] = 0.0;
collector[2] = 0.0;
/* alpha is not set.... why?*/
return;
}
if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) {
ma->r= R.vcol[0];
ma->g= R.vcol[1];
ma->b= R.vcol[2];
}
/* mirror reflection colour */
R.refcol[0]= R.refcol[1]= R.refcol[2]= R.refcol[3]= 0.0;
if(ma->texco) {
if(ma->texco & TEXCO_REFL) {
RE_calc_R_ref();
}
if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) {
R.mat->r= R.vcol[0];
R.mat->g= R.vcol[1];
R.mat->b= R.vcol[2];
}
do_material_tex();
}
if(ma->mode & MA_SHLESS) {
if( (ma->mode & (MA_VERTEXCOL+MA_VERTEXCOLP+MA_FACETEXTURE) )) {
ir= R.vcol[0]*ma->r;
ig= R.vcol[1]*ma->g;
ib= R.vcol[2]*ma->b;
}
else {
ir= ma->r; /* apparently stored as [0,1]? */
ig= ma->g;
ib= ma->b;
}
collector[0] = ir; /* no clipping, no alpha */
collector[1] = ig;
collector[2] = ib;
return;
}
if( (ma->mode & (MA_VERTEXCOL+MA_VERTEXCOLP))== MA_VERTEXCOL ) {
ir= ma->emit+R.vcol[0];
ig= ma->emit+R.vcol[1];
ib= ma->emit+R.vcol[2];
}
else ir= ig= ib= ma->emit;
for(a=0; a<R.totlamp; a++) {
lar= R.la[a];
/* test op lamplayer */
if(lar->mode & LA_LAYER) if((lar->lay & R.vlr->lay)==0) continue;
/* lampdist berekening */
if(lar->type==LA_SUN || lar->type==LA_HEMI) {
VECCOPY(lv, lar->vec);
lampdist= 1.0;
}
else {
lv[0]= R.co[0]-lar->co[0];
lv[1]= R.co[1]-lar->co[1];
lv[2]= R.co[2]-lar->co[2];
ld= sqrt(lv[0]*lv[0]+lv[1]*lv[1]+lv[2]*lv[2]);
lv[0]/= ld;
lv[1]/= ld;
lv[2]/= ld;
/* ld wordt verderop nog gebruikt (texco's) */
if(lar->mode & LA_QUAD) {
t= 1.0;
if(lar->ld1>0.0)
t= lar->dist/(lar->dist+lar->ld1*ld);
if(lar->ld2>0.0)
t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
lampdist= t;
}
else {
lampdist= (lar->dist/(lar->dist+ld));
}
if(lar->mode & LA_SPHERE) {
t= lar->dist - ld;
if(t<0.0) continue;
t/= lar->dist;
lampdist*= (t);
}
}
if(lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv);
if(lar->type==LA_SPOT) {
/* hier de fie Inp() vertaagt! */
if(lar->mode & LA_SQUARE) {
if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0) {
float x;
/* rotate view to lampspace */
VECCOPY(lvrot, lv);
MTC_Mat3MulVecfl(lar->imat, lvrot);
x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2]));
/* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
inpr= 1.0/(sqrt(1+x*x));
}
else inpr= 0.0;
}
else {
inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
}
t= lar->spotsi;
if(inpr<t) continue;
else {
t= inpr-t;
i= 1.0;
soft= 1.0;
if(t<lar->spotbl && lar->spotbl!=0.0) {
/* zachte gebied */
i= t/lar->spotbl;
t= i*i;
soft= (3.0*t-2.0*t*i);
inpr*= soft;
}
if(lar->mode & LA_ONLYSHADOW && lar->shb) {
if(ma->mode & MA_SHADOW) {
/* inprodukt positief: voorzijde vlak! */
inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
if(inp>0.0) {
/* testshadowbuf==0.0 : 100% schaduw */
RE_testshadowbuf(lar->shadowBufOb, lar->shb, inp, shadfacvec);
/* testshadowbuf(lar->shb, inp, shadfacvec); */
shadfac = 1.0 - shadfacvec[0];
if(shadfac>0.0) {
shadfac*= inp*soft*lar->energy;
ir -= shadfac;
ig -= shadfac;
ib -= shadfac;
continue;
}
}
}
}
lampdist*=inpr;
}
if(lar->mode & LA_ONLYSHADOW) continue;
if(lar->mode & LA_OSATEX) {
R.osatex= 1; /* signaal voor multitex() */
O.dxlv[0]= lv[0] - (R.co[0]-lar->co[0]+O.dxco[0])/ld;
O.dxlv[1]= lv[1] - (R.co[1]-lar->co[1]+O.dxco[1])/ld;
O.dxlv[2]= lv[2] - (R.co[2]-lar->co[2]+O.dxco[2])/ld;
O.dylv[0]= lv[0] - (R.co[0]-lar->co[0]+O.dyco[0])/ld;
O.dylv[1]= lv[1] - (R.co[1]-lar->co[1]+O.dyco[1])/ld;
O.dylv[2]= lv[2] - (R.co[2]-lar->co[2]+O.dyco[2])/ld;
}
}
/* inprodukt en reflectivity*/
inp=i= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
if(lar->type==LA_HEMI) {
i= 0.5*i+0.5;
}
if(i>0.0) {
i*= lampdist*ma->ref;
}
/* schaduw en spec */
if(i> -0.41) { /* beetje willekeurig, beetje getest */
shadfac= 1.0;
if(lar->shb) {
if(ma->mode & MA_SHADOW) {
float shadfacvec[3] = {1.0, 1.0, 1.0};
RE_testshadowbuf(lar->shadowBufOb, lar->shb, inp, shadfacvec);
/* testshadowbuf(lar->shb, inp, shadfacvec); */
shadfac = shadfacvec[0];
/* shadfac = 1.0; : no shadow */
if(shadfac==0.0) continue;
i*= shadfac;
}
}
/* specularity */
if(ma->spec!=0.0) {
if(lar->type==LA_SUN || lar->type==LA_HEMI) {
if(lar->type==LA_SUN) {
lv[2]-= 1.0;
}
else {
lv[0]+= view[0];
lv[1]+= view[1];
lv[2]+= view[2];
}
Normalise(lv);
t= vn[0]*lv[0]+vn[1]*lv[1]+vn[2]*lv[2];
if(lar->type==LA_HEMI) {
t= 0.5*t+0.5;
}
/* let op: shadfac en lampdist uit onderstaande */
/* no more speclim */
t= ma->spec*RE_Spec(t, ma->har);
isr+= t*(lar->r * ma->specr);
isg+= t*(lar->g * ma->specg);
isb+= t*(lar->b * ma->specb);
}
else {
/* Does specular reflection? This would be the place */
/* to put BRDFs. */
t= shadfac*ma->spec*lampdist*CookTorr(vn, lv, view, ma->har);
isr+= t*(lar->r * ma->specr);
isg+= t*(lar->g * ma->specg);
isb+= t*(lar->b * ma->specb);
}
}
}
if(i>0.0) {
ir+= i*lar->r;
ig+= i*lar->g;
ib+= i*lar->b;
}
}
/* clipping: maybe don't clip? (nzc) */
/* yes, it shouldn't be done... unfortunately the current
* gammaCorrect implementation doesn't handle negative values
* correctly ( (-1)^2 = 1!!) (ton)
*/
/* if(ir<0.0) ir= 0.0; */
/* if(ig<0.0) ig= 0.0; */
/* if(ib<0.0) ib= 0.0; */
/* if(isr<0.0) isr= 0.0; */
/* if(isg<0.0) isg= 0.0; */
/* if(isb<0.0) isb= 0.0; */
/* Well, it does now. -(1^2) = -1 :) (nzc) */
if(ma->mode & MA_ZTRA) { /* ztra shade */
if(ma->spectra!=0.0) {
t = MAX3(isr, isb, isg);
t *= ma->spectra;
if(t>1.0) t= 1.0;
if(ma->mapto & MAP_ALPHA) ma->alpha= (1.0-t)*ma->alpha+t;
else ma->alpha= (1.0-t)*R.mat->alpha+t;
}
}
if(R.refcol[0]==0.0) {
collector[0] = (ma->r * ir) + ma->ambr + isr;
collector[1] = (ma->g * ig) + ma->ambg + isg;
collector[2] = (ma->b * ib) + ma->ambb + isb;
/* clip for >0 ? */
}
else {
collector[0] = (ma->mirr * R.refcol[1])
+ ((1.0 - (ma->mirr * R.refcol[0])) * ((ma->r * ir) + ma->ambr))
+ isr;
collector[1] = (ma->mirg*R.refcol[2])
+ ((1.0 - (ma->mirg * R.refcol[0])) * ((ma->g * ig) +ma->ambg))
+isg;
collector[2] = (ma->mirb*R.refcol[3])
+ ((1.0 - (ma->mirb * R.refcol[0])) * ((ma->b * ib) +ma->ambb))
+isb;
}
#ifdef RE_FAKE_LAMP_SHADE
collector[0] = 0.5;
collector[1] = 0.5;
collector[2] = 1.0;
#endif
}
/* ------------------------------------------------------------------------- */
void* renderHaloPixel(float x, float y, int haloNr) {
HaloRen *har = NULL;
float dist = 0.0;
unsigned int zz = 0;
#ifdef RE_FAKE_HALO_PIXELS
collector[0] = RE_UNITY_COLOUR_FLOAT;
collector[1] = 0;
collector[2] = 0;
collector[3] = RE_UNITY_COLOUR_FLOAT;
har = RE_findOrAddHalo(haloNr); /* crash prevention */
return (void*) har;
#endif
/* 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);
/* make a second fake pixel? */
#ifdef RE_FAKE_HALO_PIXELS_2
collector[0] = RE_UNITY_COLOUR_FLOAT;
collector[1] = 0;
collector[2] = 0;
collector[3] = RE_UNITY_COLOUR_FLOAT;
#endif
}; /* 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)
{
/* in col invullen */
/* 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) {
/* sterren geen mist */
alpha= har->alfa;
}
else {
/* een beetje patch... */
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);
/* let op: hiermee wordt gesjoemeld: flarec wordt op nul gezet in de pixstruct */
if(flarec) har->pixels+= (int)(har->rad-radist);
if(har->ringc) {
float *rc, fac;
int ofs;
/* per ring een alicirc */
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 een aliline */
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;
/* rotatie */
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 wordt doorsneden? */
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[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;
linef *= 255.0;
colf[0]+= linef * ma->specr;
colf[1]+= linef * ma->specg;
colf[2]+= linef * ma->specb;
if(har->type & HA_XALPHA) colf[3]+= linef*linef;
else colf[3]+= linef;
}
if(ringf!=0.0) {
Material *ma= har->mat;
ringf *= 255.0;
colf[0]+= ringf * ma->mirr;
colf[1]+= ringf * ma->mirg;
colf[2]+= 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() */
/* ------------------------------------------------------------------------- */
void renderSpotHaloPixel(float x, float y, float* target)
{
float u = 0.0, v = 0.0;
#ifdef RE_FAKE_SPOTHALO_PIXELS
target[0] = 0.0;
target[1] = 1.0;
target[2] = 0.0;
target[3] = 1.0;
return;
#endif
/* Strange fix? otherwise done inside shadepixel. It's sort */
/* of like telling this is a 'sky' pixel. */
R.vlaknr = 0;
target[3] = 0.0;
/*
Here's the viewvector setting again.
*/
if( (G.special1 & G_HOLO) && ((Camera *)G.scene->camera->data)->flag & CAM_HOLO2) {
R.view[0]= (x+(R.xstart)+1.0+holoofs);
}
else {
R.view[0]= (x+(R.xstart)+1.0);
}
if(R.flag & R_SEC_FIELD) {
if(R.r.mode & R_ODDFIELD) R.view[1]= (y+R.ystart+0.5)*R.ycor;
else R.view[1]= (y+R.ystart+1.5)*R.ycor;
}
else R.view[1]= (y+R.ystart+1.0)*R.ycor;
R.view[2]= -R.viewfac;
if(R.r.mode & R_PANORAMA) {
float panoco, panosi;
panoco = getPanovCo();
panosi = getPanovSi();
u= R.view[0]; v= R.view[2];
R.view[0]= panoco*u + panosi*v;
R.view[2]= -panosi*u + panoco*v;
}
R.co[2]= 0.0;
/* This little function is a patch for spothalos on non-covered pixels. */
renderspothaloFix(target);
} /* end of void renderSpotHaloPixel(float x, float y, float colbuf[4]) */
/* ------------------------------------------------------------------------- */
/*
This routine is only for sky-pixels. Therefore, no gamma needs to be done.
One strange side-effect is when you have a negative halo lamp. This suddenly
gives loads of colour. That particular case has been explicitly guarded: no
halo for negative halo spots!
This routine uses the viewvector in R... to determine what to shade. Just
deposit the colour to be blended in col.
I would like to add colours 'normally', so this routine would be the same
for spothalo on covered pixels, but that doesn't work. Some strange clipping
occurs...
*/
void renderspothaloFix(float *col)
{
LampRen *lar;
float i;
int a;
for(a=0; a<R.totlamp; a++) {
lar= R.la[a];
if((lar->type==LA_SPOT)
&& (lar->mode & LA_HALO)
&& !(lar->mode & LA_NEG)
&& (lar->haint>0)) {
if(lar->org) {
lar->r= lar->org->r;
lar->g= lar->org->g;
lar->b= lar->org->b;
}
/* returns the intensity in i */
spotHaloFloat(lar, R.view, &i);
if(i>0.0) {
/* Premul colours here! */
col[0] = i * lar->r;
col[1] = i * lar->g;
col[2] = i * lar->b;
col[3] = i;
}
}
}
}
/* ------------------------------------------------------------------------- */
/*
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)
{
#ifdef RE_FAKE_SKY_PIXELS
collector[0] = 1.0;
collector[1] = 1.0;
collector[2] = 0.0;
collector[3] = 1.0;
return;
#endif
switch (keyingType) {
case RE_ALPHA_PREMUL:
/* Premul: don't fill, and don't change the values! */
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);
break;
default:
; /* Error: illegal alpha blending state */
}
}
/*
Stuff the sky colour into the collector.
*/
void shadeSkyPixel(float fx, float fy) {
/*
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) {
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) {
R.view[0]= (fx+(R.xstart))/(float)R.afmx;
R.view[1]= (fy+(R.ystart))/(float)R.afmy;
R.view[2]= 0.0;
}
else {
/* Wasn't this some pano stuff? */
R.view[0]= (fx+(R.xstart)+1.0);
if(R.flag & R_SEC_FIELD) {
if(R.r.mode & R_ODDFIELD) R.view[1]= (fy+R.ystart+0.5)*R.ycor;
else R.view[1]= (fy+R.ystart+1.5)*R.ycor;
}
else R.view[1]= (fy+R.ystart+1.0)*R.ycor;
R.view[2]= -R.viewfac;
fac= Normalise(R.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= R.view[0]; v= R.view[2];
R.view[0]= panoco*u + panosi*v;
R.view[2]= -panosi*u + panoco*v;
}
/* get sky colour in the collector */
shadeSkyPixelFloat(fy);
}
}
/* Only line number is important here. Result goes to collector[4] */
void shadeSkyPixelFloat(float y)
{
/* 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= R.view[0]*R.grvec[0]+ R.view[1]*R.grvec[1]+ R.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*R.view[1];
}
else {
/* the fraction of how far we are above the bottom of the screen */
R.inprz= fabs(0.5+ R.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(R.lo, R.view);
if(R.wrld.skytype & WO_SKYREAL) {
MTC_Mat3MulVecfl(R.imat, R.lo);
SWAP(float, R.lo[1], R.lo[2]);
}
R.osatex= 0;
/* sky texture? I wonder how this manages to work... */
/* Does this communicate with R.wrld.hor{rgb}? Yes. */
do_sky_tex();
/* 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? */
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;
/* om verkeerde optimalisatie alphaover van flares te voorkomen */
/* ??? seems strange to me... This used to be a 1 when the colours */
/* were chars. might need a separate flag for this... */
}
/*
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 */