Render:
- New; support for dual CPU render (SDL thread)
Currently only works with alternating scanlines, but gives excellent
performance. For both normal render as unified implemented.
Note the "mutex" locks on z-transp buffer render and imbuf loads.
- This has been made possible by major cleanups in render code, especially
getting rid of globals (example Tin Tr Tg Tb Ta for textures) or struct
OSA or using Materials or Texture data to write to.
- Made normal render fully 4x32 floats too, and removed all old optimizes
with chars or shorts.
- Made normal render and unified render use same code for sky and halo
render, giving equal (and better) results for halo render. Old render
now also uses PostProcess options (brightness, mul, gamma)
- Added option ("FBuf") in F10 Output Panel, this keeps a 4x32 bits buffer
after render. Using PostProcess menu you will note an immediate re-
display of image too (32 bits RGBA)
- Added "Hue" and "Saturation" sliders to PostProcess options
- Render module is still not having a "nice" API, but amount of dependencies
went down a lot. Next todo: remove abusive "previewrender" code.
The last main global in Render (struct Render) now can be re-used for fully
controlling a render, to allow multiple "instances" of render to open.
- Renderwindow now displays a smal bar on top with the stats, and keeps the
stats after render too. Including "spare" page support.
Not only easier visible that way, but also to remove the awkward code that
was drawing stats in the Info header (extreme slow on some ATIs too)
- Cleaned up blendef.h and BKE_utildefines.h, these two had overlapping
defines.
- I might have forgotten stuff... and will write a nice doc on the architecture!
790 lines
18 KiB
C
790 lines
18 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$
|
|
*
|
|
*/
|
|
|
|
#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_material_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 "vanillaRenderPipe_types.h"
|
|
#include "pixelblending.h"
|
|
#include "rendercore.h" /* for some shading functions... */
|
|
#include "shadbuf.h"
|
|
#include "zbufferdatastruct.h"
|
|
|
|
#include "renderHelp.h"
|
|
|
|
#include "gammaCorrectionTables.h"
|
|
#include "errorHandler.h"
|
|
#include "pixelshading.h"
|
|
|
|
|
|
/* ton:
|
|
- unified render now uses face render routines from rendercore.c
|
|
- todo still: shalo render and sky routines */
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
void *renderPixel(RE_COLBUFTYPE *collector, float x, float y, int *obdata, int mask)
|
|
{
|
|
void* data = NULL;
|
|
|
|
if (obdata[3] & RE_POLY) {
|
|
data = shadepixel(x, y, obdata[1], mask, collector);
|
|
}
|
|
else if (obdata[3] & RE_HALO) {
|
|
data = renderHaloPixel(collector, 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(RE_COLBUFTYPE *collector, 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] = 0.0f; collector[1] = 0.0f;
|
|
collector[2] = 0.0f; collector[3] = 0.0f;
|
|
|
|
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[];
|
|
|
|
static void render_lighting_halo(HaloRen *har, float *colf)
|
|
{
|
|
LampRen *lar;
|
|
float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
|
|
float ir, ig, ib, shadfac, soft, lacol[3];
|
|
int a;
|
|
|
|
ir= ig= ib= 0.0;
|
|
|
|
VECCOPY(rco, har->co);
|
|
dco[0]=dco[1]=dco[2]= 1.0/har->rad;
|
|
|
|
vn= har->no;
|
|
|
|
for(a=0; a<R.totlamp; a++) {
|
|
lar= R.la[a];
|
|
|
|
/* test for lamplayer */
|
|
if(lar->mode & LA_LAYER) if((lar->lay & har->lay)==0) continue;
|
|
|
|
/* lampdist cacluation */
|
|
if(lar->type==LA_SUN || lar->type==LA_HEMI) {
|
|
VECCOPY(lv, lar->vec);
|
|
lampdist= 1.0;
|
|
}
|
|
else {
|
|
lv[0]= rco[0]-lar->co[0];
|
|
lv[1]= rco[1]-lar->co[1];
|
|
lv[2]= rco[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 is re-used further on (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);
|
|
}
|
|
|
|
}
|
|
|
|
lacol[0]= lar->r;
|
|
lacol[1]= lar->g;
|
|
lacol[2]= lar->b;
|
|
|
|
if(lar->mode & LA_TEXTURE) {
|
|
ShadeInput shi;
|
|
VECCOPY(shi.co, rco);
|
|
shi.osatex= 0;
|
|
do_lamp_tex(lar, lv, &shi, lacol);
|
|
}
|
|
|
|
if(lar->type==LA_SPOT) {
|
|
|
|
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, lvrot[3];
|
|
|
|
/* 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.0+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) {
|
|
/* soft area */
|
|
i= t/lar->spotbl;
|
|
t= i*i;
|
|
soft= (3.0*t-2.0*t*i);
|
|
inpr*= soft;
|
|
}
|
|
if(lar->mode & LA_ONLYSHADOW) {
|
|
/* if(ma->mode & MA_SHADOW) { */
|
|
/* dot product positive: front side face! */
|
|
inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
|
|
if(inp>0.0) {
|
|
/* testshadowbuf==0.0 : 100% shadow */
|
|
shadfac = testshadowbuf(lar->shb, rco, dco, dco, inp);
|
|
if( shadfac>0.0 ) {
|
|
shadfac*= inp*soft*lar->energy;
|
|
ir -= shadfac;
|
|
ig -= shadfac;
|
|
ib -= shadfac;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
/* } */
|
|
}
|
|
lampdist*=inpr;
|
|
}
|
|
if(lar->mode & LA_ONLYSHADOW) continue;
|
|
|
|
}
|
|
|
|
/* dot product and reflectivity*/
|
|
|
|
inp= 1.0-fabs(vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]);
|
|
|
|
/* inp= cos(0.5*M_PI-acos(inp)); */
|
|
|
|
i= inp;
|
|
|
|
if(lar->type==LA_HEMI) {
|
|
i= 0.5*i+0.5;
|
|
}
|
|
if(i>0.0) {
|
|
i*= lampdist;
|
|
}
|
|
|
|
/* shadow */
|
|
if(i> -0.41) { /* heuristic valua! */
|
|
shadfac= 1.0;
|
|
if(lar->shb) {
|
|
shadfac = testshadowbuf(lar->shb, rco, dco, dco, inp);
|
|
if(shadfac==0.0) continue;
|
|
i*= shadfac;
|
|
}
|
|
}
|
|
|
|
if(i>0.0) {
|
|
ir+= i*lacol[0];
|
|
ig+= i*lacol[1];
|
|
ib+= i*lacol[2];
|
|
}
|
|
}
|
|
|
|
if(ir<0.0) ir= 0.0;
|
|
if(ig<0.0) ig= 0.0;
|
|
if(ib<0.0) ib= 0.0;
|
|
|
|
colf[0]*= ir;
|
|
colf[1]*= ig;
|
|
colf[2]*= ib;
|
|
|
|
}
|
|
|
|
|
|
|
|
void shadeHaloFloat(HaloRen *har, float *col, unsigned int zz,
|
|
float dist, float xn, float yn, short flarec)
|
|
{
|
|
/* fill in col */
|
|
float t, zn, radist, ringf=0.0, linef=0.0, alpha, si, co;
|
|
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) {
|
|
col[0]= har->r;
|
|
col[1]= har->g;
|
|
col[2]= har->b;
|
|
col[3]= dist;
|
|
|
|
do_halo_tex(har, xn, yn, col);
|
|
|
|
col[0]*= col[3];
|
|
col[1]*= col[3];
|
|
col[2]*= col[3];
|
|
|
|
}
|
|
else {
|
|
col[0]= dist*har->r;
|
|
col[1]= dist*har->g;
|
|
col[2]= dist*har->b;
|
|
if(har->type & HA_XALPHA) col[3]= dist*dist;
|
|
else col[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, col);
|
|
}
|
|
|
|
/* Next, we do the line and ring factor modifications. */
|
|
if(linef!=0.0) {
|
|
Material *ma= har->mat;
|
|
|
|
col[0]+= linef * ma->specr;
|
|
col[1]+= linef * ma->specg;
|
|
col[2]+= linef * ma->specb;
|
|
|
|
if(har->type & HA_XALPHA) col[3]+= linef*linef;
|
|
else col[3]+= linef;
|
|
}
|
|
if(ringf!=0.0) {
|
|
Material *ma= har->mat;
|
|
|
|
col[0]+= ringf * ma->mirr;
|
|
col[1]+= ringf * ma->mirg;
|
|
col[2]+= ringf * ma->mirb;
|
|
|
|
if(har->type & HA_XALPHA) col[3]+= ringf*ringf;
|
|
else col[3]+= ringf;
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/*
|
|
|
|
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(RE_COLBUFTYPE *collector, 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(collector, x, y);
|
|
collector[3]= 0.0;
|
|
break;
|
|
default:
|
|
; /* Error: illegal alpha blending state */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Stuff the sky colour into the collector.
|
|
*/
|
|
void shadeSkyPixel(RE_COLBUFTYPE *collector, float fx, float fy)
|
|
{
|
|
float view[3], dxyview[2];
|
|
|
|
/*
|
|
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(collector, 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] = 1.0f;
|
|
} 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) {
|
|
dxyview[0]= 1.0/fac;
|
|
dxyview[1]= 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(collector, view, dxyview);
|
|
collector[3] = 1.0f;
|
|
}
|
|
}
|
|
|
|
/* Only view vector is important here. Result goes to colf[3] */
|
|
void shadeSkyPixelFloat(float *colf, float *view, float *dxyview)
|
|
{
|
|
float lo[3], zen[3], hor[3], blend, blendm;
|
|
|
|
/* 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) {
|
|
|
|
blend= view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2];
|
|
|
|
if(blend<0.0) R.wrld.skytype-= WO_ZENUP;
|
|
blend= fabs(blend);
|
|
}
|
|
else if(R.wrld.skytype & WO_SKYPAPER) {
|
|
blend= 0.5+ 0.5*view[1];
|
|
}
|
|
else {
|
|
/* the fraction of how far we are above the bottom of the screen */
|
|
blend= fabs(0.5+ view[1]);
|
|
}
|
|
|
|
hor[0]= R.wrld.horr; hor[1]= R.wrld.horr; hor[2]= R.wrld.horb;
|
|
zen[0]= R.wrld.zenr; zen[1]= R.wrld.zenr; zen[2]= R.wrld.zenb;
|
|
|
|
/* 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]);
|
|
|
|
}
|
|
do_sky_tex(lo, dxyview, hor, zen, &blend);
|
|
}
|
|
|
|
if(blend>1.0) blend= 1.0;
|
|
blendm= 1.0-blend;
|
|
|
|
/* No clipping, no conversion! */
|
|
if(R.wrld.skytype & WO_SKYBLEND) {
|
|
colf[0] = (blendm*hor[0] + blend*zen[0]);
|
|
colf[1] = (blendm*hor[1] + blend*zen[1]);
|
|
colf[2] = (blendm*hor[2] + blend*zen[2]);
|
|
} else {
|
|
/* Done when a texture was grabbed. */
|
|
colf[0]= hor[0];
|
|
colf[1]= hor[1];
|
|
colf[2]= hor[2];
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
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 fillBackgroundImageChar(char *col, float x, float y)
|
|
{
|
|
|
|
int iy, ix;
|
|
unsigned int* imBufPtr;
|
|
|
|
/* This double check is bad... */
|
|
if (!(R.backbuf->ok)) {
|
|
/* Something went sour here... bail... */
|
|
col[0] = 0;
|
|
col[1] = 0;
|
|
col[2] = 0;
|
|
col[3] = 255;
|
|
return;
|
|
}
|
|
/* load image if not already done?*/
|
|
if(R.backbuf->ibuf==0) {
|
|
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;
|
|
|
|
*( (int *)col) = *imBufPtr;
|
|
|
|
}
|
|
|
|
void fillBackgroundImage(RE_COLBUFTYPE *collector, float x, float y)
|
|
{
|
|
char col[4];
|
|
|
|
fillBackgroundImageChar(col, x, y);
|
|
cpCharColV2FloatColV(col, collector);
|
|
|
|
}
|
|
|
|
/* eof */
|