Files
test2/source/blender/src/previewrender.c
Ton Roosendaal 425f295604 Patch submitted by Jorge Bernal (lordloki) and Jonathan Merritt.
This will add Minneart diffuse and WardIso specular to our shader menu.
Minneart gives nice control over darkness/brightness areas, the wardIso
over 'plastic' style sharp or fuzzy specular.

Webpage is being made with nice samples. Will be in release log.

Jorge: one change is in the do_versions, you inserted it on wrong location.
2005-04-17 17:43:07 +00:00

1341 lines
31 KiB
C

/* previewrender.c GRAPHICS
*
* maart 95
*
* $Id$
*
* ***** 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_material_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_mywindow.h"
#include "BIF_interface.h"
#include "BIF_glutil.h"
#include "BIF_previewrender.h" /* include ourself for prototypes */
#include "PIL_time.h"
#include "RE_renderconverter.h"
#include "blendef.h" /* CLAMP */
#include "interface.h" /* ui_graphics_to_window() SOLVE! (ton) */
#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 rctf prerect;
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])/4.1;
vec[1]= (minlabda*(ray1[1]-ray2[1])+ray2[1])/4.1;
vec[2]= (minlabda*(ray1[2]-ray2[2])+ray2[2])/4.1;
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 set_previewrect(int win, int xmin, int ymin, int xmax, int ymax)
{
float pr_sizex, pr_sizey;
prerect.xmin= xmin;
prerect.ymin= ymin;
prerect.xmax= xmax;
prerect.ymax= ymax;
ui_graphics_to_window(win, &prerect.xmin, &prerect.ymin);
ui_graphics_to_window(win, &prerect.xmax, &prerect.ymax);
pr_sizex= (prerect.xmax-prerect.xmin);
pr_sizey= (prerect.ymax-prerect.ymin);
pr_facx= ( pr_sizex-1.0)/PR_RECTX;
pr_facy= ( pr_sizey-1.0)/PR_RECTY;
/* correction for gla draw */
prerect.xmin-= curarea->winrct.xmin;
prerect.ymin-= curarea->winrct.ymin;
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glaDefine2DArea(&curarea->winrct);
glPixelZoom(pr_facx, pr_facy);
}
static void end_previewrect(void)
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPixelZoom(1.0, 1.0);
// restore viewport / scissor which was set by glaDefine2DArea
glViewport(curarea->winrct.xmin, curarea->winrct.ymin, curarea->winx, curarea->winy);
glScissor(curarea->winrct.xmin, curarea->winrct.ymin, curarea->winx, curarea->winy);
}
static void display_pr_scanline(unsigned int *rect, int recty)
{
/* we do steps of 4 scanlines. but draw 5, because of errors in some gfx cards (nvidia geforce, ati...) */
if( (recty & 3)==3) {
if(recty == 3) {
glaDrawPixelsSafe(prerect.xmin, prerect.ymin, PR_RECTX, 4, rect);
}
else {
rect+= (recty-4)*PR_RECTX;
glaDrawPixelsSafe(prerect.xmin, prerect.ymin + (((float)recty-4.0)*pr_facy), PR_RECTX, 5, rect);
}
}
}
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;
if (sbuts->rect==0) BIF_preview_changed(sbuts);
else {
int y;
set_previewrect(sbuts->area->win, PR_XMIN, PR_YMIN, PR_XMAX, PR_YMAX);
for (y=0; y<PR_RECTY; y++) {
display_pr_scanline(sbuts->rect, y);
}
end_previewrect();
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], lacol[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);
lacol[0]= la->r;
lacol[1]= la->g;
lacol[2]= la->b;
if(la->mode & LA_TEXTURE) do_lamp_tex(la, vec, shi, lacol);
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*lacol[0];
if(col<=0) rect[0]= 0; else if(col>=255) rect[0]= 255; else rect[0]= col;
col= 255.0*dist*lacol[1];
if(col<=0) rect[1]= 0; else if(col>=255) rect[1]= 255; else rect[1]= col;
col= 255.0*dist*lacol[2];
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= mat->r;
har->g= mat->g;
har->b= 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, colf[4];
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, colf, 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, y;
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.r.postmul= R.r.postgamma= R.r.postsat= 1.0;
R.r.posthue= R.r.postadd= 0.0;
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 (disabled then)
//areawinset(curarea->win);
/* draw can just be this way, all settings are OK */
for (y=0; y<PR_RECTY; y++) {
display_pr_scanline(sbuts->rect, y);
}
/* temps */
R.ycor= ycor;
R.rectx= rectx;
R.recty= recty;
R.afmx= afmx;
R.afmy= afmy;
R.rectot= rectot;
}
static void texture_preview_pixel(Tex *tex, int x, int y, char *rect)
{
float i, v1, xsq, ysq, texvec[3];
float tin=1.0, tr, tg, tb, ta;
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;
}
if(skip==0) rgbnor= multitex_ext(tex, texvec, &tin, &tr, &tg, &tb, &ta);
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 {
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->mat;
// copy all relevant material vars, note, keep this synced with render_types.h
memcpy(&shi->r, &mat->r, 23*sizeof(float));
// set special cases:
shi->har= mat->har;
if((mat->mode & MA_RAYMIRROR)==0) shi->ray_mirror= 0.0;
v1= 1.0/PR_RECTX;
shi->view[0]= v1*x;
shi->view[1]= v1*y;
shi->view[2]= 1.0;
Normalise(shi->view);
shi->xs= (float)x;
shi->ys= (float)y;
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= shi->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*(shi->r);
if(temp>255) rect[0]= 255; else if(temp<0) rect[0]= 0; else rect[0]= temp;
temp= 255.0*(shi->g);
if(temp>255) rect[1]= 255; else if(temp<0) rect[1]= 0; else rect[1]= temp;
temp= 255.0*(shi->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(shi->spec>0.0) {
if(is>0.0) {
/* specular shaders */
float specfac;
if(mat->spec_shader==MA_SPEC_PHONG)
specfac= Phong_Spec(shi->vn, lv, shi->view, shi->har);
else if(mat->spec_shader==MA_SPEC_COOKTORR)
specfac= CookTorr_Spec(shi->vn, lv, shi->view, shi->har);
else if(mat->spec_shader==MA_SPEC_BLINN)
specfac= Blinn_Spec(shi->vn, lv, shi->view, mat->refrac, (float)shi->har);
else if(mat->spec_shader==MA_SPEC_WARDISO)
specfac= WardIso_Spec(shi->vn, lv, shi->view, mat->rms);
else
specfac= Toon_Spec(shi->vn, lv, shi->view, mat->param[2], mat->param[3]);
inprspec= specfac*shi->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*shi->specr;
isg+= inprspec*shi->specg;
isb+= inprspec*shi->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 if(mat->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(is, shi->vn, shi->view, mat->darkness);
// else Lambert
inp= (shi->refl*is + shi->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]= shi->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] +shi->ambr +isr);
if(a>255) a=255; else if(a<0) a= 0;
rect[0]= a;
a= 255.0*(diff[1] +shi->ambg +isg);
if(a>255) a=255; else if(a<0) a= 0;
rect[1]= a;
a= 255*(diff[2] +shi->ambb +isb);
if(a>255) a=255; else if(a<0) a= 0;
rect[2]= a;
}
else {
a= 255.0*( shi->mirr*shi->refcol[1] + (1.0 - shi->mirr*shi->refcol[0])*(diff[0] +shi->ambr) +isr);
if(a>255) a=255; else if(a<0) a= 0;
rect[0]= a;
a= 255.0*( shi->mirg*shi->refcol[2] + (1.0 - shi->mirg*shi->refcol[0])*(diff[1] +shi->ambg) +isg);
if(a>255) a=255; else if(a<0) a= 0;
rect[1]= a;
a= 255.0*( shi->mirb*shi->refcol[3] + (1.0 - shi->mirb*shi->refcol[0])*(diff[2] +shi->ambb) +isb);
if(a>255) a=255; else if(a<0) a= 0;
rect[2]= a;
}
}
/* ztra shade */
if(shi->spectra!=0.0) {
inp = MAX3(isr, isg, isb);
inp *= shi->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, shi->ang);
}
tracol= previewback(mat->pr_back, x, y) & 255;
tracol= (1.0-alpha)*tracol;
if((mat->mode & MA_RAYTRANSP) && mat->filter!=0.0) {
float fr= 1.0+ mat->filter*(shi->r-1.0);
rect[0]= fr*tracol+ (rect[0]*alpha) ;
fr= 1.0+ mat->filter*(shi->g-1.0);
rect[1]= fr*tracol+ (rect[1]*alpha) ;
fr= 1.0+ mat->filter*(shi->b-1.0);
rect[2]= fr*tracol+ (rect[2]*alpha) ;
}
else {
rect[0]= tracol+ (rect[0]*alpha) ;
rect[1]= tracol+ (rect[1]*alpha) ;
rect[2]= tracol+ (rect[2]*alpha) ;
}
}
}
void BIF_previewrender(SpaceButs *sbuts)
{
static double lasttime= 0;
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;
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) */
}
uiPanelPush(block); // sets UImat
set_previewrect(sbuts->area->win, PR_XMIN, PR_YMIN, PR_XMAX, PR_YMAX); // uses UImat
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);
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);
/* flush opengl for cards with frontbuffer slowness */
if(sbuts->cury==PR_RECTY-1 || (PIL_check_seconds_timer() - lasttime > 0.05)) {
lasttime= PIL_check_seconds_timer();
glFlush();
}
sbuts->cury++;
}
end_previewrect();
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) {
MEM_freeN(R.la[0]);
}
R.totlamp= 0;
end_render_textures();
}
else if(wrld) {
end_render_textures();
}
}